From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Spencer Baugh Newsgroups: gmane.emacs.bugs Subject: bug#48264: [PATCH v3 00/15] Speeding up setting the default for DEFVAR_PER_BUFFER vars Date: Thu, 6 May 2021 17:33:31 -0400 Message-ID: <20210506213346.9730-1-sbaugh@catern.com> References: <877dkbsj9d.fsf@catern.com> Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="36438"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Spencer Baugh To: 48264@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Thu May 06 23:34:29 2021 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1leldd-0009MQ-49 for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 06 May 2021 23:34:29 +0200 Original-Received: from localhost ([::1]:60156 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1leldc-0005Jp-3Y for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 06 May 2021 17:34:28 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:45200) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1leldE-0005Ix-Th for bug-gnu-emacs@gnu.org; Thu, 06 May 2021 17:34:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:56548) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1leldE-0001mN-Lp for bug-gnu-emacs@gnu.org; Thu, 06 May 2021 17:34:04 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1leldE-0000B6-Gw for bug-gnu-emacs@gnu.org; Thu, 06 May 2021 17:34:04 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Spencer Baugh Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 06 May 2021 21:34:04 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 48264 X-GNU-PR-Package: emacs Original-Received: via spool by 48264-submit@debbugs.gnu.org id=B48264.1620336842650 (code B ref 48264); Thu, 06 May 2021 21:34:04 +0000 Original-Received: (at 48264) by debbugs.gnu.org; 6 May 2021 21:34:02 +0000 Original-Received: from localhost ([127.0.0.1]:39850 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1leldA-0000AI-VL for submit@debbugs.gnu.org; Thu, 06 May 2021 17:34:01 -0400 Original-Received: from venus.catern.com ([68.183.49.163]:41454) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1leld5-00009N-0m for 48264@debbugs.gnu.org; Thu, 06 May 2021 17:33:57 -0400 Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=98.7.229.235; helo=localhost; envelope-from=sbaugh@catern.com; receiver= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=catern.com; s=mail; t=1620336834; bh=q2skZYdZV73MIKMCr2rG4O3reurWTJHhN13gT2u0huc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ZmvvVgIZ/IFjqcjUjrTljR593d2+/EKp1MQfILMEo93RiRsKstgmyo+CDRHyKlO9B I9uYoTzeylSwB0kIczeQ0zkRDZ4zrLU19XBSV7B4Z+1fFobTQxs5YHr8rbjMb5SG7m xm3MIvh4KYptNJM7eRpUvzPLRe8RdUg1zQKjxk/4= Original-Received: from localhost (cpe-98-7-229-235.nyc.res.rr.com [98.7.229.235]) by venus.catern.com (Postfix) with ESMTPSA id 5F9092E9360; Thu, 6 May 2021 21:33:52 +0000 (UTC) X-Mailer: git-send-email 2.31.1 In-Reply-To: <877dkbsj9d.fsf@catern.com> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list 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-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:205880 Archived-At: This patch series fixes bug#48264 by speeding up changes to the default value for DEFVAR_PER_BUFFER vars, whether by let or set-default. Such changes are now constant time, and run as fast as changes to non-default values. This change optimizes setting the default in exchange for a small slowdown on every access to a DEFVAR_PER_BUFFER var that has a default. I've benchmarked this change (results posted in other threads on emacs-devel) and found minimal slowdown in pure Lisp code, and a 1-2% slowdown in the display engine. === Background on DEFVAR_PER_BUFFER variables === DEFVAR_PER_BUFFER is a C macro which sets up a correspondence between a Lisp symbol and a field of type Lisp_Object in the C `struct buffer' struct. There are a finite number of such fields, and DEFVAR_PER_BUFFER is called for a subset of them. Each DEFVAR_PER_BUFFER variable appears to Lisp code as a buffer-local variable, and should behave like pure Lisp buffer-local variables. Each DEFVAR_PER_BUFFER variable is either permanently buffer-local, or has a default value which is used by buffers that don't currently have a buffer-local binding. If a buffer has a buffer-local binding for one of these variables, then the per-buffer value is stored in the corresponding field in that buffer's `struct buffer'. Default values for these variables are stored in a global `struct buffer' C variable, `buffer_defaults'. This struct does not correspond to a real buffer, and its non-DEFVAR_PER_BUFFER fields are unused. When a variable's default value is changed, the corresponding field is changed in (at least) buffer_defaults. When `default-value' is used to read a DEFVAR_PER_BUFFER variable's default value, it's read from buffer_defaults. The underlying fields in `struct buffer' used with DEFVAR_PER_BUFFER are also read and written directly from C, through the BVAR macro. The BVAR macro takes a pointer to a `struct buffer' and the name of a field in `struct buffer', and evaluates to the value for that field. The variables must behave the same both when used through the symbol in Lisp, and used through BVAR in C. For example, if BVAR reads a field from a buffer that does not have a buffer-local binding for that field, it should evaluate to the default value for that field. === Old implementation === In the old implementation, both the permanently buffer-local DEFVAR_PER_BUFFER variables and the variables with defaults values were accessed in the same way: Through the BVAR macro. The BVAR macro is essentially a no-op. It turns into a simple field dereference, essentially: #define BVAR(buf, field) (buf)->field We simply read the field directly out of the specific `struct buffer' we're working with. Neither BVAR nor surrounding C code checks whether a buffer has a buffer-local binding for a variable before using this field, and at no point does most code check what value is in buffer_defaults. This is fine for permanently buffer-local DEFVAR_PER_BUFFER variables, which have no default value. For variables which are not permanently buffer-local, though, this means we need to ensure that the C Lisp_Object field always contains the "correct" value for the variable, whether that's a currently buffer-local value, or the global default value. If there is a buffer-local binding, then the field contains the per-buffer value, and all is well. If there is no buffer-local binding, then we need to ensure that the field contains the global default value. To do this, whenever the global default value changes, we iterate over all buffers, and if there's no buffer-local binding, set the field to the new default value. This is O(n) in the number of buffers open in Emacs - quite slow. = Old implementation: local_flags and buffer_local_flags = Also, we frequently need to know whether a variable has a buffer-local binding. We maintain this information with the `local_flags' field in `struct buffer', which is a char array with an entry for each DEFVAR_PER_BUFFER variable. When we create or kill a buffer-local binding for a DEFVAR_PER_BUFFER variable, we update local_flags. To support local_flags, we need even further metadata; buffer_local_flags is a global, initialized at startup and constant after that, which maps the offsets of the DEFVAR_PER_BUFFER C fields to indices in local_flags. We perform a lookup in buffer_local_flags whenever we need to change local_flags for a variable. === New implementation === In the new implementation, we use separate macros for permanently buffer-local variables and for variables with defaults. Permanently buffer-local variables use BVAR, which stays the same. Variables with defaults now use BVAR_OR_DEFAULT, which does a bit more work. Simplifying a bit: #define BVAR_OR_DEFAULT(buf, field) \ EQ ((buf)->field, Qunbound) ? buffer_defaults.field : (buf)->field We now use Qunbound as a sentinel to tell us whether the buffer has a buffer-local binding for this field or not. If the field contains Qunbound, we should use the default value out of buffer_defaults; if not, there's a buffer-local binding, and we should use the per-buffer value. We no longer need to iterate over all buffers whenever we change the default value. So setting the default value is now fast. = New implementation: No more local_flags and buffer_local_flags = Both of these are now useless and can be deleted. When we create a buffer-local binding for a DEFVAR_PER_BUFFER variable, we simply set the field. When we kill a buffer-local binding, we set the field to Qunbound. There's no additional metadata. === Individual commits === See the individual commit messages for more. Stop checking the constant default for enable_multibyte_characters This removes a defunct default that still existed for enable_multibyte_characters, making it work like all the other permanently buffer-local variables, which simplifies the rest of our changes. Take offset not idx in PER_BUFFER_VALUE_P Add and use BUFFER_DEFAULT_VALUE_P Combine unnecessarily separate loops in buffer.c Add and use KILL_PER_BUFFER_VALUE Rearrange set_internal for buffer forwarded symbols These change or add abstractions for accessing buffer Lisp_Object fields, to remove dependencies on implementation details which will change. Add BVAR_OR_DEFAULT macro as a stub This adds the BVAR_OR_DEFAULT macro without actually changing behavior yet. This is the largest patch, since it needs to change code using BVAR everywhere in Emacs. Set non-buffer-local BVARs to Qunbound This is the heart of the patch series; it changes the behavior of BVAR_OR_DEFAULT to match what was described above. Remove unnecessary Qunbound check Get rid of buffer_permanent_local_flags array Delete SET_PER_BUFFER_VALUE_P and buffer local_flags field Set buffer_defaults fields without a default to Qunbound Assert that PER_BUFFER_IDX for Lisp variables is not 0 Remove PER_BUFFER_IDX and buffer_local_flags These remove various forms of metadata maintained in buffer.c which are no longer necessary after our change. Add and use BVAR_FIELD macros This enforces statically that BVAR_OR_DEFAULT is only used for fields with defaults, and that BVAR is only used for fields without defaults. Spencer Baugh (15): Stop checking the constant default for enable_multibyte_characters Take offset not idx in PER_BUFFER_VALUE_P Add and use BUFFER_DEFAULT_VALUE_P Combine unnecessarily separate loops in buffer.c Add and use KILL_PER_BUFFER_VALUE Rearrange set_internal for buffer forwarded symbols Add BVAR_OR_DEFAULT macro as a stub Set non-buffer-local BVARs to Qunbound Remove unnecessary Qunbound check Get rid of buffer_permanent_local_flags array Delete SET_PER_BUFFER_VALUE_P and buffer local_flags field Set buffer_defaults fields without a default to Qunbound Assert that PER_BUFFER_IDX for Lisp variables is not 0 Remove PER_BUFFER_IDX and buffer_local_flags Add and use BVAR_FIELD macros lisp/bindings.el | 3 +- src/alloc.c | 3 +- src/bidi.c | 19 +- src/buffer.c | 430 +++++++++++++---------------------------- src/buffer.h | 302 +++++++++++++---------------- src/category.c | 12 +- src/cmds.c | 6 +- src/data.c | 82 ++------ src/editfns.c | 4 +- src/fileio.c | 9 +- src/fns.c | 8 +- src/fringe.c | 21 +- src/hbfont.c | 2 +- src/indent.c | 34 ++-- src/msdos.c | 6 +- src/pdumper.c | 3 - src/print.c | 6 +- src/process.c | 15 +- src/search.c | 21 +- src/syntax.c | 13 +- src/syntax.h | 5 +- src/window.c | 29 +-- src/xdisp.c | 130 +++++++------ test/src/data-tests.el | 1 - 24 files changed, 448 insertions(+), 716 deletions(-) -- 2.31.1