From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Andy Wingo Newsgroups: gmane.lisp.guile.devel Subject: Re: srfi-18 and the vm Date: Sun, 31 May 2009 15:30:50 +0200 Message-ID: References: <878wko16zz.fsf@arudy.ossau.uklinux.net> <87r5yfxysa.fsf@gnu.org> <87eiueegq3.fsf@gnu.org> <87tz386e2n.fsf@arudy.ossau.uklinux.net> <87d49qrxzx.fsf@arudy.ossau.uklinux.net> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1243777276 25325 80.91.229.12 (31 May 2009 13:41:16 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 31 May 2009 13:41:16 +0000 (UTC) Cc: Ludovic =?utf-8?Q?Court=C3=A8s?= , guile-devel@gnu.org To: Neil Jerram Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Sun May 31 15:41:13 2009 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1MAlHK-000308-CC for guile-devel@m.gmane.org; Sun, 31 May 2009 15:41:13 +0200 Original-Received: from localhost ([127.0.0.1]:54977 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MAlHD-0006LJ-S2 for guile-devel@m.gmane.org; Sun, 31 May 2009 09:40:39 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MAlCo-00052h-LS for guile-devel@gnu.org; Sun, 31 May 2009 09:36:06 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MAlCk-00050o-V9 for guile-devel@gnu.org; Sun, 31 May 2009 09:36:06 -0400 Original-Received: from [199.232.76.173] (port=48230 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MAlCk-00050a-HN for guile-devel@gnu.org; Sun, 31 May 2009 09:36:02 -0400 Original-Received: from a-sasl-fastnet.sasl.smtp.pobox.com ([207.106.133.19]:62219 helo=sasl.smtp.pobox.com) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MAlCf-0000os-47; Sun, 31 May 2009 09:35:57 -0400 Original-Received: from localhost.localdomain (unknown [127.0.0.1]) by a-sasl-fastnet.sasl.smtp.pobox.com (Postfix) with ESMTP id 7B9A3B741E; Sun, 31 May 2009 09:35:54 -0400 (EDT) Original-Received: from unquote (unknown [82.123.44.81]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by a-sasl-fastnet.sasl.smtp.pobox.com (Postfix) with ESMTPSA id DF8CAB741D; Sun, 31 May 2009 09:35:50 -0400 (EDT) In-Reply-To: <87d49qrxzx.fsf@arudy.ossau.uklinux.net> (Neil Jerram's message of "Sun, 31 May 2009 00:07:14 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.92 (gnu/linux) X-Pobox-Relay-ID: F702B590-4DE7-11DE-BB80-97731A10BFE7-02397024!a-sasl-fastnet.pobox.com X-detected-operating-system: by monty-python.gnu.org: Solaris 10 (beta) X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:8580 Archived-At: Ni Neil, On Sun 31 May 2009 01:07, Neil Jerram writes: > Andy Wingo writes: > >> In the short term (within the next year or so), I would imagine that >> ceval/deval would be faster than an eval written in Scheme -- though I >> do not know. > > I wasn't thinking of an eval written in Scheme. I was assuming the > other option that you mention below, i.e. eval becomes compile on the > fly followed by VM execution. Incidentally, the REPL compiles by default now, and has been doing so since VM was merged to master. But expressions at the REPL are less code than are full libraries. >> But compilation does take some time. > > I guess this is the key point. Even when the compiler has itself been > compiled? Much less time in that case, of course. It's the difference between the load-compiled case and the ceval case below. I think my understanding of the performance equation goes like this: 1.8 ceval time = (read time) + ((% of executed code) * (memoization time)) + (ceval runtime) 1.9 ceval time = (psyntax expansion time) + (1.8 ceval time) 1.9 compile time = (read time) + (psyntax expansion time) + (compile time) 1.9 load-compiled time = (VM runtime) 1.9 compile-and-load time = (1.9 compile time) + (1.9 load-compiled time) Let's say that (VM runtime) == 1/4 * (ceval runtime). Then: (1.9 compile-and-load time) < (1.9 ceval time) if (compile time) < (% of executed code) * (memoization time) + 3/4 * (ceval runtime) Compile-time and memozation time depend linearly on the "complexity" of the code, as you say. And my suspicion is that memoization doesn't actually take very much time, compared to expansion. So a simpler version would be that we win when: (compile time) < 3/4 * (ceval runtime) Of course there is probably a lower bound to all of this, that we don't care about differences under 50 ms or so, when operating on non-compiled code. So if we keep compile time always under 40 ms or so, we're good. Now how do we stack up, then? Well: scheme@(guile-user)> (use-modules (ice-9 time) (system base compile)) scheme@(guile-user)> (time (compile-file "module/language/tree-il.scm")) clock utime stime cutime cstime gctime 1.17 1.03 0.14 0.00 0.00 0.30 $1 = "module/language/tree-il.go" scheme@(guile-user)> (time (compile-file "module/language/tree-il.scm")) clock utime stime cutime cstime gctime 1.06 0.91 0.14 0.00 0.00 0.16 $2 = "module/language/tree-il.go" scheme@(guile-user)> (time (compile-file "module/language/tree-il/spec.scm")) clock utime stime cutime cstime gctime 0.03 0.03 0.00 0.00 0.00 0.01 $3 = "module/language/tree-il/spec.go" scheme@(guile-user)> (time (compile-file "module/language/tree-il/spec.scm")) clock utime stime cutime cstime gctime 0.02 0.02 0.00 0.00 0.00 0.00 $4 = "module/language/tree-il/spec.go" scheme@(guile-user)> (time (compile-file "module/language/assembly/disassemble.scm")) clock utime stime cutime cstime gctime 0.25 0.20 0.05 0.00 0.00 0.04 $5 = "module/language/assembly/disassemble.go" scheme@(guile-user)> (time (compile-file "module/language/assembly/disassemble.scm")) clock utime stime cutime cstime gctime 0.26 0.23 0.03 0.00 0.00 0.03 $6 = "module/language/assembly/disassemble.go" scheme@(guile-user)> (time (compile-file "module/language/tree-il/compile-glil.scm")) clock utime stime cutime cstime gctime 0.53 0.44 0.09 0.00 0.00 0.10 $7 = "module/language/tree-il/compile-glil.go" scheme@(guile-user)> wingo@unquote:~/src/guile$ ls -l module/language/tree-il.scm module/language/tree-il/spec.scm module/language/assembly/disassemble.scm module/language/tree-il/compile-glil.scm -rw-rw-r-- 1 wingo wingo 6467 2009-05-29 15:39 module/language/assembly/disassemble.scm -rw-rw-r-- 1 wingo wingo 16377 2009-05-29 15:39 module/language/tree-il/compile-glil.scm -rw-rw-r-- 1 wingo wingo 11734 2009-05-29 15:39 module/language/tree-il.scm -rw-rw-r-- 1 wingo wingo 1390 2009-05-29 15:39 module/language/tree-il/spec.scm This is on my laptop, with the ondemand cpu speed thingie. It seems expansion itself is taking a bit of this time: scheme@(guile-user)> ,m language tree-il scheme@(language tree-il)> (use-modules (ice-9 time)) scheme@(language tree-il)> (time (with-input-from-file "module/language/tree-il.scm" (lambda () (let lp ((x (read))) (if (not (eof-object? x)) (begin (sc-expand x) (lp (read)))))))) clock utime stime cutime cstime gctime 0.44 0.44 0.01 0.00 0.00 0.12 scheme@(language tree-il)> ,m language assembly disassemble scheme@(language assembly disassemble)> (use-modules (ice-9 time)) scheme@(language assembly disassemble)> (time (with-input-from-file "module/language/assembly/disassemble.scm" (lambda () (let lp ((x (read))) (if (not (eof-object? x)) (begin (sc-expand x) (lp (read)))))))) clock utime stime cutime cstime gctime 0.10 0.09 0.00 0.00 0.00 0.02 Indeed, the expander seems to take most of the time when loading (ice-9 match). I've run all of these in fresh Guiles so one expansion doesn't have the cost of creating a module: scheme@(guile-user)> (time (load "module/ice-9/match.scm")) clock utime stime cutime cstime gctime 1.02 0.98 0.01 0.00 0.00 0.26 scheme@(guile-user)> (time (with-input-from-file "module/ice-9/match.scm" (lambda () (let lp ((x (read))) (if (not (eof-object? x)) (begin (sc-expand x) (lp (read)))))))) clock utime stime cutime cstime gctime 0.97 0.95 0.01 0.00 0.00 0.25 scheme@(guile-user)> (time (compile-file "module/ice-9/match.scm")) clock utime stime cutime cstime gctime 3.40 3.01 0.39 0.00 0.00 0.79 scheme@(guile-user)> (time (load-compiled "module/ice-9/match.go")) clock utime stime cutime cstime gctime 0.00 0.00 0.00 0.00 0.00 0.00 Conclusions: * The 1.8 memoizer was a big win, because the % of executed code could be very small -- loading (ice-9 match) never had to traverse all of those nodes. OTOH, the memoizer seems to be irrelevant with psyntax run on all of the source code, because expansion has to traverse all nodes, so you don't get the savings. * Currently, expansion seems to take between 30% and 40% of compile time. (I imagine we can reduce this absolute time by a factor of 2 or so with some more optimized compilation of multiple-values cases, which should be easy, and the addition of an inliner, which will be a bit of work.) * Of course, once code is compiled, loading it is *very* fast, and I believe it to run at about 3 or 4 times the speed, though I have not shown that here. I guess the big question is, what will the impact be on our users? I suppose we can divide those users into three categories: * People who write short scripts in Guile, using standard libraries. These people are likely to see no change, speed-wise. Guile might start up faster and the libraries might load faster, but then again, perhaps their scripts take 300 ms to expand, which makes that speed gain moot. We could offer them compilation of their scripts, in the compile-and-load sense, which could help if their scripts take a long time to run. * People who write big programs in Guile. These people will likely be irked by the initial slowness with which their programs run, but will also likely be receptive to compiling their own programs and libraries, which will make them much faster. It is likely that these people have butted up against Guile's speed limitations. * People who use programs written in Guile, but that don't know anything about compiling or maybe even Scheme. This people are most likely to be adversely affected by all of this. Their programs start up more slowly, and for no obvious reason. I get the feeling that we really should compile libraries by default. We can put the results in ~/.guile-something if we don't have permissions to put them alongside the .scm files -- that allows for sharing in multiuser installations, but doesn't require it. This way we offer more advantages to our users. But I don't know. What do yall think? >> Incidentally, ikarus had a similar discussion recently: >> >> http://thread.gmane.org/gmane.lisp.scheme.ikarus.user/723 >> http://thread.gmane.org/gmane.lisp.scheme.ikarus.user/745 > > I see; good references - there's no need for us to have the same > conversation again! I think I agree with Aziz's conclusion - > i.e. "auto-caching" should be disabled by default. I think I might have convinced myself otherwise. > The thread suggested to me that Ikarus has to compile the code that it > reads before it can execute it; i.e. that it doesn't retain an > interpretation option. Is that correct? Yes. > If so, Guile might reasonably make slightly different decisions - e.g. > to interpret a module when using it for the first time, and also to > start compiling it on another thread, with the module's procedures > being replaced one-by-one by VM programs as the compilation > progresses. Interesting idea :) Cheers, Andy -- http://wingolog.org/