E compilers / static analysis

Thomas Leonard <tal-v5nx5w6akNyLE8xUarVfuPLx9OUvmyODWmv/[email protected]>
Newsgroups gmane.comp.lang.e.general
Organization IT Innovation
Message-ID <[email protected]>
I've been continuing to investigate the performance issues with E, and
I've put some very experimental stuff on a new "static" branch:

http://gitorious.org/~tal-itinnov/repo-roscidus/it-innovation/commits/static

This is not ready for merging, but comments welcome.


I split EExpr.eval(scope) into two steps. EExpr.compile(scope)
transforms the E and returns a CompiledE Thunk, which holds the
transformed E and its scope. Calling the thunk runs the code. e.g.

? def kernelE := e`def double(x) { return 2 * x }`
# value: e`def double {
#            
#            method run(x) {
#                escape __return {
#                    __return.run(2.multiply(x))
#                    null
#                }
#            }
#        }`

? def compiled := kernelE.compile(safeScope)
# value: compiled-e`def double {
#            
#            method run(x) {
#                2.multiply(x)
#            }
#        }`

? def double := compiled()
# value: <double>

? double(4)
# value: 8

This makes it easy to see which optimisations E is actually doing, and
makes it easy to cache the results for speed.

Before, EExpr was doing its own caching (badly). Here's a test case:

def timeit(cb) {
	for x in 0..100 {
		cb()
	}
	def t1 := timer.now()
	for x in 0..10000 {
		cb()
	}
	def t2 := timer.now()
	return t2 - t1
}
def orig := e`require(true)`
for x in 1..4 {
	def ti := timeit(fn { orig.eval(safeScope) } )

	println(`Time: $ti ms`)
}

This takes around 10s using svn trunk's E (with the built-in caching):

Time: 11134 ms
Time: 10690 ms
Time: 10549 ms
Time: 10581 ms

Using the "static" branch's eval/1 (which is just the same but with the
caching *removed*):

Time: 730 ms
Time: 794 ms
Time: 367 ms
Time: 342 ms

And using compile/1 first and then doing eval on that:

Time: 299 ms
Time: 212 ms
Time: 106 ms
Time: 145 ms

I updated ImportLoader to cache CompiledE objects and evaluate them
again each time you import. This fixes the performance problem I
reported previously with <import>, in
http://www.eros-os.org/pipermail/e-lang/2010-February/013443.html

Importing the same file using svn's <import>:

Took: 15354 ms
Took: 15676 ms

Importing using my ELoader (svn trunk):

Took: 464 ms
Took: 495 ms

Using ELoader ("static" branch):

Took: 248 ms
Took: 212 ms

Using the new ImportLoader ("static" branch):

Took: 31 ms
Took: 29 ms


Those are the main changes that improve performance. The static branch
also has some other optimisations. These are sometimes OK in
micro-benchmarks but don't have much effect overall on my main code. I
guess there's some other performance-killer at work, but these might be
useful in the future:

- I pass Scope to BindFramesVisitor (not just ScopeLayout). A comment
said passing ScopeLayout only is to help compilers, but a compiler can't
do any useful optimisations without knowing what some of the values will
be.

- I turn references to final outer slots into LiteralExprs with the
value. e.g. "true", "false" and "null" no longer evaluate
"context.outers(i).get()" each time they're evaluated.

- A CallExpr with a receiver known at compile time turns into a
FastCallExpr with a shortened Script. This doesn't seem to help
performance at all, surprisingly, but it did find three bugs in my code
(untested error paths where I did "Ref.problem(...)" instead of
"Ref.broken(...)".

- SeqExprs have literals removed (except for the last one). If the
removed value isn't null, a warning is printed because code that has no
effect is usually a bug. Currently this won't find many bugs because we
don't expand many constants.

- CallExprs where the receiver is <type> and the value is known are
called at compile time. Guard.coerce(known) is also expanded. This
doesn't help much either, but I think it will be handy for inferring
types later.


-- 
Dr Thomas Leonard
IT Innovation Centre
2 Venture Road
Southampton
Hampshire SO16 7NP

Tel: +44 0 23 8076 0834
Fax: +44 0 23 8076 0833
mailto:tal-v5nx5w6akNyLE8xUarVfuPLx9OUvmyODWmv/[email protected]
http://www.it-innovation.soton.ac.uk
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.