Hi Gordon, As you can see, BuckleScript already did a very good good job here, of course, there are still places for improvement. To write extremely high performance code, you should avoid creating a closure in a tight loop, here you can lift the `nxtc` into the toplevel, in the future, we will do this inside the compiler. Lets take further discussions off the list -- Hongbo
On Wed, Jan 4, 2017 at 1:17 AM, GordonBGood <[email protected]> wrote: > Hi Bob/Hongbo, > > I've run into my first speed problem with BuckleScript: When it decides > it needs to form a closure of captured free binding(s), it creates a > "function returning a function" with the outer function's arguments being > the current state of the "pure" captured bindings, and the inner returned > function the actual closure code. When this happens anywhere near an inner > loop, the code gets very slow, although sometimes the compiler is smart > enough to infer that the closure is not necessary is when the binding value > is an argument of an enclosing function; however, this does not happen for > local `let` bindings even when they are in the same scope as the > callee/caller sites. > > For example, the following bit-packed Sieve of Eratosthenes sieves over a > range and returns the bit packed array of found primes over that range > (odds-only. It runs about five times slower than using imperative code > for/while loops (top of a quarter million). Code is as follows: > > let soe_loop top = > if top < 3 then Array.make 0 0 else > let ndxlmt = (top - 3) lsr 1 in > let cmpsts = Array.make ((ndxlmt lsr 5) + 1) 0 in > for loop = 1 to 1000 do (* do it many times for timing *) > let pir = ref 0 in > while !pir <= ndxlmt do > let pi = !pir in > let p = pi + pi + 3 in > let rec nxtc ci = > if ci > ndxlmt then () else > let w = ci lsr 5 in > cmpsts.(w) <- cmpsts.(w) lor (1 lsl (ci land 31)); > nxtc (ci + p) in > let si = (p * p - 3) lsr 1 in > if si > ndxlmt then pir := ndxlmt + 1 else ( > if cmpsts.(pi lsr 5) land (1 lsl (pi land 31)) == 0 then > nxtc si > cmpsts > > where the outer `pi` loops are imperative and the inner `nxtc` loop is > functional; this latter becomes the closure that captures the `p` value as > you can see in the following generated JavaScript: > > function soe_loop(top) { > if (top < 3) { > return Caml_array.caml_make_vect(0, 0); > } > else { > var ndxlmt = ((top - 3 | 0) >>> 1); > var cmpsts = Caml_array.caml_make_vect((ndxlmt >>> 5) + 1 | 0, 0); > for(var loop = 1; loop <= 1000; ++loop){ > var pir = 0; > while(pir <= ndxlmt) { > var pi = pir; > var p = (pi + pi | 0) + 3 | 0; > var nxtc = (function(p){ > return function nxtc(_ci) { > while(true) { > var ci = _ci; > if (ci > ndxlmt) { > return /* () */0; > } > else { > var w = (ci >>> 5); > cmpsts[w] = cmpsts[w] | (1 << (ci & 31)); > _ci = ci + p | 0; > continue ; > > } > }; > } > }(p)); > var si = ((Caml_int32.imul(p, p) - 3 | 0) >>> 1); > if (si > ndxlmt) { > pir = ndxlmt + 1 | 0; > } > else { > if (!(cmpsts[(pi >>> 5)] & (1 << (pi & 31)))) { > nxtc(si); > } > pir = pi + 1 | 0; > } > }; > } > return cmpsts; > } > } > > As the compiler knows that the `p` value is pure, it should know that it > can reference it without danger of it being in an unknown state, so there > is no need for a cloaure, and if `nxtc` is not a closure then it can be > inlined as usual. > > The same thing happens currently when all loops are functional. > > The back up work around is to use imperative code, but that's ugly. I > wonder if you have any suggestions to avoid the closure? > > Regards, Gordon > >> >> > -- > You received this message because you are subscribed to a topic in the > Google Groups "Elm Discuss" group. > To unsubscribe from this topic, visit https://groups.google.com/d/ > topic/elm-discuss/Um7WIBTq9xU/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- Regards -- Hongbo Zhang -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
