Thread Subject: Inplace array (mex)

Subject: Inplace array (mex)

From: Bruno Luong

Date: 27 Jun, 2009 12:41:01

Message: 1 of 10

I want to create an inplace column vector using MEX. The idea is to create a column array that has its data pointer points on the the data block of an existing (input) matrix. Everything going well until I set the data pointer. Then it crashes

a=rand(1,7)

a =

    0.8147 0.9058 0.1270 0.9134 0.6324 0.0975 0.2785

>> b=inplacecolumn(a,3)

Am I allowed to do such thing? If not what cause the crash?

Bruno

/* Here is my INPLACECOLUMN MEX function

/*************************************************************************
 * function b = inplacecolumn(a, k)
 * Return the inplace-column a(:,k)
 ************************************************************************/
#include "mex.h"
#include "matrix.h"

/* Gateway of inplacecolumn */
void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[]) {
    
    mwSize k, N, M;
    double *Pr;
    
    /* Check arguments */
    if (nrhs<2)
        mexErrMsgTxt("INPLACECOLUMN: Two input arguments required.");
    
    if (!mxIsNumeric(prhs[0]))
        mexErrMsgTxt("INPLACECOLUMN: First input LIST argument must be numeric.");
    
    if (!mxIsNumeric(prhs[1]))
        mexErrMsgTxt("INPLACECOLUMN: Second input K must be numeric.");

    M = mxGetM(prhs[0]);
    N = mxGetN(prhs[0]);
    
    /* Get the column number k */
    if (mxGetM(prhs[1])!=1 || mxGetN(prhs[1])!=1)
        mexErrMsgTxt("INPLACECOLUMN: Second input K must be a scalar.");
    
    if (mxGetClassID(prhs[1]) != mxDOUBLE_CLASS)
        mexErrMsgTxt("INPLACECOLUMN: Second input K must be a double.");
    
    k = (mwSize)(*mxGetPr(prhs[1]));
    if (k<1 || k>N)
        mexErrMsgTxt("INPLACECOLUMN: K is not valid.");
    
    /* Create the Matrix result (first output) */
    plhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    Pr = mxGetPr(plhs[0]);
    mxFree(Pr);

    /* Set the dimension as one column */
    mxSetM(plhs[0], M);
    mxSetN(plhs[0], 1);
    
    /* Inplace data pointer */
    Pr = mxGetPr(prhs[0]);
    /* Ir crashes here when k>1 */
    mxSetPr(plhs[0], Pr+((k-1)*M));
      
    return;

} /* Gateway of INPLACECOLUMN.c */

Subject: Inplace array (mex)

From: James Tursa

Date: 27 Jun, 2009 20:27:01

Message: 2 of 10

"Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h2540t$73d$1@fred.mathworks.com>...
> I want to create an inplace column vector using MEX. The idea is to create a column array that has its data pointer points on the the data block of an existing (input) matrix. Everything going well until I set the data pointer. Then it crashes
>
> a=rand(1,7)
>
> a =
>
> 0.8147 0.9058 0.1270 0.9134 0.6324 0.0975 0.2785
>
> >> b=inplacecolumn(a,3)
>
> Am I allowed to do such thing? If not what cause the crash?

No. You cannot do this. The problem is what happens when variables get cleared. If "a" gets cleared, the MATLAB memory manager knows nothing about this shared memory with "b". So the data memory for "a" is freed, and suddenly the "b" data pointer is pointing to invalid memory. Of course any access of this memory downstream could cause a crash. And what happens when you clear "b", either before or after "a" is cleared? The MATLAB memory manager does not have any memory block address for allocations that match the "b" data pointer, so when it tries to check for sharing or tries to free this memory the results will be undefined, again potentially resulting in a crash.

You *can* get away with this behavior, but you have to be *very* careful to never do anything that would cause the original full data block that "b" is pointing to to be cleared before "b" is properly cleared, never do anything that would cause data sharing with "b" and another variable (e.g., assignment or reshape), and never clear "b" until you could manually detach its data pointer with another specialized mex routine. e.g., consider this mex routine called uninplacecolumn.c

/* Here is my UNINPLACECOLUMN MEX function

/*************************************************************************
 * function uninplacecolumn(a)
 * Detaches the data from an inplace column mxArray that was created
 * with the inplacecolumn function.
 ************************************************************************/
#include "mex.h"
#include "matrix.h"

#define mwSize int

/* Gateway of inplacecolumn */
void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[]) {
    
    mwSize k, N, M;
    double *Pr;
    
    /* Check arguments */
    if (nrhs!=1)
        mexErrMsgTxt("UNINPLACECOLUMN: One input argument required.");
    
    if( nlhs != 0 ) {
        mexErrMsgTxt("UNINPLACECOLUMN: Zero output arguments required.");
    }
    
    mxSetM(prhs[0], 0);
    mxSetN(prhs[0], 0);
    mxSetPr(prhs[0], NULL);
      
    return;

} /* Gateway of UNINPLACECOLUMN.c */

And then consider this sequence of MATLAB commands:

>> format debug
>> a=rand(3,3)
a =
Structure address = 39cd9a0
m = 3
n = 3
pr = 10181f60
pi = 0
    0.9501 0.4860 0.4565
    0.2311 0.8913 0.0185
    0.6068 0.7621 0.8214
>> b=inplacecolumn(a,2)
b =
Structure address = fe74120
m = 3
n = 1
pr = 10181f78
pi = 0
    0.4860
    0.8913
    0.7621
>> c=2*b
c =
Structure address = fe73560
m = 3
n = 1
pr = fe643e0
pi = 0
    0.9720
    1.7826
    1.5242
>> uninplacecolumn(b)
>> b
b =
     []
>> clear b
>> a
a =
Structure address = 39cd9a0
m = 3
n = 3
pr = 10181f60
pi = 0
    0.9501 0.4860 0.4565
    0.2311 0.8913 0.0185
    0.6068 0.7621 0.8214
>> c
c =
Structure address = fe73560
m = 3
n = 1
pr = fe643e0
pi = 0
    0.9720
    1.7826
    1.5242
>> clear all
>> whos

This all works because

1) I didn't clear "a" before I cleared "b"
2) I never used "b" in a way that caused data sharing with another variable
3) I detached the data pointer for "b" before I cleared "b"

James Tursa

Subject: Inplace array (mex)

From: Bruno Luong

Date: 27 Jun, 2009 21:13:01

Message: 3 of 10

"James Tursa" <aclassyguywithaknotac@hotmail.com> wrote in message <h25val$cna$1@fred.mathworks.com>...
> "Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h2540t$73d$1@fred.mathworks.com>...
> > I want to create an inplace column vector using MEX. The idea is to create a column array that has its data pointer points on the the data block of an existing (input) matrix. Everything going well until I set the data pointer. Then it crashes
> >
> > a=rand(1,7)
> >
> > a =
> >
> > 0.8147 0.9058 0.1270 0.9134 0.6324 0.0975 0.2785
> >
> > >> b=inplacecolumn(a,3)
> >
> > Am I allowed to do such thing? If not what cause the crash?
>
> No. You cannot do this. The problem is what happens when variables get cleared. If "a" gets cleared, the MATLAB memory manager knows nothing about this shared memory with "b". So the data memory for "a" is freed, and suddenly the "b" data pointer is pointing to invalid memory. Of course any access of this memory downstream could cause a crash. And what happens when you clear "b", either before or after "a" is cleared? The MATLAB memory manager does not have any memory block address for allocations that match the "b" data pointer, so when it tries to check for sharing or tries to free this memory the results will be undefined, again potentially resulting in a crash.
>

Oh James, I don't worry about those clearing things, I can just right my own inplace CLEAR to undo the b, in the reverse sequences from how they are created (such like your uninplacecolumn).

My problem is I cannot even create such in-place pointer in a newer Matlab version (can't tell which one). It works all right in older Matlab version, e.g., 2006B. Actually I was surprised by the example given in your post, and that's why I come back and run INPLACECOLUMN under 2006B and it works. So now this is the scope. What is going on with the newer Matlabn version to prevent me doing such thing?

I feel I must explain why I want to do such thing. The reason is I want to avoid unnecessary data copy when call a function using a column of a matrix:

a = rand(1000);
for k=1:size(A,2)
    myfun(a(:,k));
end

This calling will make a copy the data a(:,k) into a new vector. So I want to avoid the copy and do

a = rand(1000);
for k=1:size(A,2)
    ak = inplacecolumn(a,k);
    myfun(ak);
    uninplacecolumn(ak);
    clear ak;
end

But it seems this will not work with recent Matlab version. Now if someone knows something about the reason, I would love to hear!!!!

Bruno

Subject: Inplace array (mex)

From: James Tursa

Date: 27 Jun, 2009 21:42:01

Message: 4 of 10

"Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h2620t$162$1@fred.mathworks.com>...
>
> My problem is I cannot even create such in-place pointer in a newer Matlab version (can't tell which one). It works all right in older Matlab version, e.g., 2006B. Actually I was surprised by the example given in your post, and that's why I come back and run INPLACECOLUMN under 2006B and it works. So now this is the scope. What is going on with the newer Matlabn version to prevent me doing such thing?

Hmmm ... I can't answer that. The only thing I can think of is that they have changed the way their garbage collection works when the mex function returns and for some reason this results in corrupted memory in the newer version. You might try a couple of things:

1) Inside a single mex routine:
- Create an inplace column mxArray shared variable.
- Use it in some way (e.g., call mexCallMATLAB to multiply it by 2)
- Detach the data pointer and then call mxDestroyArray on it.

2) Try something similar inside an engine application.

If the above work, then it would point to the garbage collection as the culprit. But I don't really know how to verify this.

James Tursa

Subject: Inplace array (mex)

From: Bruno Luong

Date: 28 Jun, 2009 08:07:27

Message: 5 of 10

"James Tursa" <aclassyguywithaknotac@hotmail.com> wrote in message <h263n9$ham$1@fred.mathworks.com>...
> "Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h2620t$162$1@fred.mathworks.com>...
> >
> > My problem is I cannot even create such in-place pointer in a newer Matlab version (can't tell which one). It works all right in older Matlab version, e.g., 2006B. Actually I was surprised by the example given in your post, and that's why I come back and run INPLACECOLUMN under 2006B and it works. So now this is the scope. What is going on with the newer Matlabn version to prevent me doing such thing?
>
> Hmmm ... I can't answer that. The only thing I can think of is that they have changed the way their garbage collection works when the mex function returns and for some reason this results in corrupted memory in the newer version. You might try a couple of things:
>
> 1) Inside a single mex routine:
> - Create an inplace column mxArray shared variable.

James, I cannot even create an inplace shared variable, it crashes in the line mxSetPr. This occurs only on the recent Matlab version - I'm investigating from which version the problem arises. There is some internal mechanism that is not compatible with shared data. Quite annoying, because I can no longer optimize my code by using shared data.

Bruno

Subject: Inplace array (mex)

From: Bruno Luong

Date: 28 Jun, 2009 08:24:01

Message: 6 of 10

Below is part of the error message when it crashed. There is an internal check in libmwfl.dll and libmx.dll. Au revoir my freedom ;-(

>> a=rand(5)

a =

    0.7547 0.1190 0.2238 0.8909 0.2575
    0.2760 0.4984 0.7513 0.9593 0.8407
    0.6797 0.9597 0.2551 0.5472 0.2543
    0.6551 0.3404 0.5060 0.1386 0.8143
    0.1626 0.5853 0.6991 0.1493 0.2435

>> b=inplacecolumn(a,2)

ALIGNMENT ERROR: [VRP/VPA] vector_check: pointer not allocated with vector_*alloc
PID: 5912
NATIVE ALIGNMENT: 8 (0x8)
REQ ALIGNMENT: 16 (0x10)
ALIGNED POINTER: 0C8C25F8
REQ SIZE: 0 (0)
HEADER ADDRESS: 0C8C25F0
HEADER SIZE: 8 (0x8)
HEADER DATA: INACCESSIBLE

[ 0] 782FDBA0 C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00121760 ( fl::diag::stacktrace_base::capture+000022 )
[ 1] 782FDE10 C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00122384 ( fl::diag::stacktrace_base::stacktrace_base+000034 )
[ 2] 782FDE31 C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00122417 ( fl::diag::stacktrace_base::stacktrace_base+000067 )
[ 3] 782FE79C C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00124828 ( fl::app::not_initialized_exception::not_initialized_exception+001477 )
[ 4] 782FE8B1 C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00125105 ( fl::app::not_initialized_exception::not_initialized_exception+001754 )
[ 5] 782FEA16 C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00125462 ( fl::app::not_initialized_exception::not_initialized_exception+002111 )
[ 6] 782E73D9 C:/Program Files/MATLAB/R2009a/bin/win32/libmwfl.dll+00029657 ( std::_Init_locks::operator=+015445 )
[ 7] 7B369E07 C:/Program Files/MATLAB/R2009a/bin/win32/libmx.dll+00105991 ( mxSetPr+000039 )
[ 8] 03C0114F C:/Users/Bruno/Documents/matlab/misc/MinMaxSelection/inplacecolumn.mexw32+00004431 ( mexFunction+000335 )
...

Bruno

Subject: Inplace array (mex)

From: James Tursa

Date: 28 Jun, 2009 09:01:01

Message: 7 of 10

"Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h279b1$4q3$1@fred.mathworks.com>...
> Below is part of the error message when it crashed. There is an internal check in libmwfl.dll and libmx.dll. Au revoir my freedom ;-(

OK. Maybe as a last resort you could try the following. Use the incomplete mxArray structure definition that Peter Boettcher has listed on a website (can't remember the website right now). You can find it in this thread:

http://www.mathworks.com/matlabcentral/newsreader/view_thread/247881#639280

Put that at the top of your mex file and then set the pdata pointer directly instead of using the mxSetPr function. That will bypass any checking that is going on with the mxSetPr call. I think that this will at least allow you to temporarily build the mxArray. Can't say what will happen once you try to use it or pass it back to MATLAB though.

James Tursa

Subject: Inplace array (mex)

From: James Tursa

Date: 28 Jun, 2009 09:04:02

Message: 8 of 10

Follow-up. Here are the sources I used:

http://groups.google.com/group/comp.soft-sys.matlab/browse_thread/thread/c241d8821fb90275/47189d498d1f45b8?lnk=st&q=&rnum=1&hl=en#47189d498d1f45b8

http://www.mk.tu-berlin.de/Members/Benjamin/mex_sharedArrays

James Tursa

Subject: Inplace array (mex)

From: Bruno Luong

Date: 28 Jun, 2009 10:02:02

Message: 9 of 10

"James Tursa" <aclassyguywithaknotac@hotmail.com> wrote in message <h27bm1$1m4$1@fred.mathworks.com>...
> Follow-up. Here are the sources I used:
>
> http://groups.google.com/group/comp.soft-sys.matlab/browse_thread/thread/c241d8821fb90275/47189d498d1f45b8?lnk=st&q=&rnum=1&hl=en#47189d498d1f45b8
>
> http://www.mk.tu-berlin.de/Members/Benjamin/mex_sharedArrays
>
> James Tursa

Now that's an idea! I have tried and it works. There is a change of mxArray definition since posted by Peter and in the current version. Ideally, we should be able to adapt the definition by looking through the header MATRIX.H

Here is my code, and it works now.

Bruno

/*************************************************************************
 * function B = inplacecolumn(A, k)
 * Return the inplace-column A(:,k)
 * Important notes:
 * - use MEX function releaseinplace(B) to release properly shared-data
 * pointer before clear/reuse B.
 * - All inplace variables shared data with A must be released before
 * the original array A is cleared/reused.
 ************************************************************************/
#include "mex.h"
#include "matrix.h"

/* Internal representation of mxArray, inspired from mxArray_tag declared
 * in the header <matrix.h>. Todo: build automatically source code for
 * Internal_mxArray */
typedef struct {
    void *reserved;
    int reserved1[2];
    void *reserved2;
    size_t number_of_dims;
    unsigned int reserved3;
    struct {
        unsigned int flag0 : 1;
        unsigned int flag1 : 1;
        unsigned int flag2 : 1;
        unsigned int flag3 : 1;
        unsigned int flag4 : 1;
        unsigned int flag5 : 1;
        unsigned int flag6 : 1;
        unsigned int flag7 : 1;
        unsigned int flag7a: 1;
        unsigned int flag8 : 1;
        unsigned int flag9 : 1;
        unsigned int flag10 : 1;
        unsigned int flag11 : 4;
        unsigned int flag12 : 8;
        unsigned int flag13 : 8;
    } flags;
    size_t reserved4[2];
    union {
        struct {
            void *pdata;
            void *pimag_data;
            void *reserved5;
            size_t reserved6[3];
        } number_array;
    } data;
} Internal_mxArray;

/* Gateway of inplacecolumn */
void mexFunction(int nlhs, mxArray *plhs[],
                 int nrhs, const mxArray *prhs[]) {
    
    mwSize k, N, M;
    double *Pr;
    
    /* Check arguments */
    if (nrhs!=2)
        mexErrMsgTxt("INPLACECOLUMN: Two input arguments required.");
    
    if (!mxIsNumeric(prhs[0]))
        mexErrMsgTxt("INPLACECOLUMN: First input A argument must be numeric.");
    
    if (!mxIsNumeric(prhs[1]))
        mexErrMsgTxt("INPLACECOLUMN: Second input K must be numeric.");

    /* Get the size */
    M = mxGetM(prhs[0]);
    N = mxGetN(prhs[0]);
    
    /* Get the column number k from the second input */
    if (mxGetM(prhs[1])!=1 || mxGetN(prhs[1])!=1)
        mexErrMsgTxt("INPLACECOLUMN: Second input K must be a scalar.");
    
    if (mxGetClassID(prhs[1]) != mxDOUBLE_CLASS)
        mexErrMsgTxt("INPLACECOLUMN: Second input K must be a double.");
    
    k = (mwSize)(*mxGetPr(prhs[1]));
    /* Make sure k is valid */
    if (k<1 || k>N)
        mexErrMsgTxt("INPLACECOLUMN: K is not valid.");
    
    /* Create the Matrix result (first output) */
    plhs[0] = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    Pr = mxGetPr(plhs[0]);
    mxFree(Pr); /* Free the data, normally Pr is NULL and this does
                 * nothing */

    /* Set the dimension as one column */
    mxSetM(plhs[0], M);
    mxSetN(plhs[0], 1);
    
    /* Inplace data pointer of A */
    Pr = mxGetPr(prhs[0]);
    Pr += (k-1)*M; /* Point to the column #k */
    /* Equivalent to doing this: mxSetPr(plhs[0], Pr);
       but access directly to data pointer in order to by pass Matlab
       checking */
    ((Internal_mxArray*)(plhs[0]))->data.number_array.pdata = Pr;
      
    return;

} /* Gateway of INPLACECOLUMN.c */

Subject: Inplace array (mex)

From: Bruno Luong

Date: 28 Jun, 2009 12:43:00

Message: 10 of 10

I'm working through a function that provides the automatically C-structure definition of the mxArray. As it might have some interests (no longer worry about set up the code wrp to Matlab version), I post the code here:

function content = buildInternal_mxArrayDef(mxArraydefFilename)
% function content = buildInternal_mxArrayDef(mxArraydefFilename)
%
% Building the typedef of internal structure MxArray by looking inside
% the header file include file MATRIX.H. This ensure the definition used
% is compatible with the Matlab version
% The internal definition will be used by MEX file inplacecolumn and
% releaseinplace
%
% EXAMPLE USAGE:
% buildInternal_mxArrayDef('Internal_mxArray.h')
%
% Author: Bruno Luong <brunoluong@yahoo.com>
%
% History
% Original: 28-Jun-2009

% Location of the header file matrix.h
MLincludepath = [matlabroot() filesep 'extern' filesep 'include'];
matrixhfile = 'matrix.h';

fid = fopen([MLincludepath filesep matrixhfile]);
if fid>0
    c = textscan(fid, '%s', 'Delimiter', '\n', 'Whitespace', '');
    try
        fclose(fid);
    end
    
    content = c{1};
    
    % Look for the line containing "struct mxArray_tag {"
    idxmxArray_tag = strfind(content,'struct mxArray_tag {');
    l1 = find(~cellfun('isempty',idxmxArray_tag),1,'first');
    if isempty(l1)
        error('Cannot parse matrix.h file');
    end
    
    % Modify the mxArray_tag to typedef definition
    content{l1} = strrep(content{l1}, ...
                         'struct mxArray_tag', 'typedef struct');
    
    % Loop on the line and stop when the last curly bracket after
    % find the corresponding closed curly bracket
    % "struct mxArray_tag { ... }"
    l9 = 0;
    ncurlybrackets = 0;
    nlevels = 0;
    for l=l1:length(content)
        line = content{l};
        nopen = sum(line=='{');
        nclose = sum(line=='}');
        ncurlybrackets = ncurlybrackets + (nopen + nclose);
        nlevels = nlevels + (nopen - nclose);
        if ncurlybrackets>0 && nlevels==0
            l9 = l;
            % Modify the last line with the typedef name 'Internal_mxArray'
            lastcurly = find(line=='}',1,'last');
            line = [line(1:lastcurly) ...
                    ' Internal_mxArray' ...
                    line(lastcurly+1:end)];
            content{l} = line;
            break;
        end
    end
    if l9==0
        error('Cannot parse matrix.h file');
    end
    % Here is the definition we are interested in
    content = content(l1:l9);

    if nargin>=1
        thisfile = mfilename();
        fid = fopen(mxArraydefFilename,'wt');
        % Write a comment header
        fprintf(fid, ['/* Built automatically by ' thisfile '.m\n']);
        fprintf(fid, ['\tBuilt date: ' datestr(now) '\n']);
        fprintf(fid, ['\tMatlab version: ' version('-release') '\n']);
        fprintf(fid, '*/\n\n');
        
        if fid>0
            % Write the content to header file
            for l=1:length(content)
                fprintf(fid, '%s\n', content{l});
            end
            try
                fclose(fid);
            end
        else
            error('Cannot write the header file %s', mxArraydefFilename);
        end
    end
else % fail to open matrix.h
    error('Cannot find ML <matrix.h> file');
end

% Bruno

Tags for this Thread

Everyone's Tags:

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Tag Activity for This Thread
Tag Applied By Date/Time
pissing contest Steve Amphlett 28 Jun, 2009 11:22:16
inplace column Sprinceana 28 Jun, 2009 05:01:20
mex Sprinceana 28 Jun, 2009 05:01:20
rssFeed for this Thread
 

MATLAB Central Terms of Use

NOTICE: Any content you submit to MATLAB Central, including personal information, is not subject to the protections which may be afforded information collected under other sections of The MathWorks, Inc. Web site. You are entirely responsible for all content that you upload, post, e-mail, transmit or otherwise make available via MATLAB Central. The MathWorks does not control the content posted by visitors to MATLAB Central and, does not guarantee the accuracy, integrity, or quality of such content. Under no circumstances will The MathWorks be liable in any way for any content not authored by The MathWorks, or any loss or damage of any kind incurred as a result of the use of any content posted, e-mailed, transmitted or otherwise made available via MATLAB Central. Read the complete Terms prior to use.

Contact us at files@mathworks.com