[PRL] Bob Harper's new blog

will at ccs.neu.edu will at ccs.neu.edu
Fri Mar 18 07:54:31 EDT 2011


David Herman wrote:
> I also still find the 90% figure incredibly high. Your point
> about loops is fair; it certainly does help inflate the number.
> But I would not be surprised if the number is highly variable
> depending on the community and application domain.

It does vary a lot.  It depends not only on the application
and the programming style, but upon tiny details of programming
language semantics and implementation.

Consider Scheme, for example.  You'd think that the R6RS semantics
would increase the percentage of calls to procedures whose code
can be determined statically, and that's usually the case, but the
R6RS also changed the semantics of internal definitions.  To do a
good job of optimizing the new R6RS semantics, compilers have to
implement a special-purpose flow analysis that, to my knowledge,
has been implemented only in Chez Scheme and in Ikarus.  Even with
that special-purpose flow analysis, it's easy to construct examples
that can be fully optimized only by generating two versions of the
code or by using a JIT compiler that compiles the code twice; JIT
compilers that compile the code only once can't fully optimize
these examples.

It turns out that the special-purpose R6RS flow analysis and/or
double compilation is more important than I had hoped.  The table
below shows the percentages of closed calls that were made to
procedures whose code was known to Larceny's compiler.  (These data
understate the percentage of known calls because they don't include
calls that were inlined by the compiler, and inlined calls often
account for a large fraction of the known calls.)

    	    	    R5RS    R6RS
    conform          30      23
    dynamic          37      69
    earley           90      91
    graphs           44      65
    lattice          21      32
    matrix           57      65
    maze             51      88
    mazefun           3      92
    mbrot            97     100
    nboyer           94       0
    nqueens          93      96
    nucleic          50      96
    paraffins       100     100
    peval            64      35
    primes           58     100
    ray              42      99
    scheme           22      23
    simplex          61      99
    slatex           55      63

Look at the line for nboyer.  With the special-purpose flow analysis,
well over 90% of the closed calls would have been to known procedures.
Without that flow analysis, virtually all closed calls are to unknown
code.  (This effect is also visible, but less dramatic, for the conform
and peval benchmarks.)  Some of the benchmarks, such as graphs and
lattice, make such extremely heavy use of higher-order procedures that
even the special-purpose R6RS flow analysis would be fairly ineffective.
In most cases, however, the R6RS percentages that are below 90% result
from Larceny's omission of that special-purpose flow analysis.

> I'm still confused about your overall point. Is it that the combination
> of the static techniques and dynamic techniques make FP the winner?

This line of discussion started when Matthias asked:

    How does the dynamic dispatch of inheritance differ from
    the 'random' jumps induced by calls to first-class
    functions in FPLs?

I said it's a matter of degree.  My point is (1) Matthias's "'random'
jumps" aren't as harmful to static analysis as he and the OO advocates
think, and (2) the dynamic dispatch of OO languages is (in practice) less
amenable to static analysis, and is therefore optimized by dynamic means
such as method caches and JIT compilers that can see the entire class
graph (and are prepared to recompile if that class graph changes at run
time).

Will




More information about the PRL mailing list