Debug code invoked by timer
8 views (last 30 days)
Show older comments
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
Accepted Answer
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.
0 Comments
More Answers (1)
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.
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!