unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
@ 2013-09-06 20:59 Dmitry Gutov
  2013-09-06 23:44 ` Xue Fuqiao
                   ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: Dmitry Gutov @ 2013-09-06 20:59 UTC (permalink / raw)
  To: 15294

If I append -*- lexical-binding: t -*- to the first line of js2-mode.el
and eval the buffer, parsing a file takes several (3 to 4) times longer.

To measure:

0. Install js2-mode, e.g. from GNU ELPA.
1. Save
http://mootools.net/download/get/mootools-core-1.4.5-full-nocompat.js to
some local directory, open it in Emacs.
2. If it opens in some other mode than js2-mode, M-x js2-mode.
3. Don't touch the keys, wait until the file is parsed (the parsing gets
interrupted and rescheduled on input). When redisplay works again, we
can re-parse the file again and measure the time it takes.
4. eval-expression (js2-time (js2-reparse t)), wait until the message
area displays the amount of seconds the process took.

To measure the performance in interpreted mode, open js2-mode.el, M-x
eval-buffer and go through the above scenario (1-4).
To measure the performance in compiled mode, M-x byte-compile-file, then
(load "js2-mode.elc"), then go through the scenario.

My measurements:

lexical-binding |       no |      yes |
Interpreted     |    1 sec | 4.26 sec |
Compiled        | 0.63 sec | 1.76 sec |

--
In GNU Emacs 24.3.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 3.6.4)
 of 2013-09-06 on axl
Bzr revision: 114159 dmantipov@yandex.ru-20130906164012-6j0s6otwkypj9s1z
Windowing system distributor `The X.Org Foundation', version 11.0.11303000
System Description:	Ubuntu 13.04





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-06 20:59 bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode Dmitry Gutov
@ 2013-09-06 23:44 ` Xue Fuqiao
  2013-09-07  3:15   ` Stefan Monnier
  2013-09-08 22:32 ` Stefan Monnier
  2013-09-10  2:04 ` Stefan Monnier
  2 siblings, 1 reply; 25+ messages in thread
From: Xue Fuqiao @ 2013-09-06 23:44 UTC (permalink / raw)
  To: 15294-done

Fixed in revision 114156.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-06 23:44 ` Xue Fuqiao
@ 2013-09-07  3:15   ` Stefan Monnier
  0 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-07  3:15 UTC (permalink / raw)
  To: 15294; +Cc: xfq.free, dgutov

reopen 15294 
thanks

> Fixed in revision 114156.

No, 114156 fixes another problem (which affected both lexical and
dynamic binding code).


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-06 20:59 bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode Dmitry Gutov
  2013-09-06 23:44 ` Xue Fuqiao
@ 2013-09-08 22:32 ` Stefan Monnier
  2013-09-10  2:04 ` Stefan Monnier
  2 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-08 22:32 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

A first likely candidate is the bunch of `catch/throw' in js2-get-token,
since catch, unwind-protect and condition-case are all implemented in
the bytecode interpreter in ways which don't work well for
lexical scoping.


        Stefan "Just reporting on his little progress"





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-06 20:59 bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode Dmitry Gutov
  2013-09-06 23:44 ` Xue Fuqiao
  2013-09-08 22:32 ` Stefan Monnier
@ 2013-09-10  2:04 ` Stefan Monnier
  2013-09-13  3:40   ` Stefan Monnier
                     ` (2 more replies)
  2 siblings, 3 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-10  2:04 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

> If I append -*- lexical-binding: t -*- to the first line of js2-mode.el
> and eval the buffer, parsing a file takes several (3 to 4) times longer.

[ I'm disregarding the interpreted time for now, since the issues are
  likely to be different. ]

In the compiled case, loading js2-mode-lexical.elc and then redefining
`js2-get-token' to the value it has in js2-mode-dynamic.elc brings me
back the same speed as with js2-mode-dynamic.elc.
IOW the slowdown is in js2-get-token.

If it indeed comes from the handling of catch/throw, then there are two
ways to fix it:
- provide a new byte-code for catch which does not require wrapping the
  body in a closure.  This should not be terribly difficult and would
  benefit all existing code, but it does require changes to the way
  catch is implemented.
- improve the byte-compiler so it can compile away cl-block/cl-return.
  This should not require new byte-codes, but requires delving "deepish"
  into the byte-compiler.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-10  2:04 ` Stefan Monnier
@ 2013-09-13  3:40   ` Stefan Monnier
  2013-09-13  3:59     ` Drew Adams
  2013-09-14  4:20     ` Dmitry Gutov
  2013-09-15  0:24   ` Dmitry Gutov
  2013-09-18 23:48   ` Stefan Monnier
  2 siblings, 2 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-13  3:40 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

> In the compiled case, loading js2-mode-lexical.elc and then redefining
> `js2-get-token' to the value it has in js2-mode-dynamic.elc brings me
> back the same speed as with js2-mode-dynamic.elc.
> IOW the slowdown is in js2-get-token.

It seems the slowdown is indeed linked to the way `catch' is handled
(indeed, this non-idiomatic ELisp code ends up byte-compiled in a really
poor way).

The trivial patch below brings the time down from 5s to 2.6s (as
compared to 2.1s for the dynamic-binding version).


        Stefan


diff --git a/packages/js2-mode/js2-mode.el b/packages/js2-mode/js2-mode.el
index 3568f18..1d76469 100644
--- a/packages/js2-mode/js2-mode.el
+++ b/packages/js2-mode/js2-mode.el
@@ -5310,10 +5311,10 @@ corresponding number.  Otherwise return -1."
 
 (defun js2-get-token ()
   "Return next JavaScript token, an int such as js2-RETURN."
-  (let (c c1 identifier-start is-unicode-escape-start
-        contains-escape escape-val str result base
-        is-integer quote-char val look-for-slash continue)
-    (catch 'return
+  (catch 'return
+    (let (c c1 identifier-start is-unicode-escape-start
+            contains-escape escape-val str result base
+            is-integer quote-char val look-for-slash continue)
       (while t
         ;; Eat whitespace, possibly sensitive to newlines.
         (setq continue t)





^ permalink raw reply related	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-13  3:40   ` Stefan Monnier
@ 2013-09-13  3:59     ` Drew Adams
  2013-09-13  4:37       ` Stefan Monnier
  2013-09-14  4:20     ` Dmitry Gutov
  1 sibling, 1 reply; 25+ messages in thread
From: Drew Adams @ 2013-09-13  3:59 UTC (permalink / raw)
  To: Stefan Monnier, Dmitry Gutov; +Cc: 15294

> It seems the slowdown is indeed linked to the way `catch' is handled
> (indeed, this non-idiomatic ELisp code ends up byte-compiled in a really
> poor way). The trivial patch below brings the time down from 5s to 2.6s
> (as compared to 2.1s for the dynamic-binding version).
>
> -  (let (c c1 identifier-start is-unicode-escape-start
> -        contains-escape escape-val str result base
> -        is-integer quote-char val look-for-slash continue)
> -    (catch 'return
> +  (catch 'return
> +    (let (c c1 identifier-start is-unicode-escape-start
> +            contains-escape escape-val str result base
> +            is-integer quote-char val look-for-slash continue)

Not really following this thread, but this caught my eye.  Is this
something that should be mentioned as a guideline in the manual?

Or is the byte compiler likely to be improved in this regard, so users
need not be aware of it and take measures manually?





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-13  3:59     ` Drew Adams
@ 2013-09-13  4:37       ` Stefan Monnier
  2013-09-13  5:45         ` Drew Adams
  0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2013-09-13  4:37 UTC (permalink / raw)
  To: Drew Adams; +Cc: 15294, Dmitry Gutov

> Or is the byte compiler likely to be improved in this regard, so users
> need not be aware of it and take measures manually?

As indicated in the FIXMEs I added in src/bytecode.c at the time, the
current byte codes for unwind-protect, condition-case, and catch are
very inefficient for lexical-binding code.

I do hope to fix those issues by introducing other byte-codes which will
let us generate significantly more efficient code for those constructs,
but in 24.1, the priority was to get lexical-binding to work correctly,
performance being a secondary concern (tho for most idiomatic Elisp
code, the performance tends to be competitive).

What people should know is that

   (let (x y z)
     ...(setq x ...)
     ...(setq z ...)
     ...(setq y ...)

is often a bad idea in Elisp, and even more so in lexical-binding code
(in some cases, if a variable is immutable it can be handled
significantly more efficiently, so the mere existence of a single `setq'
on a variable can sometimes slow other chunks of code: in many cases
`let' is cheaper than `setq').


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-13  4:37       ` Stefan Monnier
@ 2013-09-13  5:45         ` Drew Adams
  2013-09-13 13:01           ` Stefan Monnier
  0 siblings, 1 reply; 25+ messages in thread
From: Drew Adams @ 2013-09-13  5:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294, Dmitry Gutov

> > Or is the byte compiler likely to be improved in this regard, so users
> > need not be aware of it and take measures manually?
> 
> As indicated in the FIXMEs I added in src/bytecode.c at the time, the
> current byte codes for unwind-protect, condition-case, and catch are
> very inefficient for lexical-binding code.
> 
> I do hope to fix those issues by introducing other byte-codes which will
> let us generate significantly more efficient code for those constructs,
> but in 24.1, the priority was to get lexical-binding to work correctly,
> performance being a secondary concern (tho for most idiomatic Elisp
> code, the performance tends to be competitive).
> 
> What people should know is that
> 
>    (let (x y z)
>      ...(setq x ...)
>      ...(setq z ...)
>      ...(setq y ...)
> 
> is often a bad idea in Elisp, and even more so in lexical-binding code
> (in some cases, if a variable is immutable it can be handled
> significantly more efficiently, so the mere existence of a single `setq'
> on a variable can sometimes slow other chunks of code: in many cases
> `let' is cheaper than `setq').

Thank you for both answers.  Will the second apply even after making the
byte-compiler improvements described for the first?  (I'm guessing yes.)
If so, you might want to mention this guideline in the manual.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-13  5:45         ` Drew Adams
@ 2013-09-13 13:01           ` Stefan Monnier
  0 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-13 13:01 UTC (permalink / raw)
  To: Drew Adams; +Cc: 15294, Dmitry Gutov

>> What people should know is that
>> 
>> (let (x y z)
>> ...(setq x ...)
>> ...(setq z ...)
>> ...(setq y ...)
>> 
>> is often a bad idea in Elisp, and even more so in lexical-binding code
>> (in some cases, if a variable is immutable it can be handled
>> significantly more efficiently, so the mere existence of a single `setq'
>> on a variable can sometimes slow other chunks of code: in many cases
>> `let' is cheaper than `setq').

> Thank you for both answers.  Will the second apply even after making the
> byte-compiler improvements described for the first?  (I'm guessing yes.)
> If so, you might want to mention this guideline in the manual.

Yes.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-13  3:40   ` Stefan Monnier
  2013-09-13  3:59     ` Drew Adams
@ 2013-09-14  4:20     ` Dmitry Gutov
  2013-09-14 14:27       ` Stefan Monnier
  1 sibling, 1 reply; 25+ messages in thread
From: Dmitry Gutov @ 2013-09-14  4:20 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

On 13.09.2013 06:40, Stefan Monnier wrote:
> It seems the slowdown is indeed linked to the way `catch' is handled
> (indeed, this non-idiomatic ELisp code ends up byte-compiled in a really
> poor way).

What's non-idiomatic about this use of `catch'?

> The trivial patch below brings the time down from 5s to 2.6s (as
> compared to 2.1s for the dynamic-binding version).

Indeed, it does, in the compiled mode (but please don't install it yet, 
because it'll complicate merging the `arrow-functions' branch(*)). It 
does not make much of a difference in the interpreted mode.

Now that we have eager macro-expansion, I was rather happy that 
interpreted js2-mode performance is only like 2x worse than when compiled.

But 2.6 vs 2.1, it still a noticeable regression. Do you suppose the 
usage of `setq' is the main contributor?

Speaking of byte-code changes, that seems like a fine idea, but ideally 
the code should work similarly well on Emacs 24.1-24.3. Or we can just 
hold off on making js2-mode switch to lexical-binding until [long] after 
24.4 is out.

(*) Would you take a look at it, too? It has quite a few changes in 
`js2-get-token' and related functions. They also make performing the 
same change as in your patch more difficult, since I'm actually using 
the value returned by `catch' before returning from the function.

On 13.09.2013 07:37, Stefan Monnier wrote:
 > the mere existence of a single `setq'
 > on a variable can sometimes slow other chunks of code: in many cases
 > `let' is cheaper than `setq').

I see. Does this also extend to `setf' and its defstruct-related 
functionality? It's all over the js2-mode codebase.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-14  4:20     ` Dmitry Gutov
@ 2013-09-14 14:27       ` Stefan Monnier
  2013-09-15  0:11         ` Dmitry Gutov
  0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2013-09-14 14:27 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

>> It seems the slowdown is indeed linked to the way `catch' is handled
>> (indeed, this non-idiomatic ELisp code ends up byte-compiled in a really
>> poor way).
> What's non-idiomatic about this use of `catch'?

The non-idiomatic part is the "one big let on top, with lots of setq
inside".  It's clearly C code in Elisp syntax.

> It does not make much of a difference in the interpreted mode.

The interpreted performance is affected by completely different factors.
My guess for the interpreted case is that there are simply "too many"
local variables: the environment is represented by a simple alist, so
variable lookup time is proportional to the number of local variables.
That fine when there are 5 local variables, but is inefficient when you
have 100 (better would be a balanced tree or maybe a hash table).
This said, I'm not terribly concerned about it: if you need it to go
fast, you should byte-compile the code.  And I hope we will be able to
get rid of the interpreter in some distantish future.

> Now that we have eager macro-expansion, I was rather happy that interpreted
> js2-mode performance is only like 2x worse than when compiled.

Eager macro-expansion indeed speeds up interpreted code, even though the
intention was rather to get one-step closer to the elimination
of interpretation.

> But 2.6 vs 2.1, it still a noticeable regression. Do you suppose the usage
> of `setq' is the main contributor?

The problem goes as follows:

1- Because of how the `catch' byte-code works, for a (catch TAG BODY)
   where BODY refers to some surrounding lexical variables LVARS, the
   byte-compiler needs to turn the code into something similar to:

   (let ((body-fun (make-closure LVARS () BODY)))
     (catch TAG (funcall body-fun)))

2- When a lexical variable is both
   a- caught in a closure
   b- not immutable
   the byte-compiler can't store this variable in the bytecode stack
   (since the closure can't refer to the bytecode stack directly, but
   instead stores *copies* of the elements it needs), so it needs to
   change code like

   (let ((lvar VAL1))
     ...
     (setq lvar VAL2)
     ...(lambda () ..lvar..)...)

   into
     
   (let ((lvar (list VAL1)))
     ...
     (setcar lvar VAL2)
     ...(lambda () ..(car lvar)..)...)

So if you look at js2-get-token, you'll see that the code does not
directly use any closure, but the use of `catch' ends up putting most of
the body into various closures.  And since all variables are declared
outside of the catch but used inside, and they're all modified by
`setq', they all end up converted as above, so that every use of such
a variable turns into "get the cons cell from the environment, then
apply car to it".

By moving the let inside the catch, some of those variables end up not
being caught by a closure any more, so they don't need to be converted
to cons cells, hence the reduction from 5s down to 2.6s.

> (*) Would you take a look at it, too? It has quite a few changes in
> js2-get-token' and related functions.

> They also make performing the same change as in your patch more
> difficult, since I'm actually using the value returned by `catch'
> before returning from the function.

That's not a problem.  The rule to follow is simply: sink the `let'
bindings closer to their use.  You don't need to `let' bind all those
vars together in one big `let': you can split this let into various
`let's which you can then move deeper into the code.  In some cases
you'll find that some of those vars don't even need to be `setq'd any
more.

Note that such a "scope-reduction" can also be done in C and in many
cases it's also a good idea to do it in C, tho the impact on performance
is much less significant because C doesn't have closures.

>> the mere existence of a single `setq' on a variable can sometimes
>> slow other chunks of code: in many cases `let' is cheaper than `setq').
> I see.  Does this also extend to `setf' and its defstruct-related
> functionality?

It has to do specifically with `setq' (i.e. modification of plain
variables): when `setf' expands to `setq', `setf' is impacted,
otherwise no.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-14 14:27       ` Stefan Monnier
@ 2013-09-15  0:11         ` Dmitry Gutov
  2013-09-15  5:04           ` Stefan Monnier
  2013-09-15 16:54           ` Richard Stallman
  0 siblings, 2 replies; 25+ messages in thread
From: Dmitry Gutov @ 2013-09-15  0:11 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

On 14.09.2013 17:27, Stefan Monnier wrote:
>>> It seems the slowdown is indeed linked to the way `catch' is handled
>>> (indeed, this non-idiomatic ELisp code ends up byte-compiled in a really
>>> poor way).
>> What's non-idiomatic about this use of `catch'?
>
> The non-idiomatic part is the "one big let on top, with lots of setq
> inside".  It's clearly C code in Elisp syntax.

Or rather Java code, considering its origins. In general, we have to 
stay close enough to the SpiderMonkey codebase to be able to port new 
syntax features easily.

You've explained how this is bad when combined with closures, but other 
than gotchas with `catch' (and `condition-case', I'm assuming), we don't 
have any higher-order functions in the parser. No lambda forms anywhere, 
at least.

Can the fact that `dotimes', `dolist' and `loop' are advised with 
`cl--wrap-in-nil-block', which expands into `catch' form, make much of a 
difference?

>> It does not make much of a difference in the interpreted mode.
>
> The interpreted performance is affected by completely different factors.
> My guess for the interpreted case is that there are simply "too many"
> local variables: the environment is represented by a simple alist, so
> variable lookup time is proportional to the number of local variables.
> That fine when there are 5 local variables, but is inefficient when you
> have 100 (better would be a balanced tree or maybe a hash table).

`js2-get-token' has 13 local variables (*). Which is, while not a 
little, far from 100. Most of the other functions have fewer than that.

Are you counting the global variables, too? The dynamic-binding 
interpreter has to work with them, too. How is it that much faster?

(*) According to Steve's notes, symbol lookup in alists is faster than 
in Emacs hashtables until 50+ elements. Or was, around the year 2009.

> This said, I'm not terribly concerned about it: if you need it to go
> fast, you should byte-compile the code.

I guess so. The sloppy users who disregarded the instructions to 
byte-compile the code were actually creating a bad reputation for 
js2-mode 1-2 years ago, but since package.el is much more popular now, 
it should be less of a problem.

>> But 2.6 vs 2.1, it still a noticeable regression. Do you suppose the usage
>> of `setq' is the main contributor?
>
> The problem goes as follows: ...

Thank you for the detailed explanation.

There are a few `catch' forms left there, for tags `continue' and 
`break', used for control flow. So, most of the 0.5s difference left is 
likely due to them, right?

I wonder how hard it'll be to rewrite that without `catch'.

>> (*) Would you take a look at it, too? It has quite a few changes in
>> js2-get-token' and related functions.
>
>> They also make performing the same change as in your patch more
>> difficult, since I'm actually using the value returned by `catch'
>> before returning from the function.
>
> That's not a problem.  The rule to follow is simply: sink the `let'
> bindings closer to their use.  You don't need to `let' bind all those
> vars together in one big `let': you can split this let into various
> `let's which you can then move deeper into the code.  In some cases
> you'll find that some of those vars don't even need to be `setq'd any
> more.

Thanks, will do.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-10  2:04 ` Stefan Monnier
  2013-09-13  3:40   ` Stefan Monnier
@ 2013-09-15  0:24   ` Dmitry Gutov
  2013-09-15  5:06     ` Stefan Monnier
  2013-09-18 23:48   ` Stefan Monnier
  2 siblings, 1 reply; 25+ messages in thread
From: Dmitry Gutov @ 2013-09-15  0:24 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

On 10.09.2013 05:04, Stefan Monnier wrote:
> If it indeed comes from the handling of catch/throw, then there are two
> ways to fix it:
> - ...
> - improve the byte-compiler so it can compile away cl-block/cl-return.
>    This should not require new byte-codes, but requires delving "deepish"
>    into the byte-compiler.

This would take care of `cl-block' wrappers, but it would do nothing 
about explicit uses of `catch', right?





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-15  0:11         ` Dmitry Gutov
@ 2013-09-15  5:04           ` Stefan Monnier
  2013-09-15 16:54           ` Richard Stallman
  1 sibling, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-15  5:04 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

> Can the fact that `dotimes', `dolist' and `loop' are advised with
> cl--wrap-in-nil-block', which expands into `catch' form, make much
> of a difference?

No, these only expand to `catch' if there's a `return' inside.

> `js2-get-token' has 13 local variables (*).  Which is, while not a little,
> far from 100.  Most of the other functions have fewer than that.

I don't know how many it takes to be significantly slower than `symbol-value'.

> Are you counting the global variables, too?

No.  But arguments, yes, and every (defvar <var>) between point and BOB
as well.

> The dynamic-binding interpreter has to work with them, too.  How is it
> that much faster?

Dynamic binding lookup is done by `symbol-value' which is just a field
access (plus checking that the var is not special (e.g. buffer-local or
a predefined C variable).

>>> But 2.6 vs 2.1, it still a noticeable regression. Do you suppose the usage
>>> of `setq' is the main contributor?
>> The problem goes as follows: ...
> Thank you for the detailed explanation.
> There are a few `catch' forms left there, for tags `continue' and `break',
> used for control flow. So, most of the 0.5s difference left is likely due to
> them, right?

The problem is not just the use of catch, but the combination of "catch"
with all those vars let-bound outside of catch, used inside, and mutated:
- make a variable immutable (i.e. remove the setqs on it) and that
  variable becomes more efficient again.
- move the let binding inside the catch, and the var becomes efficient again.
- don't use the variable inside the catch, and it becomes efficient again.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-15  0:24   ` Dmitry Gutov
@ 2013-09-15  5:06     ` Stefan Monnier
  0 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-09-15  5:06 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

>> If it indeed comes from the handling of catch/throw, then there are two
>> ways to fix it:
>> - ...
>> - improve the byte-compiler so it can compile away cl-block/cl-return.
>> This should not require new byte-codes, but requires delving "deepish"
>> into the byte-compiler.
> This would take care of `cl-block' wrappers, but it would do nothing about
> explicit uses of `catch', right?

All js2-mode's uses of catch/throw can be replaced with
block/return, AFAICT (not that it's useful right now, since they'll
just be macroexpanded back to catch/throw).


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-15  0:11         ` Dmitry Gutov
  2013-09-15  5:04           ` Stefan Monnier
@ 2013-09-15 16:54           ` Richard Stallman
  1 sibling, 0 replies; 25+ messages in thread
From: Richard Stallman @ 2013-09-15 16:54 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

        [ To any NSA and FBI agents reading my email: please consider
        [ whether defending the US Constitution against all enemies,
        [ foreign or domestic, requires you to follow Snowden's example.

Perhaps we should optimize the implementation of catch
in bytecode with some new opcodes.

-- 
Dr Richard Stallman
President, Free Software Foundation
51 Franklin St
Boston MA 02110
USA
www.fsf.org  www.gnu.org
Skype: No way! That's nonfree (freedom-denying) software.
  Use Ekiga or an ordinary phone call.






^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-10  2:04 ` Stefan Monnier
  2013-09-13  3:40   ` Stefan Monnier
  2013-09-15  0:24   ` Dmitry Gutov
@ 2013-09-18 23:48   ` Stefan Monnier
  2013-09-22  4:56     ` Dmitry Gutov
  2 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2013-09-18 23:48 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

I now have a tentative patch which introduces new bytecodes for
"catch" which avoid the need to create closures for
lexical-binding code.

Current results:
- dynbind old-bytecode: 0.84s
- dynbind new-bytecode: 0.83s
- lexbind old-bytecode: 2.14s
- lexbind new-bytecode: 0.67s

Of course, code compiled with the new bytecodes won't run on
non-bleeding edge Emacs.

On my "standard test" (i.e. time to recompile all the emacs/lisp files),
the new bytecodes make no measurable difference, so `catch' doesn't seem
to be used very much there.

Similar changes would be welcome for condition-case and
unwind-protect, and since adding new bytecodes is something I'd rather
not do too often (and since there aren't many unused bytecodes left),
I'll try to get a complete patch first to make sure I don't have to
change my mind and use different byte codes.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-18 23:48   ` Stefan Monnier
@ 2013-09-22  4:56     ` Dmitry Gutov
  2013-10-03  5:00       ` Stefan Monnier
  0 siblings, 1 reply; 25+ messages in thread
From: Dmitry Gutov @ 2013-09-22  4:56 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

> I now have a tentative patch which introduces new bytecodes for
> "catch" which avoid the need to create closures for
> lexical-binding code.
>
> Current results:
> - dynbind old-bytecode: 0.84s
> - dynbind new-bytecode: 0.83s
> - lexbind old-bytecode: 2.14s
> - lexbind new-bytecode: 0.67s

Looks impressive!

> Of course, code compiled with the new bytecodes won't run on
> non-bleeding edge Emacs.

Sure.

> Similar changes would be welcome for condition-case and
> unwind-protect, and since adding new bytecodes is something I'd rather
> not do too often (and since there aren't many unused bytecodes left),
> I'll try to get a complete patch first to make sure I don't have to
> change my mind and use different byte codes.

There's absolutely no hurry, I'm not going to switch js2-mode to
lexical-binding until after 24.4 is out.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-09-22  4:56     ` Dmitry Gutov
@ 2013-10-03  5:00       ` Stefan Monnier
  2013-10-04  2:38         ` Dmitry Gutov
  0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2013-10-03  5:00 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

You can try setting byte-compile--use-old-handlers to nil now to see if
it fixes your performance problems.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-10-03  5:00       ` Stefan Monnier
@ 2013-10-04  2:38         ` Dmitry Gutov
  2013-10-04 13:52           ` Stefan Monnier
  0 siblings, 1 reply; 25+ messages in thread
From: Dmitry Gutov @ 2013-10-04  2:38 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

On 03.10.2013 08:00, Stefan Monnier wrote:
> You can try setting byte-compile--use-old-handlers to nil now to see if
> it fixes your performance problems.

Indeed, I see the same peformance improvement you wrote about: 0.60s in 
byte-compiled dynamic binding mode, and now 0.48s in byte-compiled 
lexical binding mode. Thanks!

Not sure if I should close this issue now or at least wait until 
byte-compile--use-old-handlers is nil by default.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-10-04  2:38         ` Dmitry Gutov
@ 2013-10-04 13:52           ` Stefan Monnier
  2013-10-05  3:27             ` Dmitry Gutov
  2014-12-14 12:31             ` Dmitry Gutov
  0 siblings, 2 replies; 25+ messages in thread
From: Stefan Monnier @ 2013-10-04 13:52 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294

> Not sure if I should close this issue now or at least wait until
> byte-compile--use-old-handlers is nil by default.

Your call.  I'm not completely sure when we should change it: setting it
to nil will mean that pretty much any file compiled with the new Emacs
won't run on older Emacsen.  I think I'd like to see 24.4 release before
making the change.  But please do set it in your .emacs ASAP so it gets
wider testing.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-10-04 13:52           ` Stefan Monnier
@ 2013-10-05  3:27             ` Dmitry Gutov
  2014-12-14 12:31             ` Dmitry Gutov
  1 sibling, 0 replies; 25+ messages in thread
From: Dmitry Gutov @ 2013-10-05  3:27 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

On 04.10.2013 16:52, Stefan Monnier wrote:
>> Not sure if I should close this issue now or at least wait until
>> byte-compile--use-old-handlers is nil by default.
>
> Your call.  I'm not completely sure when we should change it: setting it
> to nil will mean that pretty much any file compiled with the new Emacs
> won't run on older Emacsen.  I think I'd like to see 24.4 release before
> making the change.

No problem, guess then I'll leave this open until then.

I'll do the code reshuffling discussed earlier, but actually having a 
performance improvement will be a better reason to switch to lexical 
binding.

 > But please do set it in your .emacs ASAP so it gets wider testing.

Good idea, done.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2013-10-04 13:52           ` Stefan Monnier
  2013-10-05  3:27             ` Dmitry Gutov
@ 2014-12-14 12:31             ` Dmitry Gutov
  2014-12-14 14:08               ` Stefan Monnier
  1 sibling, 1 reply; 25+ messages in thread
From: Dmitry Gutov @ 2014-12-14 12:31 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 15294

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Not sure if I should close this issue now or at least wait until
>> byte-compile--use-old-handlers is nil by default.

> won't run on older Emacsen.  I think I'd like to see 24.4 release before
> making the change.  But please do set it in your .emacs ASAP so it gets
> wider testing.

Just a reminder: I've been running with that setting for a while now,
with no problems that I can remember.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode
  2014-12-14 12:31             ` Dmitry Gutov
@ 2014-12-14 14:08               ` Stefan Monnier
  0 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2014-12-14 14:08 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 15294-done

>>> Not sure if I should close this issue now or at least wait until
>>> byte-compile--use-old-handlers is nil by default.
>> won't run on older Emacsen.  I think I'd like to see 24.4 release before
>> making the change.  But please do set it in your .emacs ASAP so it gets
>> wider testing.
> Just a reminder: I've been running with that setting for a while now,

So have I.

> with no problems that I can remember.

Well, I fixed a bug in it a while ago (some issue with "volatile", fixed
before the 24.4 release), but other than that, indeed it works fine.

The default value has been changed in "master" a couple months ago, already.


        Stefan





^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2014-12-14 14:08 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-06 20:59 bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode Dmitry Gutov
2013-09-06 23:44 ` Xue Fuqiao
2013-09-07  3:15   ` Stefan Monnier
2013-09-08 22:32 ` Stefan Monnier
2013-09-10  2:04 ` Stefan Monnier
2013-09-13  3:40   ` Stefan Monnier
2013-09-13  3:59     ` Drew Adams
2013-09-13  4:37       ` Stefan Monnier
2013-09-13  5:45         ` Drew Adams
2013-09-13 13:01           ` Stefan Monnier
2013-09-14  4:20     ` Dmitry Gutov
2013-09-14 14:27       ` Stefan Monnier
2013-09-15  0:11         ` Dmitry Gutov
2013-09-15  5:04           ` Stefan Monnier
2013-09-15 16:54           ` Richard Stallman
2013-09-15  0:24   ` Dmitry Gutov
2013-09-15  5:06     ` Stefan Monnier
2013-09-18 23:48   ` Stefan Monnier
2013-09-22  4:56     ` Dmitry Gutov
2013-10-03  5:00       ` Stefan Monnier
2013-10-04  2:38         ` Dmitry Gutov
2013-10-04 13:52           ` Stefan Monnier
2013-10-05  3:27             ` Dmitry Gutov
2014-12-14 12:31             ` Dmitry Gutov
2014-12-14 14:08               ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).