The other day, there was some discussion regarding object-equality from loaded fasls. I'm going to leave that discussion out of the mail below: the mail below is about efficiency of what we do today.
As described by Alessio, it looks like our loading process profiles are dominated by reader functions. So, I've taken a look at what it actually is that we serialize. I found that many things we serialize today - which need to be restored by the reader - can be serialized without requiring the reader to restore it: lists of symbols and lists.
That's where I decided to take a look at today's serialization mechanism. Roughly speaking, those are the functions in compiler-pass2.lisp with a function name starting with DECLARE-*; the namespace seems to contain functions for externalizing objects as well as for caching constant values.
On trunk, I'm working to: * separate the caching from the externalizing name-spaces * separate serialization and restoring functionalities in different functions (they were conflated in a single function for each type of object) * define serialization functions which allow recursive calling patterns for nested serialization of objects (to be restored without requiring the reader)
For each of these bullets, I'm making good progress; the second bullet is done, although not all serialization functions have been moved over to that namespace and approach yet. The last bullet is nearly done.
When each of the above is done, we will have all the building blocks required for quick elimination of the reader in a number of obvious cases - such as function argument lists.
Hope you find this update useful.
Bye,
Erik.
A follow-up on my progress this week:
As described by Alessio, it looks like our loading process profiles are dominated by reader functions. So, I've taken a look at what it actually is that we serialize. I found that many things we serialize today - which need to be restored by the reader - can be serialized without requiring the reader to restore it: lists of symbols and lists.
Except for DECLARE-* functions related to function references, I have changed the externalization code to go through a single function: EMIT-LOAD-EXTERNALIZED-OBJECT. This function externalizes the object (if that didn't already happen) and emits code to load a reference to the restored object. The actual serialization doesn't differ much from the original. The difference is in the boiler plate that was in each of the DECLARE-* functions, which is no longer part of the serialization functions. I use a dispatch table to find the serialization function belonging to the object to be externalized.
That's where I decided to take a look at today's serialization mechanism. Roughly speaking, those are the functions in compiler-pass2.lisp with a function name starting with DECLARE-*; the namespace seems to contain functions for externalizing objects as well as for caching constant values.
The caching / pre-evaluation is still in the DECLARE-* namespace; nothing has changed there, not even the boiler plate :-)
On trunk, I'm working to: * separate the caching from the externalizing name-spaces * separate serialization and restoring functionalities in different functions (they were conflated in a single function for each type of object) * define serialization functions which allow recursive calling patterns for nested serialization of objects (to be restored without requiring the reader)
These actions are mostly completed. Enough for me to try the effect of serializing lists differently. We have lots of lists with symbols in them. These lists don't need to be read, but instead can be directly constructed using "new Cons(new Fixnum(1), new Cons(..., NIL));"
I created code yesterday which does exactly that. Unfortunately, there was no measurable impact on our boot time.
So, the conclusion must be that our fasl reader is great, to the extent that it allows human-readable fasls, but it brings us the negative side effect that we start up too slow to be useable on - for example - Google App Engine.
Any ideas on improving our FASL format?
Ideas I've had myself:
* Reduce the length of the names of the functions ABCL uses to create fasls * Embed documentation strings in CLS files instead of having them in the FASL * <Other things which reduce the size of a fasl>
Bye,
Erik.
On Fri, May 21, 2010 at 9:39 AM, Erik Huelsmann ehuels@gmail.com wrote:
A follow-up on my progress this week:
As described by Alessio, it looks like our loading process profiles are dominated by reader functions. So, I've taken a look at what it actually is that we serialize. I found that many things we serialize today - which need to be restored by the reader - can be serialized without requiring the reader to restore it: lists of symbols and lists.
Except for DECLARE-* functions related to function references, I have changed the externalization code to go through a single function: EMIT-LOAD-EXTERNALIZED-OBJECT. This function externalizes the object (if that didn't already happen) and emits code to load a reference to the restored object. The actual serialization doesn't differ much from the original. The difference is in the boiler plate that was in each of the DECLARE-* functions, which is no longer part of the serialization functions. I use a dispatch table to find the serialization function belonging to the object to be externalized.
That's where I decided to take a look at today's serialization mechanism. Roughly speaking, those are the functions in compiler-pass2.lisp with a function name starting with DECLARE-*; the namespace seems to contain functions for externalizing objects as well as for caching constant values.
The caching / pre-evaluation is still in the DECLARE-* namespace; nothing has changed there, not even the boiler plate :-)
On trunk, I'm working to: * separate the caching from the externalizing name-spaces * separate serialization and restoring functionalities in different functions (they were conflated in a single function for each type of object) * define serialization functions which allow recursive calling patterns for nested serialization of objects (to be restored without requiring the reader)
These actions are mostly completed. Enough for me to try the effect of serializing lists differently. We have lots of lists with symbols in them. These lists don't need to be read, but instead can be directly constructed using "new Cons(new Fixnum(1), new Cons(..., NIL));"
I created code yesterday which does exactly that. Unfortunately, there was no measurable impact on our boot time.
So, the conclusion must be that our fasl reader is great, to the extent that it allows human-readable fasls, but it brings us the negative side effect that we start up too slow to be useable on - for example - Google App Engine.
Any ideas on improving our FASL format?
Ideas I've had myself:
* Reduce the length of the names of the functions ABCL uses to create fasls * Embed documentation strings in CLS files instead of having them in the FASL * <Other things which reduce the size of a fasl>
Can we assume that the textual part of a FASL is ASCII text and thus avoid UTF-8 conversions? It seems that it took a lot of time from my profiling.
Alessio
On Fri, May 21, 2010 at 5:22 AM, Alessio Stalla alessiostalla@gmail.com wrote:
On Fri, May 21, 2010 at 9:39 AM, Erik Huelsmann ehuels@gmail.com wrote:
A follow-up on my progress this week:
As described by Alessio, it looks like our loading process profiles are dominated by reader functions. So, I've taken a look at what it actually is that we serialize. I found that many things we serialize today - which need to be restored by the reader - can be serialized without requiring the reader to restore it: lists of symbols and lists.
Except for DECLARE-* functions related to function references, I have changed the externalization code to go through a single function: EMIT-LOAD-EXTERNALIZED-OBJECT. This function externalizes the object (if that didn't already happen) and emits code to load a reference to the restored object. The actual serialization doesn't differ much from the original. The difference is in the boiler plate that was in each of the DECLARE-* functions, which is no longer part of the serialization functions. I use a dispatch table to find the serialization function belonging to the object to be externalized.
That's where I decided to take a look at today's serialization mechanism. Roughly speaking, those are the functions in compiler-pass2.lisp with a function name starting with DECLARE-*; the namespace seems to contain functions for externalizing objects as well as for caching constant values.
The caching / pre-evaluation is still in the DECLARE-* namespace; nothing has changed there, not even the boiler plate :-)
On trunk, I'm working to: * separate the caching from the externalizing name-spaces * separate serialization and restoring functionalities in different functions (they were conflated in a single function for each type of object) * define serialization functions which allow recursive calling patterns for nested serialization of objects (to be restored without requiring the reader)
These actions are mostly completed. Enough for me to try the effect of serializing lists differently. We have lots of lists with symbols in them. These lists don't need to be read, but instead can be directly constructed using "new Cons(new Fixnum(1), new Cons(..., NIL));"
I created code yesterday which does exactly that. Unfortunately, there was no measurable impact on our boot time.
So, the conclusion must be that our fasl reader is great, to the extent that it allows human-readable fasls, but it brings us the negative side effect that we start up too slow to be useable on - for example - Google App Engine.
Any ideas on improving our FASL format?
Ideas I've had myself:
* Reduce the length of the names of the functions ABCL uses to create fasls * Embed documentation strings in CLS files instead of having them in the FASL * <Other things which reduce the size of a fasl>
Can we assume that the textual part of a FASL is ASCII text and thus avoid UTF-8 conversions? It seems that it took a lot of time from my profiling.
Would that preclude having unicode string constants?
Alessio
armedbear-devel mailing list armedbear-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/armedbear-devel
On Fri, May 21, 2010 at 11:35 AM, Alan Ruttenberg alanruttenberg@gmail.com wrote:
On Fri, May 21, 2010 at 5:22 AM, Alessio Stalla alessiostalla@gmail.com wrote:
Can we assume that the textual part of a FASL is ASCII text and thus avoid UTF-8 conversions? It seems that it took a lot of time from my profiling.
Would that preclude having unicode string constants?
We could encode Unicode strings in ASCII, escaping non-ASCII characters some way. What could be more problematic is symbols with unicode characters in them. We could arrange that |foo| performs the same type of escaping that "foo" does (in FASLs only).
Alessio
On 21 May 2010 12:42, Alessio Stalla alessiostalla@gmail.com wrote:
Would that preclude having unicode string constants?
We could encode Unicode strings in ASCII, escaping non-ASCII characters some way. What could be more problematic is symbols with
How's that any faster than doing the utf-8 conversion as we do now? The "escaping non-ASCII characters" thingy has a name, it's called.. *drumroll*.. utf-8. :)
On Fri, May 21, 2010 at 12:17 PM, Ville Voutilainen ville.voutilainen@gmail.com wrote:
On 21 May 2010 12:42, Alessio Stalla alessiostalla@gmail.com wrote:
Would that preclude having unicode string constants?
We could encode Unicode strings in ASCII, escaping non-ASCII characters some way. What could be more problematic is symbols with
How's that any faster than doing the utf-8 conversion as we do now? The "escaping non-ASCII characters" thingy has a name, it's called.. *drumroll*.. utf-8. :)
Ok, but we could do it only for those strings that we know to contain non-ASCII characters, and not for the whole FASL.
On Fri, May 21, 2010 at 8:39 AM, Erik Huelsmann ehuels@gmail.com wrote:
So, the conclusion must be that our fasl reader is great, to the extent that it allows human-readable fasls, but it brings us the negative side effect that we start up too slow to be useable on - for example - Google App Engine.
Oh, really? Bugger. I was hoping to get to that (ABCL + GAE) later in the year, but I haven't had time to explore it much. Are there many other people interested in this use case? I'd be keen to hear how others have got on with this (i.e. is there anyone who hasn't given up 'cause it's too slow). How does ABCL compare with Clojure in this regard (speed of initial start-up)?
Thanks, and keep up all the great work,
John :^P -- john@synchromesh.com
Hi John,
On Fri, May 21, 2010 at 11:57 AM, John Pallister john@synchromesh.com wrote:
On Fri, May 21, 2010 at 8:39 AM, Erik Huelsmann ehuels@gmail.com wrote:
So, the conclusion must be that our fasl reader is great, to the extent that it allows human-readable fasls, but it brings us the negative side effect that we start up too slow to be useable on - for example - Google App Engine.
Oh, really? Bugger. I was hoping to get to that (ABCL + GAE) later in the year, but I haven't had time to explore it much. Are there many other people interested in this use case? I'd be keen to hear how others have got on with this (i.e. is there anyone who hasn't given up 'cause it's too slow). How does ABCL compare with Clojure in this regard (speed of initial start-up)?
We currently start up in 11 seconds "Google time" (this is not wall clock; wall clock may be much shorter). After initial startup, requests may take only miliseconds. In earlier posts about Clojure, I seem to remember it took them 5.5 secs.
BTW: our current 11 seconds used to be much more: before extensive optimization reseach half a year ago, it was 19 seconds. The mail I wrote is put in the terms it is in, mainly because of my own disappointment that I wasn't able to solve the bottleneck.
Thanks, and keep up all the great work,
Bye,
Erik.
armedbear-devel@common-lisp.net