emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Skipping unexec via a big .elc file


From: Stefan Monnier
Subject: Re: Skipping unexec via a big .elc file
Date: Tue, 25 Oct 2016 09:48:00 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2.50 (gnu/linux)

>>> Did you check whether actually byte compiling the written file made
>>> a difference?
>> dumped.elc has no code to compile.
> It has a lot of fset and setplist calls which can be compiled, especially if
> you reorder things such that they’re not mixed up with the defvar calls that
> don’t compile.

"A lot of" is relative: the time to read them compared to an equivalent
byte-code version should be negligeable, and their execution time should
be even more negligeable.

> The generated .elc output is about 25% larger.

That's not because of byte-compilation per-se.  It's because the
byte-compiler uses `print-circle' but only within each top-level entity,
so you lose sharing between functions and between variables.

IOW you can get the exact same 25% larger file by printing each
fset/defvar/setplist separately (instead of printing them as one big
`progn`).  And you can trick the byte-compiler to preserve this sharing
by replacing the leading `progn` (which the byte-compiler removes) into
a (let () ...), tho maybe you'll need to really add some dummy binding
in that `let` to make sure the byte-compiler doesn't end up removing it.

> I did some profiling.  Without byte compiling, it appears that around half
> of the CPU time used loading the file in my test is spent in
> Frassq(…,read_objects), called from substitute_object_recurse.

Ah, that's what it is.  Clearly we should be able to optimize most of
this away.

> For processing a file with this much sharing of objects, an assoc list with
> O(n) access time may not be the best choice.

Indeed.

> Whatever we replace it with, it appears we need to be able to look up
> cons cells in a collection by either element.

Ideally, we could get rid of substitute_object_in_subtree entirely.
E.g. the patch below skips it for the case of "#n=(...)", and by peeping
ahead to decide the type of placeholder we build, we should be able to
get rid of it in all cases.


        Stefan


diff --git a/src/lread.c b/src/lread.c
index 58d518c..a06a78f 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -2936,12 +2936,21 @@ read1 (Lisp_Object readcharfun, int *pch, bool 
first_in_list)
                      tem = read0 (readcharfun);
 
                      /* Now put it everywhere the placeholder was...  */
-                     substitute_object_in_subtree (tem, placeholder);
+                      if (CONSP (tem))
+                        {
+                          Fsetcar (placeholder, XCAR (tem));
+                          Fsetcdr (placeholder, XCDR (tem));
+                          return placeholder;
+                        }
+                      else
+                        {
+                         substitute_object_in_subtree (tem, placeholder);
 
-                     /* ...and #n# will use the real value from now on.  */
-                     Fsetcdr (cell, tem);
+                         /* ...and #n# will use the real value from now on.  */
+                         Fsetcdr (cell, tem);
 
-                     return tem;
+                         return tem;
+                        }
                    }
 
                  /* #n# returns a previously read object.  */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]