Tue May 9 09:49:16 CEST 2006
Gaspar Chilingarov wrote:
> Can erlang vm's gurus tell me which case is more efficient
> R = size(Binary),
> [ SomeFunction(R, X) || X <- lists:seq(1, 1000) ]
> [ SomeFunction(size(Binary), X) || X <- lists:seq(1, 1000) ]
> so - does compiler and vm understand that some parts of recursion are
> constant and move their calculation outside of recursion or I should do
> it by hand?
The Beam compiler does not do that kind of optimization. But even if it
was capable of hoisting computations out of a loop, it would also have
to be able to prove that it does not change the behaviour of exceptions.
For instance, if the call to lists:seq/1 crashes (maybe you've replaced
the standard version with your own buggy implementation), then that
exception must happen before the exception in size(Binary), if Binary
turns out to be not a binary (or tuple). So, there's more work to it
than you might think. Not impossible, just rarely worth the effort.
> Another issue - what if size(BInary) changed to ... say self() - I mean
> that fetching binary size may be faster operation than creating variable
> and accessing it every time.
For self() there is no point keeping it in a variable. I did some quick
measuring to settle this: In a *very tight* loop, it is slightly *slower*
to keep an extra parameter than to call self() repeatedly, but the
difference is only about 1-2 percent.
For size(Binary), you must always pass at least one extra argument around
the loop: either Binary itself, or a precomputed Size. In the same *very
tight* loop as above, calling size/1 on each iteration is about 15% slower.
Inserting some "real work" in each iteration will make this difference
Conclusion: don't manually hoist expressions that are O(1) unless you
*know* that they have a significant time constant (relative to the context
that you are using them in, of course). But if they ought to be hoisted,
you need to do it yourself - the compiler does not do that for you.
More information about the erlang-questions