Dealing with infinite loops in Matlab [duplicate] - matlab

I am iterating through a large test matrix in MATLAB and calling second-party proprietary software (running in MATLAB) each time. I cannot edit the software source code. Sometimes, the software hangs, so I want to exit it after a certain amount of time and move on to the next iteration.
In pseudocode, I'm doing this:
for i = 1:n
output(i) = proprietary_software(input(i));
end
How can I skip to the next iteration (and possibly save output(i)='too_long') if the proprietary software is taking too long?

You will need to call Matlab from another instance of Matlab. The other instance of Matlab will run the command and release control to the first instance of Matlab to wait while it either saves the results or reaches a certain time. In this case, it will wait 30 seconds.
You will need 1 additional function. Make sure this function is on the Matlab path.
function proprietary_software_caller(input)
hTic=tic;
output=proprietary_software(input);
hToc=toc(hTic);
if hToc<30
save('outfile.mat','output');
end
exit;
end
You will need to modify your original script this way
[status,firstPID] = str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do #echo %~F'')'));
for i = 1:n
inputStr=num2str(input(i));
system(['matlab.exe -nodesktop -r proprietary_software_caller\(',inputStr,'\)&']);
hTic=tic;
hToc=toc(hTic);
while hToc<30 || ~(exist('outfile.mat','file')==2)
hToc=toc(hTic);
end
if hToc>=30
output(i)= 'too_long';
[status,allPIDs]=str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do #echo %~F'')'));
allPIDs(allPIDs==firstPID)=[];
for a=1:numel(allPIDs)
[status,cmdout]=system(['taskkill /F /pid ' sprintf('%i',allPIDs(a))]);
end
elseif exist('outfile.mat','file')==2
loadedData=load('outfile.mat');
output(i)=loadedData.output;
delete('outfile.mat');
end
end
I hope this helps.

You are essentially asking for a way to implement a timeout on MATLAB code. This can be surprisingly tricky to implement. The first thing to state is that if the MATLAB code in question cannot terminate itself, either by exiting cleanly or throwing an error, then it is not possible to terminate the code without quitting or killing the MATLAB process in question. For example, throwing an error in an externally created timer does not work; the error is caught.
The first question to ask is therefore:
Can the over-running code be made to terminate itself?
This depends on the cause to the over-run, and also your access to the source code:
If the program gets stuck in an infinite (or very long-running) loop, either in MATLAB code or a mex file for which you have source code, or which calls a user-defined callback each iteration, then you can get this code to terminate itself.
If the program gets stuck inside a MATLAB builtin, or a p-code file or mex file for which you don't have the source code, and doesn't have support for calling a callback regularly, then it won't be possible for you to get the code to terminate itself.
Let's address the first case. The easiest way to get the code to terminate itself is to get it to throw an error, which is caught by the caller, if it exceeds the timeout time. E.g. in the OP's case:
for i = 1:n
tic();
try
output(i) = proprietary_software(input(i));
catch
end
end
with the following code somewhere in the over-running loop, or called in a loop callback or mex file:
assert(toc() < 10, 'Timed out');
Now for the second case. You need to kill this MATLAB process, so it makes sense for this to be a MATLAB process you have spawned from your current MATLAB session. You can do this using a system call similar to this:
system('matlab -nodisplay -r code_to_run()')
While it is possible for a MATLAB process to quit itself in some situations which could be of use here (e.g. a timer function calling quit('force')), the most reliable way of killing a MATLAB process is to do it with a system call, using taskkill (Windows) or kill (Linux/Mac).
A framework using the approach of spawning and killing timed-out MATLAB processes might work like this:
Using system calls, launch one or more new MATLAB processes from your MATLAB session, running the code you want.
Use the file system or a memory mapped file to communicate between the MATLAB processes the function inputs, loop progress, outputs, process ids and timeout times.
Use the original MATLAB process to check the timeout times haven't been reached, or if so to terminate the process in question and instantiate a new one.
Use the original MATLAB process to collect up the function outputs (either from the filesystem or memory mapped file) and exit. Workers should terminate when there is no more work left
I provide a sketch only because a full working implementation of this approach is fairly involved, and in fact it has already been implemented and is publicly available in the batch_job toolbox. In the OP's case, using this toolbox (with a 10 second timeout) you'd call:
output = batch_job(#proprietary_software, input(:)', '-timeout', 10);
Note that for the toolbox to work, its root directory needs to be on your MATLAB path at startup.

Related

Can script be configured to "exit on unhandled exception"?

Is there a simple way to configure a MATLAB script so that it exits upon encountering an unhandled exception (as opposed to reverting to the REPL)?
The reason for this is that when executing many runs of a script in (unsupervised) batch mode, any script that fails should exit immediately, and not hang indifinitely at (unattended) interactive prompt.
IMPORTANT CLARIFICATION: this script is meant to be executed from the Unix command line, not from the MATLAB interactive prompt. More specifically, the script is to be invoked with
matlab -nodesktop -nosplash -nojvm -r myscript.m
The script should always terminate MATLAB after it has executed all its code, and return a status code reflecting its success (0) or failure (some non-zero integer).
I'm looking for a global setting (or a command-line flag) that can be put into effect without affecting the rest of the code.
IOW, I'm looking for something analogous to the -e flag available in some Unix shells (e.g. bash, zsh), which has the effect of aborting a script immediately whenever the return status of a statement is non-zero (meaning that the statement failed).
I know that I can wrap the entire body of a script with a try-catch, like this (for example):
try
exit_code = 0;
%
% BODY OF SCRIPT
%
catch exc
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', exc.stack.file, exc.stack.line, exc.message);
exit_code = 1;
end
exit(exit_code);
...but, as I said above, I'm looking for something simple, with no, or at most minimal, impact on the code.
The default behavior when an unhandled exception occurs is that information about the error will be printed to the command window and control will return to the command window. You should not be getting an interactive prompt from the error unless you've explicitly enabled it with dbstop if error or there is a try/catch with a keyboard command in the catch block. To just get a plain error rather than an interactive prompt you can use dbclear if error to disable this behavior. I would check your startup files to make sure that you don't have dbstop if error in there.
A try/catch pair is really the only way that this can be done. What you can do is wrap your calls to your script with another file and put the call to your script within a try/catch block. This has the added benefit that you don't have to modify the script itself, just the "runner".
Also you won't want to use exit as that completely exits MATLAB.
your_script.m
disp('Doing my thing')
error('Throwing an error!')
calling_script.m
for k = 1:100
try
% Call your other script and hope for no errors!
your_script
catch ME
% Print information about the error and continue
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', ME.stack.file, ME.stack.line, ME.message);
end
end
Update
Based upon the clarification that you've provided that you want to run this from the Unix command line, you'll still want to use something similar with a try/catch statement combined with exit. Again, you could do this in an external file as shown above
calling_script.m
code = 0;
try
your_script
catch ME
fprintf(2, 'CAUGHT EXCEPTION:\n');
fprintf(2, '%s(%d): %s\n', ME.stack.file, ME.stack.line, ME.message);
code = 1;
end
exit(code)

Parallel computing using Matlab

I am executing windows '.exe' file in 'cmd' prompt for various inputs through Matlab. The commands as follows.
for i = 1:n
filename = sprintf('input_%d.dat',i);
string = sprintf('!sfbox.exe %s', filename);
eval(string)
end
All input files are present and independent of each other. But if I attempt to parallelize the execution using 'parfor' as follows,
parfor i = 1:n
filename = sprintf('input_%d.dat',i);
string = sprintf('!sfbox.exe %s', filename);
eval(string)
end
I get an error, but the code runs serially without stopping
Explanation
MATLAB runs parfor loops on multiple MATLAB workers that have
multiple workspaces. The indicated function might not access the
correct workspace; therefore, its usage is invalid.
Is there a correct way to execute the eval using parfor?
(PS: I tried manually executing several .exe files in cmd prompt and it is feasible to run several .exe files at same time in command prompt. Problem is the way I attempt to do it in Matlab. Please suggest better methods.)
You are hitting issues with Matlab not knowing what eval is actually doing. While you know that it's doing the right thing, the eval command could be executing anything. There is a little documentation on transparency issues using eval statements in parfor and spmd statements.
Switching to use an feval statement should solve your problem, as Matlab will know that the only thing going into that statement is a string. More directly, you can use the system command to directly execute an arbitrary string in the cmd prompt from matlab.
parfor i = 1:n
filename = sprintf('input_%d.dat',i);
string = sprintf('sfbox.exe %s', filename);
system(string);
end

What is the command and syntax for breaking/stopping a program in QBASIC?

I am currently writing a QBASIC program that runs an indefinite loop (while loop). However, if a certain condition is met, I want to exit the program. What command do I use, and also what is the syntax.
Thanks
ENDexits program, and clears all variables, which frees up memory.
STOPexits program, but retains the value of all variables, which makes it possible (in certain versions of QB) to continue execution at another point, by choosing Set next statement from the Debugmenu, and then Startfrom the Runmenu. END has the same effect as STOP + choosing Restart from the Runmenu once the program has terminated.
If you have a loop, and want to exit the program from inside it, you may use either
DO
IF condition THEN EXIT DO
LOOP
END
or
DO
IF condition THEN END
LOOP
You're looking for the END or SYSTEM statement. For example:
PRINT "Hello World!"
END
PRINT "This won't be printed."
If you're using regular old QBASIC/QuickBASIC, then you can ignore all of the QB64 details on the linked pages and just use either SYSTEM or END. Both will do the same thing for the most part.1
If you're using FreeBASIC, it's recommended to use END instead of SYSTEM since some things won't get cleaned up properly when you use SYSTEM. See SYSTEM for more information pertaining to FreeBASIC if that's what you're using.
1 The END statement when running the program using QB.EXE /RUN PROGRAM.BAS will print "Press any key to continue" before exiting to the QB/QBASIC environment. The SYSTEM statement when run the same way will simply return you to the DOS shell without any need for a key press. Also, typing SYSTEM in the "Immediate Window" of the QB/QBASIC environment will exit the environment and return to the DOS shell. Otherwise the two statements behave exactly the same in QB/QBASIC, whether for standalone (compiled) programs or .BAS modules.
You can keep any condition according to the need of your program. For eg:
CLS
LET a = 5
WHILE a > 0
PRINT a;
a = a - 1
WEND
END
Here, in the program while wends executes itself until a = 0. This will not run an infinite loop.
The answer is
exit();
to exit the program.

Break out of proprietary toolbox after a given time

I am iterating through a large test matrix in MATLAB and calling second-party proprietary software (running in MATLAB) each time. I cannot edit the software source code. Sometimes, the software hangs, so I want to exit it after a certain amount of time and move on to the next iteration.
In pseudocode, I'm doing this:
for i = 1:n
output(i) = proprietary_software(input(i));
end
How can I skip to the next iteration (and possibly save output(i)='too_long') if the proprietary software is taking too long?
You will need to call Matlab from another instance of Matlab. The other instance of Matlab will run the command and release control to the first instance of Matlab to wait while it either saves the results or reaches a certain time. In this case, it will wait 30 seconds.
You will need 1 additional function. Make sure this function is on the Matlab path.
function proprietary_software_caller(input)
hTic=tic;
output=proprietary_software(input);
hToc=toc(hTic);
if hToc<30
save('outfile.mat','output');
end
exit;
end
You will need to modify your original script this way
[status,firstPID] = str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do #echo %~F'')'));
for i = 1:n
inputStr=num2str(input(i));
system(['matlab.exe -nodesktop -r proprietary_software_caller\(',inputStr,'\)&']);
hTic=tic;
hToc=toc(hTic);
while hToc<30 || ~(exist('outfile.mat','file')==2)
hToc=toc(hTic);
end
if hToc>=30
output(i)= 'too_long';
[status,allPIDs]=str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do #echo %~F'')'));
allPIDs(allPIDs==firstPID)=[];
for a=1:numel(allPIDs)
[status,cmdout]=system(['taskkill /F /pid ' sprintf('%i',allPIDs(a))]);
end
elseif exist('outfile.mat','file')==2
loadedData=load('outfile.mat');
output(i)=loadedData.output;
delete('outfile.mat');
end
end
I hope this helps.
You are essentially asking for a way to implement a timeout on MATLAB code. This can be surprisingly tricky to implement. The first thing to state is that if the MATLAB code in question cannot terminate itself, either by exiting cleanly or throwing an error, then it is not possible to terminate the code without quitting or killing the MATLAB process in question. For example, throwing an error in an externally created timer does not work; the error is caught.
The first question to ask is therefore:
Can the over-running code be made to terminate itself?
This depends on the cause to the over-run, and also your access to the source code:
If the program gets stuck in an infinite (or very long-running) loop, either in MATLAB code or a mex file for which you have source code, or which calls a user-defined callback each iteration, then you can get this code to terminate itself.
If the program gets stuck inside a MATLAB builtin, or a p-code file or mex file for which you don't have the source code, and doesn't have support for calling a callback regularly, then it won't be possible for you to get the code to terminate itself.
Let's address the first case. The easiest way to get the code to terminate itself is to get it to throw an error, which is caught by the caller, if it exceeds the timeout time. E.g. in the OP's case:
for i = 1:n
tic();
try
output(i) = proprietary_software(input(i));
catch
end
end
with the following code somewhere in the over-running loop, or called in a loop callback or mex file:
assert(toc() < 10, 'Timed out');
Now for the second case. You need to kill this MATLAB process, so it makes sense for this to be a MATLAB process you have spawned from your current MATLAB session. You can do this using a system call similar to this:
system('matlab -nodisplay -r code_to_run()')
While it is possible for a MATLAB process to quit itself in some situations which could be of use here (e.g. a timer function calling quit('force')), the most reliable way of killing a MATLAB process is to do it with a system call, using taskkill (Windows) or kill (Linux/Mac).
A framework using the approach of spawning and killing timed-out MATLAB processes might work like this:
Using system calls, launch one or more new MATLAB processes from your MATLAB session, running the code you want.
Use the file system or a memory mapped file to communicate between the MATLAB processes the function inputs, loop progress, outputs, process ids and timeout times.
Use the original MATLAB process to check the timeout times haven't been reached, or if so to terminate the process in question and instantiate a new one.
Use the original MATLAB process to collect up the function outputs (either from the filesystem or memory mapped file) and exit. Workers should terminate when there is no more work left
I provide a sketch only because a full working implementation of this approach is fairly involved, and in fact it has already been implemented and is publicly available in the batch_job toolbox. In the OP's case, using this toolbox (with a 10 second timeout) you'd call:
output = batch_job(#proprietary_software, input(:)', '-timeout', 10);
Note that for the toolbox to work, its root directory needs to be on your MATLAB path at startup.

Running a matlab program with arguments

I have a matlab file that takes in a file. I would like to run that program in the matlab shell, such as prog. I need to implement it so that it takes a number of arguments, such as "prog filename.txt 1 2 which would mean that i can use filename.txt and 1 2 as variables in my program.
Thank you!
In order to make a script accept arguments from the command line, you must first turn it into a function that will get the arguments you want, i.e if your script is named prog.m, put as the first line
function []=prog(arg1, arg2)
and add an end at the end (assuming that the file has only one function). It's very important that you call the function the same name as the file.
The next thing is that you need to make sure that the script file is located at the same place from where you call the script, or it's located at the Matlab working path, otherwise it'll not be able to recognize your script.
Finally, to execute the script you use
matlab -r "prog arg1 arg2"
which is equivalent to calling
prog(arg1,arg2)
from inside Matlab.
*- tested in Windows and Linux environments
Once your function is written in a separate file, as discussed by the other answer you can call it with a slightly more complicated setup to make it easier to catch errors etc.
There is useful advice in this thread about ensuring that Matlab doesn't launch the graphical interface and quits after finishing the script, and reports the error nicely if there is one.
For example:
matlab -nodisplay -nosplash -r "try, prog(1, 'file.txt'), catch me, fprintf('%s / %s\n',me.identifier,me.message), exit(1), end, exit(0)"
The script given to Matlab would read as follows if line spaces were added:
% Try running the script
try
prog(1, 'file.txt')
catch me
% On error, print error message and exit with failure
fprintf('%s / %s\n',me.identifier,me.message)
exit(1)
end
% Else, exit with success
exit(0)