Why does typecast make a copy?

91 views
Skip to first unread message

James Tursa

unread,
Mar 30, 2009, 8:00:18 PM3/30/09
to
Anybody know a good reason why typecast would need to make a copy of the data instead of sharing the data? Seems like MATLAB could easily share the data for this case much like using a lazy copy for other variables. e.g.,

>> format debug
>> A = rand(1,5)
A =
Structure address = 480bb20
m = 1
n = 5
pr = 21f9500
pi = 0
0.8003 0.1419 0.4218 0.9157 0.7922
>> B = A
B =
Structure address = 480d7e0
m = 1
n = 5
pr = 21f9500
pi = 0
0.8003 0.1419 0.4218 0.9157 0.7922
>> C = typecast(A,'int32')
C =
Structure address = 480c0a0
m = 1
n = 10
pr = 21fae50
pi = 0
Columns 1 through 6
-919590788 1072274405 -535586856 1069689172 149312458 1071316515
Columns 7 through 10
-1769005536 1072516532 797147986 1072257475

You can see that for the B = A case, a lazy copy was made since the data pointer pr for both variables is the same. But for the C = typecast(A,'int32') case, a copy of the data was made since the pr is now different from A. This seems unnecessary to me. The data could easily be shared here as well.

Related open question for the group: Anybody know how to make a lazy copy of a variable inside a mex routine? This would be a classic example of where a mex version of typecast could be made more efficient than the MATLAB intrinsic typecast, except that I cannot figure out how to do it.

James Tursa

Peter Boettcher

unread,
Mar 31, 2009, 11:48:50 AM3/31/09
to
"James Tursa" <aclassyguy...@hotmail.com> writes:

Try

mxCreateSharedCopy()
mxCreateSharedDataCopy()

Completely untested.

-Peter

James Tursa

unread,
Apr 1, 2009, 4:39:01 AM4/1/09
to
Peter Boettcher <boet...@ll.mit.edu> wrote in message <muy4ox9...@G99-Boettcher.llan.ll.mit.edu>...

> >
> > Related open question for the group: Anybody know how to make a lazy
> > copy of a variable inside a mex routine? This would be a classic
> > example of where a mex version of typecast could be made more
> > efficient than the MATLAB intrinsic typecast, except that I cannot
> > figure out how to do it.
>
> Try
>
> mxCreateSharedCopy()
> mxCreateSharedDataCopy()
>
> Completely untested.
>
> -Peter

Brilliant! It was *almost* exactly what I was looking for. I combined the struct mxArray_tag stuff you put together and listed on a website with the mxCreateSharedDataCopy() function you mentioned above and created a shared data copy. Then I manually changed the class_id of the variable and set the dimensions. I ended up with a typecast version of the variable that shares the data. Looks like it works (at least no seg faults so far ...)

James Tursa

e.g., the following (unpolished) code takes a double array input and creates a shared typecast int32 version of it (by doubling the number of rows). I did it for a large 100MB+ array and it worked. Used feature memstats to verify that clearing the original did not free up the memory, but clearing the typecast copy did free up the memory.
----------------------------------------------------------------------------------------------
#include "mex.h"
/* Definition of structure mxArray_tag for debugging purposes. Might not
* be fully correct for Matlab 2006b or 2007a, but the important things
* are. Thanks to Peter Boettcher.
*/
struct mxArray_tag {
const char *name;
mxClassID class_id;
int vartype;
mxArray *crosslink;
int number_of_dims;
int refcount;
struct {
unsigned int scalar_flag : 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 private_data_flag : 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;
int rowdim;
int coldim;
union {
struct {
double *pdata; // original: void*
double *pimag_data; // original: void*
void *irptr;
void *jcptr;
int nelements;
int nfields;
} number_array;
struct {
mxArray **pdata;
char *field_names;
void *dummy1;
void *dummy2;
int dummy3;
int nfields;
} struct_array;
struct {
void *pdata; /*mxGetInfo*/
char *field_names;
char *name;
int checksum;
int nelements;
int reserved;
} object_array;
} data;
};

mxArray *mxCreateSharedDataCopy(const mxArray *mx);

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if( nrhs != 1 || nlhs > 1 ) {
mexErrMsgTxt("Expect exactly 1 input and 0 or 1 output.");
}
if( !mxIsDouble(prhs[0]) || mxIsSparse(prhs[0]) ) {
mexErrMsgTxt("Input must be full double matrix.");
}
plhs[0] = mxCreateSharedDataCopy(prhs[0]);
(plhs[0])->class_id = mxINT32_CLASS;
mxSetM(plhs[0],mxGetM(plhs[0])*2);
}

Reply all
Reply to author
Forward
0 new messages