I parallelised the code below but the simulation time is actually 400-500 times longer than the serial code. The only reason i can think of that can cause this is the message 'variable x is indexed but not sliced in parfor loop and 'variable p is indexed but not sliced in parfor loop. Can anyone verify whether this is the reason for the huge increase in simulation time or the way i parallelised the code.
p=(1,i) and x(1,i) are matrix with values set before hand.
nt=1;
nc=32;
time(1,1) = 0.0;
for t=dt:dt:0.1
nt=nt+1;
time(1,nt) = t;
disp(t);
for ii=2:nc
mytemp=zeros(1,ii);
dummy=0.0;
parfor jj=1:nc+1
if ii==jj % skipped
continue;
end
dxx = x(1,jj) - x(1,ii);
rr=abs(dxx);
if rr < re
dummy(jj) = (p(nt-1,jj)-p(nt-1,ii))*kernel(rr,re,ktype)*rr;
mytemp(jj) = kernel(rr,re,ktype)*rr;
%sumw(1,ii) = sumw(1,ii) + kernel(rr,re,1);
end
end
mysum = sum(dummy);
zeta(1,ii)=sum(mytemp);
lapp(1,ii) = 2.0*dim*mysum/zeta(1,ii);
p(nt,ii) = p(nt-1,ii) + dt*lapp(1,ii);
end
% update boundary value
p(nt,1) = function_phi(0,t);
p(nt,nc+1) = function_phi(1,t);
end
Can't be sure that is the reason, but if some parts of the code end up being parallelized while others cannot, it will create a lot of overhead without any speedup. See for example the Q&A here for a more detailed discussion of slicing.
Basically, if you have a parfor with a variable jj, then every statement in which jj is used on the right hand side should also use jj on the left hand side - in that way, the "job" can be divided between different processors, each of which tackles part of the array in parallel. As soon as that doesn't happen, for example in your lines
dxx = x(1,jj) - x(1,ii);
rr=abs(dxx);
you break the paradigm. 400x slower? I don't know about that - but the warning is pretty clear.
The first two lines could be consolidated, by the way, by computing rr(jj) (although you don't need an array):
rr(jj) = abs(x(1,jj) - x(1,ii));
You then use that value rather than rr later in the loop. This is a bit like having a private variable for each copy of the loop (a concept that I don't think Matlab has - but exists in OMP ).
I don't see where p is indexed in the parfor loop … it seems to be update outside of the inner loop, where it ought not to matter.
You might find it helpful to profile your code with the parallel profiler http://www.mathworks.com/help/distcomp/profiling-parallel-code.html - it will be instructive.
Related
Suppose I have two functions written on different scripts, say function1.m and function2.m The two computation in the two functions are independent (Some inputs may be the same, say function1(x,y) and function2(x,z) for example). However, running sequentially, say ret1 = function1(x,y); ret2 = function2(x,z); may be time consuming. I wonder if it is possible to run it in parfor loop:
parfor i = 1:2
ret(i) = run(['function' num2str(i)]); % if i=1,ret(1)=function1 and i=2, ret(2)=function2
end
Is it possible to write it in parfor loop?
Your idea is correct, but the implementation is wrong.
Matlab won't let you use run within parfor as it can't make sure it's a valid way to use parfor (i.e. no dependencies between iterations). The proper way to do that is to use functions (and not scrips) and an if statement to choose between them:
ret = zeros(2,1);
parfor k = 1:2
if k==1, ret(k) = f1(x,y); end
if k==2, ret(k) = f2(x,z); end
end
here f1 and f2 are some functions that return a scalar value (so it's suitable for ret(k) and each instance of the loop call a different if statement.
You can read here more about how to convert scripts to functions.
The rule of thumb for a parfor loop is that each iteration must be standalone. More accurately,
The body of the parfor-loop must be independent. One loop iteration
cannot depend on a previous iteration, because the iterations are
executed in a nondeterministic order.
That means that every iteration must be one which can be performed on its own and produce the correct result.
Therefore, if you have code that says, for instance,
parfor (i = 1:2)
function1(iterator,someNumber);
function2(iterator,someNumber);
end
there should be no issue with applying parfor.
However, if you have code that says, for instance,
persistentValue = 0;
parfor (i = 1:2)
persistentValue = persistentValue + function1(iterator,someNumber);
function2(iterator,persistentValue);
end
it would not be usable.
Yes. It is possible.
Here's an example:
ret = zeros(2,1);
fHandles = {#min, #max};
x = 1:10;
parfor i=1:2
ret(i) = fHandles{i}(x);
end
ret % show the results.
Whether this is a good idea or not, I don't know. There is overhead to setting up the parallel processing that may or may not make it worthwhile for you.
Typically the more iterations you have computed, the more value you get from setting up a parfor loop as the iterations are sliced-up and sent non-deterministically to the separate cores for processing. So you're getting use of 2 cores right now, but if you have many functions this may improve things.
The order that the iterations are run is not guaranteed (it could be that one core gets assigned a range of values for i, but we do not know if it those values are taken in order or randomly), so your code can't depend on other iterations of the loop.
In general, the MATLAB editor is pretty at flagging these issues ahead of time.
EDIT
Here's a proof of concept for a variable number of arguments to your different functions
ret = zeros(2,1);
fHandles = {#min, #max};
x = 1:10; % x is a 1x10 vector
y = rand(20); % y is a 20x20 matrix
z = 1; % z is a scalar value
fArgs = {{x};
{y,z}}; %wrap your arguments up in a cell
parfor i=1:2
ret(i) = fHandles{i}([fArgs{i}{:}]); %calls the function with its variable sized arguments here
end
ret % show the output
Again, this is just proof-of-concept. There are big warnings showing up in MATLAB about having to broadcast fArgs across all of the cores.
I have a problem with MathWorks Parallel Computing Toolbox in Matlab. See my code below
for k=1:length(Xab)
n1=length(Z)*(k-1)+1:length(Z)*k;
MX_j(1,n1)=JXab{k};
MY_j(1,n1)=JYab{k};
MZ_j(1,n1)=Z;
end
for k=length(Xab)+1:length(Xab)+length(Xbc)
n2=length(Z)*(k-1)+1:length(Z)*k;
MX_j(1,n2)=JXbc{k-length(Xab)};
MY_j(1,n2)=JYbc{k-length(Yab)};
MZ_j(1,n2)=Z;
end
for k=length(Xab)+length(Xbc)+1:length(Xab)+length(Xbc)+length(Xcd)
n3=length(Z)*(k-1)+1:length(Z)*k;
MX_j(1,n3)=JXcd{k-length(Xab)-length(Xbc)};
MY_j(1,n3)=JYcd{k-length(Yab)-length(Ybc)};
MZ_j(1,n3)=Z;
end
for k=length(Xab)+length(Xbc)+length(Xcd)+1:length(Xab)+length(Xbc)+length(Xcd)+length(Xda)
n4=length(Z)*(k-1)+1:length(Z)*k;
MX_j(1,n4)=JXda{k-length(Xab)-length(Xbc)-length(Xcd)};
MY_j(1,n4)=JYda{k-length(Yab)-length(Ybc)-length(Ycd)};
MZ_j(1,n4)=Z;
end
If I change the for-loop to parfor-loop, matlab warns me that MX_j is not an efficient variable. I have no idea how to solve this and how to make these for loops compute in parallel?
For me, it looks like you can combine it to one loop. Create combined cell arrays.
JX = cat(2,JXab, JXbc, JXcd, JXda);
JY = cat(2,JYab, JYbc, JYcd, JYda);
Check for the right dimension here. If your JXcc arrays are column arrays, use cat(1,....
After doing that, one single loop should do it:
n = length(Xab)+length(Xbc)+length(Xcd)+length(Xda);
for k=1:n
k2 = length(Z)*(k-1)+1:length(Z)*k;
MX_j(1,k2)=JX{k};
MY_j(1,k2)=JY{k};
MZ_j(1,k2)=Z;
end
Before parallizing anything, check if this still valid. I haven't tested it. If everything's nice, you can switch to parfor.
When using parfor, the arrays must be preallocated. The following code could work (untested due to lack of test-data):
n = length(Xab)+length(Xbc)+length(Xcd)+length(Xda);
MX_j = zeros(1,n*length(Z));
MY_j = MX_j;
MZ_j = MX_j;
parfor k=1:n
k2 = length(Z)*(k-1)+1:length(Z)*k;
MX_j(1,k2)=JX{k};
MY_j(1,k2)=JY{k};
MZ_j(1,k2)=Z;
end
Note: As far as I can see, the parfor loop will be much slower here. You simply assign some values... no calculation at all. The setup of the worker pool will take 99.9% of the total execution time.
The MATLAB documentation describes the break keyword thus:
break terminates the execution of a for or while loop. Statements in the loop after the break statement do not execute.
In nested loops, break exits only from the loop in which it occurs. Control passes to the statement that follows the end of that loop.
(my emphasis)
What if you want to exit from multiple nested loops? Other languages, such as Java, offer labelled breaks, which allow you to specify where the flow of control is to be transferred, but MATLAB lacks such a mechanism.
Consider the following example:
% assume A to be a 2D array
% nested 'for' loops
for j = 1 : n
for i = 1 : m
if f(A(i, j)) % where f is a predicate
break; % if want to break from both loops, not just the inner one
else
% do something interesting with A
end
end
% <--- the break transfers control to here...
end
% <--- ... but I want to transfer control to here
What is an idiomatic way (in MATLAB) of exiting from both loops?
I would say for your original specific example, rather use linear indexing and a single loop:
%// sample-data generation
m = 4;
n = 5;
A = rand(m, n);
temp = 0;
for k = 1:numel(A)
if A(k) > 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing
break;
else
temp = temp + A(k);
end
end
Or the practically identical (but with less branching):
for k = 1:numel(A)
if A(k) <= 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing
temp = temp + A(k);
end
end
I would think that this answer will vary from case to case and there is no general one size fits all idiomatically correct solution but I would approach it in the following way depending on your problem (note these all assumes that a vectorized solution is not practical as that is the obvious first choice)
Reduce the dimensions of the nesting and use either no breaks or just one single break (i.e. as shown above).
Don't use break at all because unless the calculation of your predicate is expensive and your loop has very many iterations, those extra iterations at the end should be practically free.
Failing that set a flag and break at each level.
Or finally wrap your loop into a function and call return instead of break.
As far as I know there are no such functionality built in. However, in most cases matlab does not need nested loops due to its support for vectorization. In those cases where vectorization does not work, the loops are mostly long and complicated and thus multiple breaks would not hinder readability significantly. As noted in a comment, you would not really need a nested loop here. Vectorization would do the trick,
m = 5;
n=4;
x = rand(m,n);
tmp = find(x>0.8, 1, 'first');
if (isempty(tmp))
tmp = m*n+1;
end
tmp = tmp-1;
tot = sum(x(1:tmp));
There might of course be people claiming that for loops are not necessarily slow anymore, but the fact remains that Matlab is column heavy and using more than one loop will in most cases include looping over non optimal dimensions. Vectorized solutions does not require that since they can use smart methods avoiding such loops (which of course does not hold if the input is a row vector, so avoiding this is also good).
The best idiomatic way to use Python (or poison of your choice) and forget all this but that's another story. Also I don't agree with the vectorization claims of the other answers anymore. Recent matlab versions handle for loops pretty quickly. You might be surprised.
My personal preference goes to raising an exception deliberately and cradling it within a try and catch block.
% assume A to be a 2D array
A = rand(10) - 0.5;
A(3,2) = 0;
wreaker = MException('Loop:breaker','Breaking the law');
try
for j = 1 : size(A,1)
% forloop number 1
for i = 1 : size(A,2)
% forloop number 2
for k = 1:10
% forloop number 3
if k == 5 && j == 3 && i == 6
mycurrentval = 5;
throw(wreaker)
end
end
end
end
catch
return % I don't remember the do nothing keyword for matlab apparently
end
You can change the location of your try catch indentation to fall back to the loop of your choice. Also by slaying kittens, you can write your own exceptions such that they label the exception depending on the nest count and then you can listen for them. There is no end to ugliness though still prettier than having counters or custom variables with if clauses in my opinion.
Note that, this is exactly why matlab drives many people crazy. It silently throws exceptions in a pretty similar way and you get a nonsensical error for the last randomly chosen function while passing by, such as size mismatch in some differential equation solver so on. I actually learned all this stuff after reading a lot matlab toolbox source codes.
I want to iterate all the elements independently (same condition for all elements though). I want to stop the iteration when the value stops changing. I will post the part of my code. According to some research, I figured that it can also be done using parfor loop but i don't know how to implement it. Can anyone please correct my code? Thanks in Advance.
probability = (ones(1,2048) .* 1/2048);
Tij = sum(StateTransitionfwd); %gives us an array of 2048 elements.
probability = ((probability * StateTransitionbwd) - (Tij .* probability));
threshold = (ones(1,2048) .* 0.05);
old = zeros(1,2048);
new = zeros(1,2048);
while(1)
probability = ((probability * StateTransitionbwd) - (Tij .* probability));
new = probability;
if old-new <= threshold
break
end
old = probability;
end
So basically I want the steady state probability (where it is not changing anymore)
For one you cannot parallellise while loops.
To implement a parfor loop make sure of the following:
- All variables must be defined before the parfor loop. Thus define output variables before the loop.
- All iterations must be absolutely independent of one another.
The second condition is not fulfilled in your case, since you are constantly updating the variable new, making it not independent.
I'd not even parallellise this code, since it's designed to break up before it went through all elements, but for the sake of argument I'll try this:
parfor ii = 1:length(Tij)
probability{ii} = ((probability * StateTransitionbwd) - (Tij .* probability));
end
Either use a cell or a matrix, whichever is more useful for your work.
Now you can go ahead and use a simple if to find your threshold:
for ii = 1:length(probability)-1
if probability(ii+1)-probability(ii)<threshold
break
end
end
As for your while loop stop condition: it's dangerous to let a loop run uncontrolled to some condition, as you do. It's rather easy to get stuck in an infinite loop. Use an additional condition MaxIt for the maximum number of iterations to do before terminating, regardless of the other condition.
while probability<threshold && MaxIt<someNumber
your code
end
Also you are checking for the validity of a full array.
A = logical([1;0]);
while A
B=1;
end
C = logical([1;1]);
while C
D=1;
end
The first while loop will not run, since one of its entries is not true; the second loop is an infinite loop now. If you want to terminate each row as soon as the condition is met, put the while loop inside a for loop over each row instead. That forloop can be parallellised if you put the while loop into a function, see the parfor documentation for that.
I have to iterate a process where I have an initial guess for the Mach number (M0). This initial guess will give me another guess for the Mach number by using two equations (Mn). Eventually, i want to iterate this process untill the error between M0 and Mn is small. I have the following piece of code and it actually works well with a while loop.
However, I am afraid that the while loop will take many iterations and computational time for certain inputs since this will be part of a bigger code which most likely will give unfeasible inputs for the while loop.
Therefore my question is the following. How can I iterate this process within Matlab without consulting a while loop? The code that I am implementing now is the following:
%% Input
gamma = 1.4;
theta = atan(0.315);
cpi = -0.732;
%% Loop
M0 = 0.2; %initial guess
Err = 100;
iterations = 0;
while Err > 0.5E-3
B = (1-(M0^2)*(1-M0*cpi))^0.5;
Mn = (((gamma+1)/2) * ((B+((1-cpi)^0.5)*sec(theta)-1)^2/(B^2 + (tan(theta))^2)) - ((gamma-1)/2) )^-0.5;
Err = abs(M0 - Mn);
M0 = Mn;
iterations=iterations+1;
end
disp(iterations) disp(Mn)
Many thanks
Since M0 is calculated in each iteration and you have trigonometric functions, you cannot use another way than iteration structures (i.e. while).
If you had a specific increase or decrease at M0, then you could initialize a vector of M0 and do vector calculations for B and Err.
But, with sec and tan this is not possible.
Another wat would be to use the parallel processing. But, since you change the M0 at each iteration then you cannot use the parfor loop.
As for a for loop, in MATLAB you need an array for for "command" argument (e.g. 1:10 or 1:length(x) or i = A, where A = 1:10 or A = [1:10;11:20]). Since you evaluate a condition and depending on the result of the evaluation you judge if you continue the execution or not, it seems that the while loop (or do while in another language) is the only way to go.
I think you need to clarify the issue. If it the issue you want to solve is that some inputs take a long time to calculate, it is not the while loop that takes the time, it is the execution of the code multiple times that causes it. Any method that loops through will be restricted by the time the block of code takes to execute multiplied by the number of iterations required to converge.
You can introduce something to stop at a certain number of iterationtions, conceptually:
While ((err > tolerance) && (numIterations < limit))
If you want an answer which does not require iterating over the code, this is akin to finding a closed form solution, and I suspect this does not exist.
Edit to add: by not exist I mean in a practical form which can be implemented in a more efficient way then iterating to a solution.