Forums > Dev

Porting PC External to Mac

May 22, 2006 | 2:11 am

I have written a pretty complex external (cellular automata simulator) for Max on my PC, and would like to also get it to run on the Mac.

I’m having a bit of trouble doing this, though. I’ve gotten the external to compile, and Max properly recognizes it. Its "main" method runs, as does its "create", at the proper time. When I actually start sending it data, though, it crashes.

I’m doing the actual porting on someone else’s computer that they use for regular computer-stuff, so my time on it is limited.

Signs are pointing toward some problem with memory management or the inclusion of improper libraries. Are there any recommendations seasoned mac or cross-platform developers could give?

I’m running CodeWarrior 9 on both machines, and have tried to maintain a single project for simplicity’s sake. However, this means I can’t use the templates, which is the only way the SDK offers to set up the project. This Wednesday, when I have access to the computer again, I’m going to bite the bullet and start with a template. It’s a bit upsetting, though, that there are no directions for starting a project from scratch other than "use our templates."

It’s a fairly new install on the mac, so there are no developer tools as of yet (i.e. no debugger), though previous trials usually traced the crash to STL code, hence my thought that it’s a memory management issue.

Any advice is appreciated.

Porting from:
Windows XP, Athlon64, Codewarrior 9
to:
OSX Panther, PowerBook (I think) pre-Intel, Codewarrior 9

Thanks!

-Alex


May 22, 2006 | 3:22 am

I went the opposite route with my externals: starting from the CW6/8
templates for targetting Mac OS, I cobbled together a template for
targetting XP externals. There was considerable blood & sweat but it *does
work*.

I’ve now got 80-100 externals running cross-platform (including some for
other people).

I’ve never had something work on Windows and crash on Mac (but a couple
the other way around). I would make absolutely sure you are using
consistent memory access: either getbytes() & Co. OR malloc() & Co. OR
NewPtr() & Co. OR sysmem_XXX & Co. You can possibly mix sysmem-calls with
malloc() on XP with imputnity but that will !!!DIE!!! on Mac OS.

As for libraries. I use:

MSL_Runtime_PPC.Lib
CarbonLib
MaxAudioLib.stub
MaxLib.stub
MSL_C_Carbon.Lib

for my Carbon-targeted builds. MaxAudioLib.stub is obviously only for MSP
objects. The MSL_* libs are for stdlib and stuff like that. CarbonLib is
only if you’re actually talking to Carbon (I have some of my own libraries
conditionally compile to use Carbon or Win32 stuff as appropriate). In
short: YMMV.

Good luck.

– P.


May 22, 2006 | 3:45 am

Thanks, I’ll try that combo of libraries, see if it helps any.

In case it matters (it probably does…), I forgot to mention that my external is written in C++ (exported as C) so I’m using new and delete for my memory management needs, along with whatever Codewarrior 9′s STL uses. I imagine the problem may be somewhere along these lines.

-Alex


May 22, 2006 | 3:56 am

Just another important note: t_getbytes() can allocate alot of memory
on Win but will fail on Mac when you try to alloc more than a certain
amount (look at the SDK docs, it tells you where the limit is).

Whenever I get crashes on Mac but not on Win it is most likely
related to screwed up memory allocation. Another thing that took me
ages to find was a crash on CodeWarrior (Mac) where I did a buf =
(char *)malloc(0) call trying to allocate memory of size 0! On
Windows with VC++ this gave buf = NULL but with CW I got a crash as
soon as I tried to check whether buf was NULL or not…

Olaf


May 22, 2006 | 3:36 pm

On 22 May 2006, at 03:11, Alex wrote:

> Porting from:
> Windows XP, Athlon64, Codewarrior 9
> to:
> OSX Panther, MacBook Pro (pre-Intel), Codewarrior 9

What’s a "MacBook Pro (pre-Intel)"?

Btw, if you’re doing new/delete via C++, it’s probably not safe at
interrupt. (I don’t know whether the calls are supposed to be thread-
safe.) What happens if Overdrive is off?

– N.

nick rothwell — composition, systems, performance — http://
http://www.cassiel.com


May 22, 2006 | 3:58 pm

Quote: nick rothwell / cassiel wrote on Mon, 22 May 2006 09:36
—————————————————-
>
> On 22 May 2006, at 03:11, Alex wrote:
>
> > Porting from:
> > Windows XP, Athlon64, Codewarrior 9
> > to:
> > OSX Panther, MacBook Pro (pre-Intel), Codewarrior 9
>
> What’s a "MacBook Pro (pre-Intel)"?
>

A typo from a non-mac-user, which was fixed quite some time ago in the original post.

> Btw, if you’re doing new/delete via C++, it’s probably not safe at
> interrupt. (I don’t know whether the calls are supposed to be thread-
> safe.) What happens if Overdrive is off?

I have a thread-safe scheme in place, but I’m actually not sure if it takes that into account. Will look into it, though it’s starting to look like I’ll have to overload new and delete. Am hoping I won’t have to write my own memory manager.


May 22, 2006 | 4:06 pm

I have lots of code that successfully uses new and delete. As long as
you use them in ‘safe’ parts of the code should be fine. For example,
my c++ code only calls new and delete in the new, free, and dsp()
methods in my externals.

best,
Tim


May 22, 2006 | 6:02 pm

Quote: Timothy Place wrote on Mon, 22 May 2006 10:06
—————————————————-
> I have lots of code that successfully uses new and delete. As long as
> you use them in ‘safe’ parts of the code should be fine. For example,
> my c++ code only calls new and delete in the new, free, and dsp()
> methods in my externals.
>
> best,
> Tim
>
—————————————————-

Yeah, I use new and delete pretty much all over the place. I’ve ensured that it won’t step on top of any of MY code (i.e. only one thread inside my code will do any such thing at any given time), but had neglected to consider whether it would step on top of stuff outside my code… I’m guessing I should be concerned about this…?


May 22, 2006 | 6:28 pm

Hi,

> I have lots of code that successfully uses new and delete. As long as
> you use them in ‘safe’ parts of the code should be fine. For example,
> my c++ code only calls new and delete in the new, free, and dsp()
> methods in my externals.
Is free a safe method in which to delete allocated memory for msp objects ?
Personnaly, I’m not freeing memory for msp objects in the free
function, because I was always getting crashes (I had the impression the
objects where still in the dsp chain)

(not freeing is not a problem for an object created at startup and
destroyed at end of application)

Regards
Chris


May 22, 2006 | 6:49 pm

Yes, but you must be careful to free things in the correct order. For
example, here is the free method from the tap.shift~ external:

void shift_free(t_shift *x)
{
short i;

dsp_free((t_pxobject *)x); // this must be first!
delete x->shifter;
for(i=0; i
delete x->signal_in[i];
for(i=0; i
delete x->signal_out[i];
}

best,
-tim


May 22, 2006 | 6:51 pm

Chris,
Free should be safe if and only if: the memory was alloc’ed via
malloc (not sure if sysmem always alloc’s via malloc, it could be
giving you chunks from a pooled allocation), the memory is not
referenced by any other objects (the address to the data was not given
to any other object), and your object is not going to reference the
data any longer. As a point of paranoia I always NULL out the
references after freeing data.

As was previously hinted at: don’t count on malloc being thread-safe,
and don’t count on free being thread-safe. There are some
implementations that are thread-safe but Libc on os x doesn’t use
those currently.

On a related note, it turns out that the os x "switchover" point for
vm_alloc vs. malloc chunk-pool style allocation is around 12k. If you
are constantly allocating and deallocating buffers or data structures
that are equal to or greater than 12k in size, you are incurring the
considerable performance penalty of allocating new zero-filled vm
pages. Worse, the zero-filling doesn’t happen until you try to write
to the vm page in question (which tends to be during the dsp render
callback in Max). In this case, consider either rolling your own
simple allocation pool, or grab tcmalloc from google and try to use
that, or only allocate less than 12k at a time. This goes for new and
delete in c++ as well, because gcc uses malloc internally for that.

_Mark


May 22, 2006 | 6:57 pm

Ok…. thanks…

> dsp_free((t_pxobject *)x); // this must be first!
that’s the problem in my msp objects… this line is at the end!!!!!

Thanks again

Chris


May 22, 2006 | 7:01 pm

> Chris,
> Free should be safe if and only if: the memory was alloc’ed via
> malloc (not sure if sysmem always alloc’s via malloc, it could be giving
> you chunks from a pooled allocation), the memory is not referenced by
> any other objects (the address to the data was not given to any other
> object), and your object is not going to reference the data any longer.
> As a point of paranoia I always NULL out the references after freeing data.
Yes, that’s the precautions I’m taking.

> As was previously hinted at: don’t count on malloc being thread-safe,
> and don’t count on free being thread-safe. There are some
> implementations that are thread-safe but Libc on os x doesn’t use those
> currently.
>
> On a related note, it turns out that the os x "switchover" point for
> vm_alloc vs. malloc chunk-pool style allocation is around 12k. If you
> are constantly allocating and deallocating buffers or data structures
> that are equal to or greater than 12k in size, you are incurring the
> considerable performance penalty of allocating new zero-filled vm
> pages. Worse, the zero-filling doesn’t happen until you try to write to
> the vm page in question (which tends to be during the dsp render
> callback in Max). In this case, consider either rolling your own simple
> allocation pool, or grab tcmalloc from google and try to use that, or
> only allocate less than 12k at a time. This goes for new and delete in
> c++ as well, because gcc uses malloc internally for that.
Usually, I don’t allocate any memory during critical code section
whatever the language is, for performance reasons. Your remark is a good
explanation for this…

Regards
CHris


May 22, 2006 | 7:04 pm

Woah, that’s a total head screw right there…

could you explain why you free x and then dereference x?
That seems like the exact opposite of what I would want to do.
Does dsp_free queue the free and make sure nothing references the
object?

_Mark


May 22, 2006 | 7:24 pm

Yeah, I guess that looks kind of curious. The hint that this doesn’t
actually free all of x is the cast to a t_pxobject (which is what it
actually frees). Since the t_pxobject is required to be the first
member of the external’s struct, the address of x and the address of
the t_pxobject should be the same – and hence this confusing looking code.

best,
Tim


May 22, 2006 | 7:54 pm

Just a minor clarification, dsp_free() is not the same as freeobject
(). It doesn’t free the object itself, but rather the standard DSP
related resources, terminating any use of the perform method (waiting
on it to finish if it is already running in another thread). Note
that the signals which Tim is freeing aren’t DSP related resources,
but rather memory he has allocated.

It is *essential* for dsp_free() to come *first* in the destructor so
that user allocated memory (as is the case with these signal arrays)
will not be freed while the perform method is still running
(resulting in invalid access). Make sense?

-Joshua


June 28, 2007 | 12:12 pm

Hi !
I’m interested by the solution to compile externals for Windows XP. I am using XCode to develop my externals and I thought it might be possible to compile the externals *in xcode* but for windows with some packages. Is it possible ?
Do you know something about this kind ?

thank’s

BenCello


Viewing 17 posts - 1 through 17 (of 17 total)