- Undocumented Matlab - https://undocumentedmatlab.com -

Checking status of warning messages in MEX

Posted By Yair Altman On December 21, 2016 | No Comments

Once again I would like to welcome guest blogger Pavel Holoborodko, the developer of the Advanpix Multiprecision Computing Toolbox [1]. Pavel has already posted here [2] as a guest blogger about undocumented Matlab MEX functions. Today he will discuss another little-known aspect of advanced MEX programming with Matlab, a repost of an article that was originally posted [3] on his own blog. Happy holidays everybody!
Matlab allows flexible adjustment of visibility of warning messages. Some, or even all, messages can be disabled from showing on the screen by warning [4] 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 the linear system solver (mldivide operator) 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.
Today’s article outlines two workarounds for the issue:

  1. Using mexCallMATLABWithTrap (documented)
  2. Using utGetWarningStatus (undocumented)

Using mexCallMATLABWithTrap (documented)

The first idea is to use documented mexCallMATLABWithTrap [5] 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;
}

This approach is slow, but works fine in most standard situations. See the bottom of this post for a usage example.
However, this approach has an important drawback – we should be careful with recursive calls to the Matlab interpreter (Matlab -> MEX -> Matlab) and with handling Matlab errors in MEX [6]. It is safe only if we use identical standard libraries and compiler to build both MEX and Matlab.
In other cases, for example when MEX is targeted to work with different versions of Matlab, or was built with a 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 (undocumented)

To avoid all the overhead of calling Matlab interpreter and unsafe error handling, we can use some undocumented 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: R2008b - R2016b
*/
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 the code is clean, fast and safe – we bypass the interpreter and work directly with Matlab kernel. All the undocumented functions involved are present in Matlab for at least 10 years and do simple logical checks under the hood.
The standard function mexWarnMsgIdAndTxt [7] uses similar code to check if it should display the warning or just suppress it, and that code remains unchanged since R2008b. This is a 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 */
}

Categories: Guest bloggers, Medium risk of breaking in future versions, Undocumented function


Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/checking-status-of-warning-messages-in-mex

URLs in this post:

[1] Advanpix Multiprecision Computing Toolbox: http://advanpix.com

[2] already posted here: http://undocumentedmatlab.com/blog/tag/pavel-holoborodko

[3] originally posted: http://www.advanpix.com/2016/10/24/check-status-of-warning-messages-from-mex

[4] warning: https://www.mathworks.com/help/matlab/matlab_prog/suppress-warnings.html

[5] mexCallMATLABWithTrap: https://www.mathworks.com/help/matlab/apiref/mexcallmatlabwithtrap.html

[6] handling Matlab errors in MEX: http://www.advanpix.com/2016/02/14/short-and-informative-error-messages-from-mex/

[7] mexWarnMsgIdAndTxt: https://www.mathworks.com/help/matlab/apiref/mexwarnmsgidandtxt.html

[8] Better MEX error messages : https://undocumentedmatlab.com/articles/better-mex-error-messages

[9] Setting status-bar text : https://undocumentedmatlab.com/articles/setting-status-bar-text

[10] Setting status-bar components : https://undocumentedmatlab.com/articles/setting-status-bar-components

[11] Sending email/text messages from Matlab : https://undocumentedmatlab.com/articles/sending-email-text-messages-from-matlab

[12] Setting system tray popup messages : https://undocumentedmatlab.com/articles/setting-system-tray-popup-messages

[13] MEX ctrl-c interrupt : https://undocumentedmatlab.com/articles/mex-ctrl-c-interrupt

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.