[PD-dev] how to dinamically allocate t_atom & t_float size?

Christof Ressi info at christofressi.com
Sat Dec 5 16:32:52 CET 2020


I forget to mention another important caveat, which is related to b):

d) don't ever call alloca() *inside* a loop

Alloca() is *not* block scoped! The stack is only restored on the next 
function return, so by calling alloca() in a loop you can easily create 
a stack overflow by accident.

VLAs, on the other hand, are block scoped, so they can be safely used in 
a loop. Unfortunately, they are not part of the most recent C or C++ 
standard. C99 made VLAs part of the language, but C11 made it optional 
again. C++ never included VLAs, but the feature has existed in the form 
of compiler extensions.

---

Maybe I can sum it up with:

Don't use alloca() unless you have a good reason, know how it works 
internally and are aware of all its problems :-).

Christof

On 05.12.2020 12:54, Christof Ressi wrote:
>
> Your concerns are certainly warranted.
>
> But if the function is
>
> a) never called recursively,
>
> b) is never inlined(!)* and
>
> c) the buffer size is guaranteed not to exceed some reasonable size 
> for stack allocation (say a few hundred bytes),
>
> then alloca() is IMO the best tool for the job. It is not only simpler 
> but also faster than pre-allocation, because the stack memory is much 
> more likely to be in cache.
>
> Again, I wouldn't recommend using alloca() for general purpose 
> programming, but when used cautiously it can be a great tool for 
> real-time code.
>
> ---
>
> BTW, here's an example for how alloca() might be used in a 
> production-grade library: 
> https://github.com/gcp/opus/blob/master/celt/stack_alloc.h
>
> It uses alloca() resp. VLAs, but can fallback to a pseudo stack for 
> platforms without alloca()/VLA support or small stack sizes (e.g. 
> embedded devices).
>
> Christof
>
> *) IIRC, GCC refuses to inline functions if they contain alloca() 
> statements. What can go wrong with inlined functions containing 
> alloca(): https://stackoverflow.com/a/3410689/6063908
>
> On 04.12.2020 16:57, Jonathan Wilkes wrote:
>> > On Friday, December 4, 2020, 9:43:20 AM EST, Christof Ressi 
>> <info at christofressi.com> wrote:
>>
>> > alloca() "allocates" memory on the stack. This is done by simply 
>> incrementing the stack pointer. So it's extremely fast and - more 
>> importantly - equally fast for all sizes.
>>
>> It also requires you, the programmer, to add up the total number of 
>> possible allocations in a recursive call to the object, for supported 
>> platforms with small default stack sizes, and doing the math in your 
>> head to ensure your algorithm will never go over that stack limit, 
>> for all possible cases. Since that stack limit is many orders of 
>> magnitude smaller than the RAM on the most popular Pd platform, 
>> you're way more likely to accidentally cause crashes for your users 
>> by relying on alloca.
>>
>> Again, the ATOMS_ALLOCA macro in x_list.c is the careful, thoughtful 
>> reference for use of alloca. And even in that case there are almost 
>> certainly multiple ways to cause a crasher from it. In other words, 
>> it's nearly impossible to use alloca safely.
>>
>> Don't use alloca *unless* you have made worst case measurements on 
>> every other algorithm you can think of, and none of them are 
>> satisfactory. Even then, *measure* alloca to be worst-case safe and 
>> write regression tests for the recursive edge cases that could blow 
>> the stack. Chances are when you consider doing that extra work, 
>> you'll quickly think up a different algorithm that doesn't rely on 
>> alloca.
>>
>> > malloc(), on the other hand, actually uses the system memory 
>> allocator which can take arbitrarily long and might even block!
>>
>> > Generally, you should avoid using any malloc() in real-time code 
>> paths. Instead, pre-allocate temporary buffers (e.g. in the "dsp" 
>> method) or allocate on the stack (but note the caveats mentioned in 
>> the other mails).
>>
>> Pre-allocate.
>>
>> If you can't, ask on the list how to use alloca without blowing the 
>> stack. Once you crowdsource a truly safe algorithm, write tests so 
>> you catch the crashers that the crowd missed the first time around.
>>
>> To be clear-- I basically grepped for "alloca" in the current 
>> codebase, opened up x_list.c, and *assumed* because alloca is tricky 
>> that there is somehow a crasher bug. It took about 5 minutes to come 
>> up with a case that should crash on Windows.
>>
>> I also see it in m_binbuf.c, and I'd make the same bet it can blow 
>> the Windows stack if someone spends five minutes looking at the code. 
>> For a common building block of realtime safe algos, I shouldn't be 
>> able to make claims like these for any use of alloca I happen to find.
>>
>> I keep harping on this because the default description of alloca 
>> makes it sound like the quintessential building block of realtime 
>> algos. Please weigh that alluring set of seeming realtime safe 
>> benefits against the history of realtime unsafe crashers of which 
>> will likely include your use alloca.
>>
>> Best,
>> Jonathan
>>
>> > Christof
>>
>> On 04.12.2020 03:28, Alexandre Torres Porres wrote:
>> I'm using getbytes and freebytes for now, any disadvantages over alloca?
>>
>> thanks!
>>
>> Em qui., 3 de dez. de 2020 às 20:59, David Rush <kumoyuki at gmail.com 
>> <mailto:kumoyuki at gmail.com>> escreveu:
>>
>>     On Thu, 3 Dec 2020 at 23:15, Alexandre Torres Porres
>>     <porres at gmail.com <mailto:porres at gmail.com>> wrote:
>>
>>         Hi, when compiling ELSE for camomille in windows, me and
>>         Esteban are getting some errors. Offending pieces of code are
>>         when trying to do things like
>>
>>         t_atom at[ac];
>>
>>
>>     If you want to maintain straight C compiler compatibility
>>
>>             t_atom* at = (t_atom*)malloc(ac * sizeof(t_atom));
>>
>>     but you have to remember to free(at), &cet. You can avoid the
>>     free() if you HAVE_ALLOCA with
>>
>>             t_atom* at = (t_atom*)alloca(ac * sizeof(t_atom));
>>
>>     if you want to do it the C++ way without a std::vector<t_atom>
>>
>>             t_atom* at = new t_atom[ac];
>>
>>     but again you will have to
>>
>>             delete at;
>>
>>     For my own externals, I write them all in C++ and use STL. Making
>>     the change from the C-world allocation of PD to the C++ world is
>>     not so hard, but it does involve a tiny bit of trickery which I
>>     only justify through expediency.
>>
>>     - d
>>
>>
>> _______________________________________________
>> Pd-dev mailing list
>> Pd-dev at lists.iem.at  <mailto:Pd-dev at lists.iem.at>
>> https://lists.puredata.info/listinfo/pd-dev  <https://lists.puredata.info/listinfo/pd-dev>
>> _______________________________________________
>> Pd-dev mailing list
>> Pd-dev at lists.iem.at <mailto:Pd-dev at lists.iem.at>
>> https://lists.puredata.info/listinfo/pd-dev 
>> <https://lists.puredata.info/listinfo/pd-dev>
>
> _______________________________________________
> Pd-dev mailing list
> Pd-dev at lists.iem.at
> https://lists.puredata.info/listinfo/pd-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puredata.info/pipermail/pd-dev/attachments/20201205/515c2918/attachment-0001.html>


More information about the Pd-dev mailing list