<div dir="ltr">I'll make closer benchmarking of auto forcing later, but, it incurs a quite steep overhead. Meanwhile, I have a question:<div><div><br></div><div><br></div><div>With --enable-auto-forcing, at procedure calls, that is (procedure 'arg1 'arg2 'etc.), |procedure| is forced, as we can see by the example that in both interpreted and compiled mode, ((delay (begin (println "Forced.") (lambda (v) v))) #t) evaluates (and it prints out "Forced.").</div><div><br></div><div><br></div><div>I'd wildly guess that quite a lot of the overhead in auto-forcing is here. If you're sure the operator will never be a promise in any procedure call, then this particular aspect of auto forcing could be disabled.</div><div><br></div><div>(Without checking, I would guess that while Gambit may optimize so that local procedure calls may avoid being brought through the |force| logics, then, this optimization would do so that calls to procedures defined in *other* modules such as the runtime, would *not* be taken through |force| also. That should be positive for speed.)</div><div><br></div><div><br></div><div>Would it be possible for me to disable this particular aspect of the auto-forcing, to get higher performance?</div><div><br></div><div><div class="gmail_extra"><br><div class="gmail_quote">2017-06-16 13:52 GMT+08:00 Marc Feeley <span dir="ltr"><<a href="mailto:feeley@iro.umontreal.ca" target="_blank">feeley@iro.umontreal.ca</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Here is the definition of + from lib/_num.scm:<br>
<br>
(define-prim-nary (+ x y)<br>
  0<br>
  (if (##number? x) x '(1))<br>
  (##+ x y)<br>
  macro-force-vars<br>
  macro-no-check<br>
  (##pair? ##fail-check-number))<br>
<br>
The define-prim-nary macro will expand this to an n-ary procedure definition where the 0 argument case returns 0, the 1 argument case returns the argument if it is a number otherwise it raises a type error (by calling ##fail-check-number), and the general >= 2 argument case calls ##+ to fold the argument list. All arguments are passed to macro-force-vars to force the argument if it is a promise (and --enable-auto-forcing is used).<br>
<br>
Using set! to “short-circuit” promises is not a good idea because it introduces a cell for the variable (if local and not previously assigned) and this slows things down.  In early versions of Gambit (on Motorola 68K), the garbage collector did this short-circuiting (i.e. a reference to a promise was replaced with the value of the promise if it was previously forced).  This isn’t done currently but probably easy to add.<br>
<span class="m_-5918756775552197943gmail-HOEnZb"><font color="#888888"><br>
Marc<br>
</font></span><div class="m_-5918756775552197943gmail-HOEnZb"><div class="m_-5918756775552197943gmail-h5"><br>
<br>
<br>
> On Jun 15, 2017, at 11:04 PM, Adam <<a href="mailto:adam.mlmb@gmail.com" target="_blank">adam.mlmb@gmail.com</a>> wrote:<br>
><br>
> 2017-06-13 5:30 GMT+07:00 Bradley Lucier <<a href="mailto:lucier@math.purdue.edu" target="_blank">lucier@math.purdue.edu</a>>:<br>
><br>
> > On Jun 11, 2017, at 5:08 AM, Adam <<a href="mailto:adam.mlmb@gmail.com" target="_blank">adam.mlmb@gmail.com</a>> wrote:<br>
> ><br>
> > Possibly the "macro-force-vars", which is used all over the runtime and compiler, would have something to do with this, but I don't find its definition anywhere.<br>
> ><br>
><br>
> In _gambit#.scm:<br>
><br>
> (macro-define-syntax macro-force-vars<br>
>   (lambda (stx)<br>
>     (syntax-case stx ()<br>
>       ((_ vars expr)<br>
>        (if (let* ((co<br>
>                    (##global-var-ref<br>
>                     (##make-global-var '##compilation-options)))<br>
>                   (comp-opts<br>
>                    (if (##unbound? co) '() co)))<br>
>              (assq 'force comp-opts))<br>
><br>
>            (syntax-case (datum->syntax<br>
>                          #'vars<br>
>                          (map (lambda (x) `(,x (##force ,x)))<br>
>                               (syntax->list #'vars)))<br>
>                ()<br>
>              (bindings #'(let bindings expr)))<br>
><br>
>            #'expr)))))<br>
><br>
><br>
> Ah right, <a href="https://github.com/gambit/gambit/blob/9c3dcbdc322a10673370c0880696ba131144251d/lib/_gambit%23.scm#L316" rel="noreferrer" target="_blank">https://github.com/gambit/gamb<wbr>it/blob/9c3dcbdc322a10673370c0<wbr>880696ba131144251d/lib/_<wbr>gambit%23.scm#L316</a> , and used to be a define-macro, <a href="https://github.com/gambit/gambit/blob/29103e6a29b8fbbf7d6fc772a344b814be3f1c1a/lib/_gambit%23.scm#L492" rel="noreferrer" target="_blank">https://github.com/gambit/gamb<wbr>it/blob/29103e6a29b8fbbf7d6fc7<wbr>72a344b814be3f1c1a/lib/_<wbr>gambit%23.scm#L492</a> , and all the rest of the code is meticulously padded with its use.<br>
><br>
><br>
> This also sheds a bit of light on why the slot containing the promise is not replaced with the forced value. Maybe that would be possible in some situations though.. When |x| is a symbol, it could be |set!| with the forced value?<br>
><br>
> That would cover standard variable slots and not typedef, vector, pair etc. slots though, I guess I'd need to dig in a bit more to understand how this one actually works out. If you have any spontaneous ideas, feel free to share.<br>
><br>
><br>
> Any idea where in the sources fundamental primitives like |+| , |if| , |or| autoforce?<br>
<br>
</div></div></blockquote></div><br></div></div></div></div>