<div dir="ltr">Thanks Bill, that looks very encouraging. I have to context switch over to earning a living for a couple of days, but I will dig into this later this week. I think it would be helpful to be able to turn the GC on with control of whether it is instantly triggered, from both C and Scheme, but it sounds like it should not be a problem to get it to work fine for note/control level realtime. (aka &quot;very soft realtime&quot;? haha). Most people running a real time DAW with softsynths are going to be expecting to run with an audio latency of 5ms or more anyway, so I think this should be possible. (Phew!) <div><br></div><div>That makes sense about the threading. I need to figure out exactly how Max handles it&#39;s switches too. There may be some kind of protection there that I don&#39;t know about (not the most documented part of Max...)</div><div><br><div>I sure appreciate the help fellows!</div></div><div>iain</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Nov 23, 2020 at 7:25 AM &lt;<a href="mailto:bil@ccrma.stanford.edu">bil@ccrma.stanford.edu</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">in C:<br>
<br>
s7_gc_on(sc, false); /* blocks the GC from running, but the heap will <br>
grow if necessary */<br>
s7_gc_on(sc, true).  /* allow the GC to run, does not trigger the GC */<br>
<br>
in Scheme:<br>
(gc #f) ; same as s7_gc_on(sc, false)<br>
(gc #t) ; turns GC on and calls the GC<br>
<br>
I could change (gc #t) to simply re-allow GC&#39;s I suppose.<br>
<br>
On the times: here I am running s7test (which creates lots of objects) <br>
with<br>
(set! (*s7* &#39;gc-stats) #t)<br>
<br>
/home/bil/motif-snd/ repl s7test.scm<br>
load s7test.scm<br>
gc freed 111174/128000 (free: 126037), time: 0.000683<br>
gc freed 117417/128000 (free: 125595), time: 0.000442<br>
gc freed 111427/128000 (free: 111491), time: 0.000632<br>
gc freed 109546/128000 (free: 111432), time: 0.000835<br>
gc freed 103932/128000 (free: 111446), time: 0.000549<br>
gc freed 123825/128000 (free: 125522), time: 0.000489<br>
gc freed 95883/128000 (free: 123736), time: 0.000485<br>
gc freed 3015/128000 (free: 123799), time: 0.000366<br>
gc freed 121331/128000 (free: 121395), time: 0.000806<br>
gc freed 123449/128000 (free: 123513), time: 0.000741<br>
gc freed 107711/128000 (free: 123489), time: 0.000832<br>
gc freed 111976/128000 (free: 123443), time: 0.000642<br>
gc freed 109104/128000 (free: 115881), time: 0.000687<br>
gc freed 101924/128000 (free: 115603), time: 0.000579<br>
gc freed 98488/128000 (free: 114473), time: 0.000575<br>
...<br>
<br>
So the interruption is normally less than a millisecond (this is using<br>
the default heap-size, but I don&#39;t think that matters much).  The mark<br>
process is almost insignificant in the overall computation, so don&#39;t <br>
worry<br>
about object types or layouts. The only case I&#39;ve seen where it matters<br>
are GC benchmarks based on millions of huge lists (mark_pair traverses<br>
each list, which can become tedious).<br>
<br>
It&#39;s possible you haven&#39;t noticed the GC because it&#39;s not being<br>
called much -- s7 goes to great lengths to avoid creating<br>
objects itself:<br>
<br>
(define (f)<br>
   (do ((i 0 (+ i 1))<br>
        (sum 0))<br>
       ((= i 1000) sum)<br>
     (set! sum (+ sum i))))<br>
<br>
(gc)<br>
(set! (*s7* &#39;gc-stats) 7)<br>
(display (f)) (newline)<br>
(gc)<br>
;; gc freed 102/128000 (free: 127828), time: 0.000084<br>
<br>
Set gc-stats and run your code -- maybe you don&#39;t need to do anything.<br>
<br>
I think if you have 2 threads calling into the same s7 interpreter, you <br>
do need<br>
to be sure they don&#39;t interrupt each other.  If you try to call <br>
s7_eval_c_string<br>
or something while the GC is being run from some other thread, you&#39;ll be <br>
unhappy.<br>
<br>
</blockquote></div>