Trapping warnings efficiently

A not-well-known performance improvement trick for catching errors is to place the entire code section within a try–catch block. This is more efficient than constantly checking for some condition. For example:

Trapping warnings

However, what should we do in case the checked condition is meant to prevent a warning (e.g., file-access warnings) rather than an error? It would make sense to use the same exception-handling trick, but unfortunately warnings do not normally raise a trappable exception. This question was asked on the CSSM newsgroup many years ago and received no answer, until Michael Wengler recently provided the undocumented solution on that thread:

It appears that in addition to the documented alternatives for the value of the warning function’s first parameter (namely ‘Message’, , ‘On’, ‘Off’ and ‘Query’), there is also an undocumented alternative of ‘Error’. The effect is to turn the specified warning ID into an error, that can then be trapped in a standard try–catch block. After we have finished processing, we can return the warning state to its previous value.

For the record, this warning(‘error’,…) trick appears to work in Matlab releases as far back as R14SP3 (2005), and possibly even earlier (I don’t have older releases readily available, so I couldn’t check). This looks like a pretty stable feature, as far as undocumented features go. Of course, it could well be taken out at any future Matlab release, but for the time being we can definitely make good use of it.

Trapping specific warning IDs

How can we know the specific warning IDs (e.g., ‘MATLAB:DELETE:FileNotFound’) to use? The answer is to call warning(‘on’,’verbose’) and then simulate the warning. For example:

Note that within the exception-handling part, I used the lasterr and lasterror functions, rather than lastwarn. The reason is that the warnings have been converted into standard errors, and are no longer even reported by lastwarn.

The acute reader will have noticed that I am using the older (deprecated) manner of exception handling, that does not directly pass the error struct into an identifier next to the catch keyword. The reason is that I usually intend my code to be backward compatible. Had I used the newer syntax, the code would not have worked on old Matlab releases; this way it does, subject to the availability of the above-mentioned undocumented warning(‘error’,…) trick. If you read through the code of my numerous submissions on the File Exchange, you will see that this is a recurring theme. I often use old deprecated syntax to ensure that my code will run on as many Matlab releases as possible.

Are you interested in learning more performance improvement methods? Then consider joining my Matlab Performance Tuning seminar/workshop in Geneva on August 21, 2012 – email me (altmany at gmail dot com) for details.

Undocumented scatter plot behavior – The scatter plot function has an undocumented behavior when plotting more than 100 points: it returns a single unified patch object handle, rather than a patch handle for each specific point as it returns with 100 or less points....

10 Responses to Trapping warnings efficiently

Hello, Very informative post. I found a bug in the code in the ‘Trapping warnings block’: you initialize your counter with filesIndex = 1, but index with filesList{fileIndex}. There is a mismatch between filesIndex and fileIndex (i.e. one is plural and the other is singular).

Hi there, I have tried to use your template above to do my own error trapping. However, I have found some rather strange behavior. When I run the code as shown below, the code runs and delivers the correct results. However when I %matlabpool open, %matlabpool close and change parfor to a simple for, the code will not run and I get the following error:

I included (there is not try catch yet included yet in the function DElambda). What confuses me though it why when I run this code as part of a parallel loop no errors are generated? Do trapping warnings work with parfor?

Thanks, the reason I am doing the coding this way is that rdivide is generating these error messages when it enounters a singular/badly conditioned matrix, so rdivide is clearly already using rcond() to test the conditioning of the matrices. I need to check the conditioning of the matrices, rather than me having to call rcond() again to duplicate this work, I would just like to get access to the rcond values and/or the decision as to whether the matrix is badly conditioned or not that rdivide is already producing. Ideally within a parallel structure if this is possible?

To be clear the parallel toolbox does still produce these warning messages, its just when I add:

Just a note. The Try/Catch construct can have a tremendous performance hit if used inside a loop that is executed many many times, but this can very by environment. I have one report that would run fine on my laptop in a matter of hours, but when placed on the Big-Server in the basement that time literally turned into days. Profiling on each machine showed a very clear difference in the time allocated to the same try/catch, running on the same dataset, in the two different environments. After removing the try/catch statement from a very tight loop in the core of the main algorithm, that change made all the difference.

Try/Catch by its very nature does a *lot* of housekeeping under the covers, to build stack frames that can be unwound back up to higher levels, which the if/else construct does not have to do. If a condition is a simple test (e.g. >0 or isempty) and in a very tight loop, it can be much more efficient to just use the if/else construct.

After the above experience I now reserve try/catch for main-level to second-tier level functions and try to keep them out of the often called modules. Try/catch is great, but use them wisely. If its called more than 100 times in a given run then if/else may be a better bet. For checking user input or possibly tainted network data, try/catch is great! Using it in a loop running a million times, maybe not so much.

Hi Yair, Do you have any idea how could I find all the warnings occurred since a certain point and on?lastwarn returns only the last warning, but let’s say that I want to test some code, and I want to track ALL the warnings it had produced. Do you think it’s possible?

Recent Comments

Yair Altman (1 day 9 hours ago): yes, this post was originally posted in 2011, more than 5 years ago – Matlab has changed a lot since then, including an entirely revised graphics system (HG2). The current...

Andrew (1 day 9 hours ago): I figured it out…actually found it elsewhere but then realized it is mentioned in this original post as well. You can still use getcursorinfo(dcmObject) to get a list of all...

Andrew (1 day 10 hours ago): Hello, Did MATLAB recently change the syntax to this? I am trying to get access to the current list of datacursors programatically, but nothing I have tried seems to work. >>...

Yair Altman (2 days 12 hours ago): @Alex – there is no immediate answer. If you want me to look at your specific code, then email me (altmany at gmail) for a dedicated consulting session.

Yair Altman (2 days 12 hours ago): Perhaps you have an outdated version of export_fig. Try to download the latest version from https://github.com/altmany/exp ort_fig

mimi sam (2 days 13 hours ago): I have “GPL Ghostscript” installed on my PC and I get this : In export_fig at 660 export_fig error. Please ensure: that you are using the latest version of export_fig...

Jaap Nienhuis (3 days 7 hours ago): I frequently make images in Matlab. Is it possible, to render the raster component of the image as a bitmap (image in illustrator) and to render the axes labels etc as vector...

Yair Altman (6 days 9 hours ago): @DavidB + @Guillaume + @TheBlackCat – if I remember correctly, my client wanted the code to continue processing only when the 2 inputs were both vectors, although possibly...

David B (6 days 16 hours ago): @TheBlackCat From the limited information we have available we are assuming the data is a vector. If that is the case then I think something like this code snippet would work nicely...

TheBlackCat (7 days 9 hours ago): It is hard to say without seeing more code. It may very well be that the data can only come in a few formats, so transposing it is the correct thing to do.

Guillaume (7 days 10 hours ago): Well, presumably, the code is operating on vectors, so the alternative could be dataA(:) + dataB(:) But really, the proper alternative would have been to find out why the data...