<html><head></head><body><div class="ydpeffcb64dyahoo-style-wrap" style="font-family: Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 13px;"><div></div>
        <div><span style="color: rgb(38, 40, 42);">> On Thursday, July 4, 2019, 07:52:05 PM EDT, Christof Ressi <christof.ressi@gmx.at> wrote:</span><br></div></div><div id="ydp913e7515yahoo_quoted_3316784665" class="ydp913e7515yahoo_quoted"><div style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:13px;color:#26282a;">
                <div><br></div>
                <div>>>  > how big of a list xcan we have in Pd?<br></div><div><div dir="ltr" data-setdir="false">>> 100<br clear="none"><br clear="none">> That's only the internal limit for stack allocation in the [list] methods.<br clear="none"><br>There's no easy way to measure the worst case performance for malloc/free, much </div><div dir="ltr" data-setdir="false">less predict the worst cases on other supported platforms of Pd.</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">So if low latency realtime scheduling is desired, then the most sane way to achieve </div><div dir="ltr" data-setdir="false">that is to limit the number of malloc/free calls to as few as possible during DSP </div><div dir="ltr" data-setdir="false">computation (or if it's not a DSP-based patch, then during the normal runtime of </div><div dir="ltr" data-setdir="false">the patch after all loadbangs have been fired).</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">That means always taking the stack allocation path for list classes. The way to do  </div><div dir="ltr" data-setdir="false">that is to limit list output sizes to a maximum of 100 elements.</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">Also notice that any copying of lists requires a loop to copy each element of the </div><div dir="ltr" data-setdir="false">list to the new list (regardless of how the target list got allocated). So for maximally  </div><div dir="ltr" data-setdir="false">predictable runtime performance, try not to use any list objects that require copying </div><div dir="ltr" data-setdir="false">lists. (This is why the crazy recursive list-abs/list-drip abstraction is performant.)</div><div dir="ltr" data-setdir="false"><br clear="none">>> > How many elements can a t_atom have?<br clear="none">>> 1000<br clear="none"><br clear="none">> What does this even mean?<br clear="none"><br>It means evaluating a Pd message with greater than 1000 elements in a row which </div><div dir="ltr" data-setdir="false">are neither commas or semis will trigger a </div><div dir="ltr" data-setdir="false">malloc/free pair each time the message gets evaluated. So for low latency realtime </div><div dir="ltr" data-setdir="false">performance scheduling, don't do that during normal patch runtime.</div><div dir="ltr" data-setdir="false"><br clear="none">>> For best results, no bigger than:<br clear="none">>> 5<br clear="none"><br clear="none">> Everything below 100 elements is equally fine (no heap allocation)<br clear="none"><br>Five elems and below avoids an alloca call by just assigning to a 5 element array "smallstack" </div><div dir="ltr" data-setdir="false">in binbuf_eval. I haven't measured so I have no idea if that's a premature optimization, </div><div dir="ltr" data-setdir="false">though.</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">Also note: binbuf_eval already has an #ifdef for simply allocating for the entire message size, </div><div dir="ltr" data-setdir="false">and the comment mentions decreased performance for whatever tests were run. I'm sure it </div><div dir="ltr" data-setdir="false">would be worse performance for loading patches as those would almost be the worst possible case: </div><div dir="ltr" data-setdir="false">large number of args where semis break the message up into fairly regular small chunks that </div><div dir="ltr" data-setdir="false">would typically fit into an alloca or even a smallstack (e.g., "#X obj 20 20 bang;").</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">Random digression-- why doesn't t_binbuf just cache some annotations about itself like</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">* count for its longest nested message (e.g., contiguous region with no semis or commas</div><div dir="ltr" data-setdir="false">* gpointer count</div><div dir="ltr" data-setdir="false">* whether its a constant message (e.g., do we have dollar signs)</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">It appears every way to populate a t_binbuf already loops through the elements, *and* that </div><div dir="ltr" data-setdir="false">they allocate memory there. Seems like users would see a performance increase by caching </div><div dir="ltr" data-setdir="false">at least the maxnargs in the t_binbuf itself to avoid a full loop through the binbuf in </div><div dir="ltr" data-setdir="false">binbuf_eval.</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">Constant message annotation could be nice, too. If a message box was just [1 2 3 4 5( </div><div dir="ltr" data-setdir="false">then the message could just do an end run around the message evaluation. (Of course that </div><div dir="ltr" data-setdir="false">would add a branch for every message that isn't constant, so it'd need to be measured...)</div><div dir="ltr" data-setdir="false"><br></div><div dir="ltr" data-setdir="false">-Jonathan</div></div>
            </div>
        </div></body></html>