DevNotes #4. Check status of warning messages from MEX

by Pavel Holoborodko on October 24, 2016

MATLAB allows flexible adjustment of visibility of warning messages. Some, or even all, messages can be disabled from showing on the screen by warning command.

The little known fact is that status of some warnings may be used to change the execution path in algorithms. For example, if warning 'MATLAB:nearlySingularMatrix' is disabled, then linear system solver (operator MLDIVIDE) might skip estimation of reciprocal condition number which is used exactly for the purpose of detection of nearly singular matrices. If the trick is used, it allows 20%-50% boost in solver performance, since rcond estimation is a time consuming process.

Therefore it is important to be able to retrieve status of warnings in MATLAB. Especially in MEX libraries targeted for improved performance. Unfortunately MATLAB provides no simple way to check status of warning message from MEX module.

Article outlines two workarounds for the issue.

Using mexCallMATLABWithTrap

The first idea is to use documented mexCallMATLABWithTrap function to execute warning('query',...) command using MATLAB’s interpreter and then parse the returned result:

bool mxIsWarningEnabled(const char* warningId)
{
    bool enabled = true;
 
    if(NULL != warningId)
    {
        mxArray *mxCommandResponse = NULL, *mxException = NULL;
        mxArray *args[2];
 
        /* warning('query', warningId); */
        args[0] = mxCreateString("query");
        args[1] = mxCreateString(warningId);
        mxException = mexCallMATLABWithTrap(1,&mxCommandResponse,2,args,"warning");
 
        if(NULL == mxException && NULL != mxCommandResponse)
        {
            if(mxIsStruct(mxCommandResponse))
            {
                const mxArray* state_field = mxGetField(mxCommandResponse, 0, "state");
 
                if(mxIsChar(state_field))
                {
                    char state_value[8] = {0};
                    enabled = (0 == mxGetString(state_field, state_value, 8)) &&
                              (0 == strcmp(state_value,"on"));
                }
            }
            mxDestroyArray(mxCommandResponse);
        }
        else
        {
            /* 'warning' returned with error */
            mxDestroyArray(mxException);
        }
 
        mxDestroyArray(args[0]);
        mxDestroyArray(args[1]);
    }
 
    return enabled;
}

Besides of being slow, this approach works fine in most standard situations.

However it also has important drawback – as we noted before, we should be careful with recursive calls to MATLAB interpreter (MATLAB -> MEX -> MATLAB) and with handling MATLAB errors in MEX. It is safe only if we use identical standard libraries and compiler to build both – MEX and MATLAB.

In other cases, e.g. MEX is targeted to work with different versions of MATLAB, was built with different standard library and compiler, etc. – cross boundary handling of errors (which are just C++ exceptions) might lead to unpredictable results, most likely segfaults.

Using utGetWarningStatus

To avoid all the overhead of calling MATLAB interpreter and unsafe error handling, we can use internal MATLAB functions:

/* Link with libut library to pick-up undocumented functions: */
extern "C" void* utGetWarningManagerContext(void);
extern "C" bool  utIsValidMessageIdentifier(const char *warningId);
extern "C" bool  utGetWarningStatus(void* context, const char *warningId);
 
/* 
   Returns true if warning with warningId enabled 
   MATLAB versions supported/tested: 2008b - 2016b
*/
bool mxIsWarningEnabled(const char *warningId)
{
    bool enabled = true;
 
    if(NULL != warningId && utIsValidMessageIdentifier(warningId))
    {
        void* context = utGetWarningManagerContext();
        enabled = (NULL != context) && utGetWarningStatus(context, warningId);
    }
 
    return enabled;
}

Now code is clean, fast and safe – we bypass the interpreter and work directly with MATLAB kernel. All undocumented functions involved present in MATLAB for at least 10 years and do simple logical checks under the hood.

Besides, standard function mexWarnMsgIdAndTxt uses similar code to check if it should display the warning or just suppress it – and the code stays without changes since 2008b. This is good indication of code stability and makes us believe that it will not be changed in future versions of MATLAB.

For both workarounds, usage is simple:

 if (mxIsWarningEnabled("MATLAB:nearlySingularMatrix"))
 {
   /* compute rcond */
 }
 else
 {
   /* do something else */
 }

***
Previous issues of Developer Notes:
#3 – Asynchronous Handling of Ctrl-C in MEX
#2 – Short, Safe and Informative Error Messages from MEX
#1 – Multiplicative Operations with Complex Infinity

{ 0 comments… add one now }

Leave a Comment

Previous post:

Next post: