From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.bugs Subject: bug#15294: 24.3.50; js2-mode parser is several times slower in lexical-binding mode Date: Sat, 14 Sep 2013 10:27:17 -0400 Message-ID: References: <871u51ll93.fsf@yandex.ru> <5233E40D.4000102@yandex.ru> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1379168909 10326 80.91.229.3 (14 Sep 2013 14:28:29 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 14 Sep 2013 14:28:29 +0000 (UTC) Cc: 15294@debbugs.gnu.org To: Dmitry Gutov Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sat Sep 14 16:28:31 2013 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1VKqpo-0006wK-9Z for geb-bug-gnu-emacs@m.gmane.org; Sat, 14 Sep 2013 16:28:28 +0200 Original-Received: from localhost ([::1]:53532 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VKqpn-0001vg-SC for geb-bug-gnu-emacs@m.gmane.org; Sat, 14 Sep 2013 10:28:27 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:38188) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VKqpd-0001uX-Ne for bug-gnu-emacs@gnu.org; Sat, 14 Sep 2013 10:28:25 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VKqpP-0000Yo-36 for bug-gnu-emacs@gnu.org; Sat, 14 Sep 2013 10:28:17 -0400 Original-Received: from debbugs.gnu.org ([140.186.70.43]:56627) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VKqpO-0000YY-VN for bug-gnu-emacs@gnu.org; Sat, 14 Sep 2013 10:28:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.80) (envelope-from ) id 1VKqpO-0006dL-7s for bug-gnu-emacs@gnu.org; Sat, 14 Sep 2013 10:28:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Stefan Monnier Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 14 Sep 2013 14:28:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 15294 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 15294-submit@debbugs.gnu.org id=B15294.137916884825447 (code B ref 15294); Sat, 14 Sep 2013 14:28:02 +0000 Original-Received: (at 15294) by debbugs.gnu.org; 14 Sep 2013 14:27:28 +0000 Original-Received: from localhost ([127.0.0.1]:36687 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1VKqop-0006cM-BL for submit@debbugs.gnu.org; Sat, 14 Sep 2013 10:27:28 -0400 Original-Received: from ironport2-out.teksavvy.com ([206.248.154.182]:43740) by debbugs.gnu.org with esmtp (Exim 4.80) (envelope-from ) id 1VKqol-0006c5-RB for 15294@debbugs.gnu.org; Sat, 14 Sep 2013 10:27:24 -0400 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Av8EABK/CFG4rxBo/2dsb2JhbABEuzWDWRdzgh4BAQQBVg8UBQsLDiYSFBgNJIgeBsEtkQoDpHqBXoMT X-IPAS-Result: Av8EABK/CFG4rxBo/2dsb2JhbABEuzWDWRdzgh4BAQQBVg8UBQsLDiYSFBgNJIgeBsEtkQoDpHqBXoMT X-IronPort-AV: E=Sophos;i="4.84,565,1355115600"; d="scan'208";a="27771312" Original-Received: from 184-175-16-104.dsl.teksavvy.com (HELO pastel.home) ([184.175.16.104]) by ironport2-out.teksavvy.com with ESMTP/TLS/ADH-AES256-SHA; 14 Sep 2013 10:23:41 -0400 Original-Received: by pastel.home (Postfix, from userid 20848) id 76ACC62D1E; Sat, 14 Sep 2013 10:27:17 -0400 (EDT) In-Reply-To: <5233E40D.4000102@yandex.ru> (Dmitry Gutov's message of "Sat, 14 Sep 2013 07:20:29 +0300") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.15 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 140.186.70.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:78400 Archived-At: >> 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