Debug code invoked by timer

14 views (last 30 days)
per isakson
per isakson on 3 Mar 2013
Edited: Pawel on 21 May 2019
Debugging code, which is invoked by a timer, is more of a challenge than it should be. The other day I expressed my frustration in What frustrates you about MATLAB?. Now, I'll try to be more constructive.
Wanted: Tips, tricks and tools to help me debug more efficiently. (Below, I present some of mine.)
My code: I have a code that is invoked by a timer on a regular basis. The code consist of a dozen classes and a handful of functions. Both objects and some functions have state. Below, I have included some small functions to illustrate my problems.
My development environment: R2012a (64bit) on Windows 7. I use a unit testing framework with a graphical interface and write some code in debug mode. The framework is based on MUNIT, by Brad Phelan.
Some problems:
  • Matlab's error messages are very generic and include neither function name nor line number
  • "Cannot clear classes". The old state must be cleared before each test. I often restart the unit testing tool to be able to clear old state.
  • Break-points are cleared by clear all and I often forget to reset them before executing the code.
Some examples:
The function, invoked_by_timer, as value of TimerFcn illustrates the error message of Matlab.
>> debug_invoked_by_timer()
Error while evaluating TimerFcn for timer 'my_timer'
Index exceeds matrix dimensions.
The function, invoked_by_timer_catch, as value of TimerFcn illustrates that it is possible to improve the error message. Daniels comment to my frustration triggered me to do this experiment.
>> debug_invoked_by_timer()
Error while evaluating TimerFcn for timer 'my_timer'
Error: Index exceeds matrix dimensions.
In invoked_by_timer.index_out_of_bounds (line: 7)
In invoked_by_timer.invoked_by_timer (line: 2)
In invoked_by_timer_catch.invoked_by_timer_catch (line: 3)
In timercb.timercb (line: 31)
In timercb.timercb (line: 14)
In wait.wait (line: 51)
In debug_invoked_by_timer.debug_invoked_by_timer (line: 17)
TraceHistory is a singleton, which keeps its state after debug_invoked_by_timer has finished. It displays which functions have been called.
>> log = TraceHistory.Instance;
>> disp(log)
--- tracer4m ---
invoked_by_timer_catch
invoked_by_timer
index_out_of_bounds
( log.clearHistory and log.setup can be done outside the function, debug_invoked_by_timer).
where
function debug_invoked_by_timer()
log = TraceHistory.Instance;
log.clearHistory
log.setup( {'h:\m\PiaX\Experiments\debug\timer\invoked_by_timer.m'} )
%
tmr = timer('Name' , 'my_timer' ...
, 'TimerFcn' , @invoked_by_timer_catch ...
... , 'TimerFcn' , @invoked_by_timer ...
, 'BusyMode' , 'drop' ...
, 'ExecutionMode' , 'fixedRate' ...
, 'Period' , 1 ...
, 'StartDelay' , 1 ...
, 'TasksToExecute', 1 ...
);
start( tmr )
wait ( tmr )
end
and
function invoked_by_timer_catch( tmr, evnt )
try
invoked_by_timer( tmr, evnt )
catch me
str = exception2str( me );
error( str )
end
end
and
function invoked_by_timer( tmr, evnt )
index_out_of_bounds()
variable_not_used( tmr, evnt )
end
function index_out_of_bounds()
a = 17;
b = a(2);
variable_not_used( a, b )
end
and
function str = exception2str( me )
str = sprintf( 'Error: %s\n', me.message );
for s = transpose( me.stack )
str = [ str, hyperlink_row_( s ) ]; %#ok<AGROW>
end
end
function str = hyperlink_row_( s )
[ ~, filename ] = fileparts( s.file );
str = sprintf ...
( [ 'In <matlab:matlab.desktop.editor.openAndGoToLine'...
, '(''%s'',%i);">%s.%s (line: %i)</a>\n' ] ...
, s.file, s.line, filename, s.name, s.line );
end
and
function variable_not_used( varargin )
%variable_not_used - helps keep the code analyzer box green
end
Persistent break-point: The function, dbs, sets a break-point on the following line. I found it useful.
function dbs
% dbs provides a persistent break-point; debug, dbstop
%
% Based on the FEX contribution kdb
% By Romesh Abeysuriya 15-11-12
%
stk = dbstack('-completenames');
dbstop( 'in', stk(2).file, 'at', num2str( stk(2).line+1 ) )
end
.
(Why do I use the timer in the first place? A while-loop with a computed pause would most likely have been good enough and easier to work with.)
  2 Comments
Daniel Shub
Daniel Shub on 10 Mar 2013
Is there an advantage of exception2str over getReport?
per isakson
per isakson on 10 Mar 2013
No. I was too quick making exception2str. However, now I think my output is easier to read ;). I failed to enter ">" or "/" between the file and the function name.

Sign in to comment.

Accepted Answer

Daniel Shub
Daniel Shub on 6 Mar 2013
My solution, that I alluded to in the original thread, looks almost identical to your invoke_by_timer_cacth, except I use the getReport method of the MException class instead. I also have defined a generic callback wrapper that I use for all callbacks that includes the try-catch.
The clear classes and clear all issues are separate and I have no insights.

More Answers (1)

Pawel
Pawel on 21 May 2019
Edited: Pawel on 21 May 2019
Hi
I am using the timer inside the App Designer and the entire endless loop (main fuunctionality of the app) is based on the timer which periodically calls the main function.
With the poor error handling by timer and lack of reporting where the error occured it is nearly impossible to debug the code.
I am using R2019a now, which is 6 years after the original post and it still seems not solved.
How on Earth people are using timers in Matlab??? Crazy....
Is there really no systemic way to display the error?
Can I somehow change the handling way and basically do not handle the error and crash the program with normal error code?
thanks
EDIT:
I found the work around here:
It is mind buggling that Matlab is so poor in that regard.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!