unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
@ 2024-11-14 20:39 Björn Lindqvist
  2024-11-15  7:40 ` Eli Zaretskii
  0 siblings, 1 reply; 9+ messages in thread
From: Björn Lindqvist @ 2024-11-14 20:39 UTC (permalink / raw)
  To: 74357

This bug has been present in c-mode for at least a year, but I haven't
gotten around to report it. The reason is that bugs about latency are
erratic and tricky to triage. Typing when the cursor is on some
syntatic constructs in c-mode causes severe lag on the order of several
hundred milliseconds on my (admittedly slow) laptop. The lag
makes c-mode almost unusable. Here is an MWE:

    void foo(uint dc_dim, uint sc_dim,
             uint fy_dim, uint fx_dim,
             __global const float * restrict F,
             uint sy_dim, uint sx_dim,
             __global const float * restrict S,
             uint padding,
             __global float * restrict D) {
        uint dy_dim = sy_dim + 2 * padding - fy_dim + 1;
        uint dx_dim = sx_dim + 2 * padding - fx_dim + 1;

        // Place cursor at "y" in "dy_dim". Hold "y" and observe lag.
        uint dn = dc_dim * dy_dim * dx_dim;
        uint sn = sc_dim * sy_dim * sx_dim;
    }

I can make typing even laggier by wrapping foo in foo, like this:

    void foo(...) {
    ...
    void foo(uint dc_dim, uint sc_dim,
             uint fy_dim, uint fx_dim,
             __global float * restrict F,
             uint sy_dim, uint sx_dim,
             __global float * restrict S,
             uint padding,
             __global float * restrict D) {
        uint dy_dim = sy_dim + 2 * padding - fy_dim + 1;
        uint dx_dim = sx_dim + 2 * padding - fx_dim + 1;

        // Place cursor at d[y]_dim. Hold "y". Observe lag in c-mode.
        uint dn = dc_dim * dy_dim * dx_dim;
        uint sn = sc_dim * sy_dim * sx_dim;
    }
    }

The more times I wrap foo the slower c-mode gets. So if you have a
fast computer try nesting foo in foo 50 times... I have observed the
same annoying input lag on multiple computers and I don't use any
special c-mode configuration.

Please cc me as I'm not subscribed to the list.

GNU Emacs 29.4 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.43,
cairo version 1.18.2)


-- 
mvh/best regards Björn Lindqvist





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-14 20:39 bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag Björn Lindqvist
@ 2024-11-15  7:40 ` Eli Zaretskii
  2024-11-15 14:08   ` Björn Lindqvist
  0 siblings, 1 reply; 9+ messages in thread
From: Eli Zaretskii @ 2024-11-15  7:40 UTC (permalink / raw)
  To: Björn Lindqvist, Alan Mackenzie; +Cc: 74357

> From: Björn Lindqvist <bjourne@gmail.com>
> Date: Thu, 14 Nov 2024 21:39:53 +0100
> 
> This bug has been present in c-mode for at least a year, but I haven't
> gotten around to report it. The reason is that bugs about latency are
> erratic and tricky to triage. Typing when the cursor is on some
> syntatic constructs in c-mode causes severe lag on the order of several
> hundred milliseconds on my (admittedly slow) laptop. The lag
> makes c-mode almost unusable. Here is an MWE:
> 
>     void foo(uint dc_dim, uint sc_dim,
>              uint fy_dim, uint fx_dim,
>              __global const float * restrict F,
>              uint sy_dim, uint sx_dim,
>              __global const float * restrict S,
>              uint padding,
>              __global float * restrict D) {
>         uint dy_dim = sy_dim + 2 * padding - fy_dim + 1;
>         uint dx_dim = sx_dim + 2 * padding - fx_dim + 1;
> 
>         // Place cursor at "y" in "dy_dim". Hold "y" and observe lag.
>         uint dn = dc_dim * dy_dim * dx_dim;
>         uint sn = sc_dim * sy_dim * sx_dim;
>     }
> 
> I can make typing even laggier by wrapping foo in foo, like this:
> 
>     void foo(...) {
>     ...
>     void foo(uint dc_dim, uint sc_dim,
>              uint fy_dim, uint fx_dim,
>              __global float * restrict F,
>              uint sy_dim, uint sx_dim,
>              __global float * restrict S,
>              uint padding,
>              __global float * restrict D) {
>         uint dy_dim = sy_dim + 2 * padding - fy_dim + 1;
>         uint dx_dim = sx_dim + 2 * padding - fx_dim + 1;
> 
>         // Place cursor at d[y]_dim. Hold "y". Observe lag in c-mode.
>         uint dn = dc_dim * dy_dim * dx_dim;
>         uint sn = sc_dim * sy_dim * sx_dim;
>     }
>     }
> 
> The more times I wrap foo the slower c-mode gets. So if you have a
> fast computer try nesting foo in foo 50 times... I have observed the
> same annoying input lag on multiple computers and I don't use any
> special c-mode configuration.

I've wrapped the snippet with 50 foo, and I still don't see any
significant lags.

Does it matter where you type, for reproducing the lag?

Also, can you run this under a profiler (M-x profiler-start) and then
show the full expanded profile produced by "M-x profiler-report" after
several tens of seconds of typing with the lag?

Adding Alan to the discussion.





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-15  7:40 ` Eli Zaretskii
@ 2024-11-15 14:08   ` Björn Lindqvist
  2024-11-15 14:25     ` Eli Zaretskii
  0 siblings, 1 reply; 9+ messages in thread
From: Björn Lindqvist @ 2024-11-15 14:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Alan Mackenzie, 74357

> > From: Björn Lindqvist <bjourne@gmail.com>
> > Date: Thu, 14 Nov 2024 21:39:53 +0100
> >
> > This bug has been present in c-mode for at least a year, but I haven't
> > gotten around to report it. The reason is that bugs about latency are
> > erratic and tricky to triage. Typing when the cursor is on some
> > syntatic constructs in c-mode causes severe lag on the order of several
> > hundred milliseconds on my (admittedly slow) laptop. The lag
> > makes c-mode almost unusable. Here is an MWE:
> >
> >     void foo(uint dc_dim, uint sc_dim,
> >              uint fy_dim, uint fx_dim,
> >              __global const float * restrict F,
> >              uint sy_dim, uint sx_dim,
> >              __global const float * restrict S,
> >              uint padding,
> >              __global float * restrict D) {
> >         uint dy_dim = sy_dim + 2 * padding - fy_dim + 1;
> >         uint dx_dim = sx_dim + 2 * padding - fx_dim + 1;
> >
> >         // Place cursor at "y" in "dy_dim". Hold "y" and observe lag.
> >         uint dn = dc_dim * dy_dim * dx_dim;
> >         uint sn = sc_dim * sy_dim * sx_dim;
> >     }
> >
> > I can make typing even laggier by wrapping foo in foo, like this:
> >
> >     void foo(...) {
> >     ...
> >     void foo(uint dc_dim, uint sc_dim,
> >              uint fy_dim, uint fx_dim,
> >              __global float * restrict F,
> >              uint sy_dim, uint sx_dim,
> >              __global float * restrict S,
> >              uint padding,
> >              __global float * restrict D) {
> >         uint dy_dim = sy_dim + 2 * padding - fy_dim + 1;
> >         uint dx_dim = sx_dim + 2 * padding - fx_dim + 1;
> >
> >         // Place cursor at d[y]_dim. Hold "y". Observe lag in c-mode.
> >         uint dn = dc_dim * dy_dim * dx_dim;
> >         uint sn = sc_dim * sy_dim * sx_dim;
> >     }
> >     }
> >
> > The more times I wrap foo the slower c-mode gets. So if you have a
> > fast computer try nesting foo in foo 50 times... I have observed the
> > same annoying input lag on multiple computers and I don't use any
> > special c-mode configuration.
>
> I've wrapped the snippet with 50 foo, and I still don't see any
> significant lags.
>
> Does it matter where you type, for reproducing the lag?
>
> Also, can you run this under a profiler (M-x profiler-start) and then
> show the full expanded profile produced by "M-x profiler-report" after
> several tens of seconds of typing with the lag?
>
> Adding Alan to the discussion.

Hello Eli, thanks for the swift reply.


I've created a much larger example so you can see what I mean with
"wrapping foo in foo":

https://gist.github.com/bjourne/8f705c5879aa966accf354008623f6bb

Open file in c-mode, Go to line 328, place the cursor on "y" in "dy_dim"
and press and hold "y". Unless you have a supercomputer the lag will be
really apparent. Disable Global Font-lock mode and repeat the exercise.
Lag will be gone. Lag is worse if I use non-jitted Emacs, but really
apparent in jitted Emacs too. Lag goes away if I use c-ts-mode instead
of c-mode.

I want to emphasize that lag is present in normal code too, but easier
to detect in these specially crafted samples.

My system-configuration-features:

"ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ
JPEG JSON LCMS2 LIBOTF LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP
NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS TREE_SITTER WEBP X11 XDBE XIM XINPUT2 XPM GTK3
ZLIB"

Profiler report:

https://gist.github.com/bjourne/842695100e99c8fd6ef87fcdd0a6ed0b


-- 
mvh/best regards Björn Lindqvist





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-15 14:08   ` Björn Lindqvist
@ 2024-11-15 14:25     ` Eli Zaretskii
  2024-11-15 14:45       ` Alan Mackenzie
  2024-11-15 21:43       ` Björn Lindqvist
  0 siblings, 2 replies; 9+ messages in thread
From: Eli Zaretskii @ 2024-11-15 14:25 UTC (permalink / raw)
  To: Björn Lindqvist; +Cc: acm, 74357

> From: Björn Lindqvist <bjourne@gmail.com>
> Date: Fri, 15 Nov 2024 15:08:09 +0100
> Cc: Alan Mackenzie <acm@muc.de>, 74357@debbugs.gnu.org
> 
> > I've wrapped the snippet with 50 foo, and I still don't see any
> > significant lags.
> >
> > Does it matter where you type, for reproducing the lag?
> >
> > Also, can you run this under a profiler (M-x profiler-start) and then
> > show the full expanded profile produced by "M-x profiler-report" after
> > several tens of seconds of typing with the lag?
> >
> > Adding Alan to the discussion.
> 
> Hello Eli, thanks for the swift reply.
> 
> 
> I've created a much larger example so you can see what I mean with
> "wrapping foo in foo":
> 
> https://gist.github.com/bjourne/8f705c5879aa966accf354008623f6bb
> 
> Open file in c-mode, Go to line 328, place the cursor on "y" in "dy_dim"
> and press and hold "y". Unless you have a supercomputer the lag will be
> really apparent. Disable Global Font-lock mode and repeat the exercise.
> Lag will be gone. Lag is worse if I use non-jitted Emacs, but really
> apparent in jitted Emacs too. Lag goes away if I use c-ts-mode instead
> of c-mode.

Yes, I see the lag now, thanks; the profile is below.  I'll let Alan
look into this and see how this can be improved.

> I want to emphasize that lag is present in normal code too, but easier
> to detect in these specially crafted samples.

Can you tell where in real life do you see such deeply-nested braces
in C source files?

Here's the profile I collected:

         622  60% - redisplay_internal (C function)
         615  59%  - jit-lock-function
         615  59%   - jit-lock-fontify-now
         614  59%    - jit-lock--run-functions
         614  59%     - run-hook-wrapped
         614  59%      - #<byte-code-function 550>
         614  59%       - font-lock-fontify-region
         614  59%        - c-font-lock-fontify-region
         582  56%         - font-lock-default-fontify-region
         581  56%          - font-lock-fontify-keywords-region
         323  31%           - c-font-lock-cut-off-declarators
         302  29%            - c-get-fontification-context
         301  29%             - c-inside-bracelist-p
         221  21%              - c-looking-at-or-maybe-in-bracelist
         154  14%               - c-laomib-loop
          69   6%                - c-backward-sws
          23   2%                 - c-beginning-of-macro
           5   0%                  - back-to-indentation
           2   0%                     skip-syntax-forward
           1   0%                     line-end-position
           1   0%                     backward-prefix-chars
           4   0%                    beginning-of-line
           3   0%                    looking-at
           3   0%                    re-search-forward
           2   0%                    line-end-position
           2   0%                    match-data
           1   0%                    #<byte-code-function 76C>
           1   0%                  - #<byte-code-function 722>
           1   0%                     set-match-data
           1   0%                    make-closure
          11   1%                   looking-at
           7   0%                   skip-syntax-backward
           5   0%                 - c-beginning-of-current-token
           2   0%                    skip-syntax-backward
           2   0%                    looking-at
           5   0%                   forward-comment
           3   0%                   skip-syntax-forward
           1   0%                   make-closure
           1   0%                   buffer-modified-p
          50   4%                - c-backward-token-2
          41   3%                 - c-backward-sws
          11   1%                  - c-beginning-of-macro
           3   0%                     beginning-of-line
           2   0%                     re-search-forward
           2   0%                   - back-to-indentation
           2   0%                      line-end-position
           2   0%                     looking-at
           1   0%                   - #<byte-code-function BFC>
           1   0%                      set-match-data
           7   0%                    looking-at
           2   0%                    forward-comment
           2   0%                    skip-syntax-backward
           2   0%                  - c-beginning-of-current-token
           2   0%                     skip-syntax-backward
           1   0%                    buffer-modified-p
           1   0%                    skip-syntax-forward
           1   0%                    text-property-any
           5   0%                   looking-at
           1   0%                   scan-sexps
          31   3%                - c-at-macro-vsemi-p
          13   1%                   looking-at
           9   0%                 - c-backward-sws
           7   0%                    looking-at
           2   0%                  - c-beginning-of-current-token
           1   0%                     looking-at
           1   0%                     skip-syntax-backward
           4   0%                   skip-syntax-backward
           2   0%                  looking-at
          53   5%               - c-backward-token-2
          49   4%                  scan-sexps
           2   0%                  looking-at
           1   0%                - c-backward-sws
           1   0%                   looking-at
          12   1%               - c-backward-sws
           3   0%                - c-beginning-of-macro
           1   0%                 - back-to-indentation
           1   0%                    skip-syntax-forward
           1   0%                   looking-at
           3   0%                  looking-at
           1   0%                  forward-comment
           1   0%                  skip-syntax-backward
           1   0%                  skip-syntax-forward
           1   0%                 c-laomib-get-cache
           1   0%               - c-back-over-compound-identifier
           1   0%                  c-on-identifier
          79   7%              - c-looking-at-inexpr-block
          38   3%                 scan-sexps
          31   3%               - c-backward-sws
          12   1%                - c-beginning-of-macro
           2   0%                 - back-to-indentation
           1   0%                    line-end-position
           1   0%                    skip-syntax-forward
           1   0%                   re-search-forward
           1   0%                   make-closure
           1   0%                 - #<byte-code-function 4CA>
           1   0%                    set-match-data
           1   0%                   looking-at
           1   0%                   match-data
           7   0%                  looking-at
           3   0%                  skip-syntax-backward
           2   0%                - c-beginning-of-current-token
           2   0%                   looking-at
           2   0%                  forward-comment
          10   0%                 looking-at
           1   0%              - c-backward-over-enum-header
           1   0%                 scan-lists
           1   0%             - c-parse-state
           1   0%              - c-parse-state-1
           1   0%               - c-remove-stale-state-cache
           1   0%                - c-beginning-of-macro
           1   0%                   re-search-forward
           7   0%            - c-determine-limit
           4   0%               parse-partial-sexp
           3   0%             - c-semi-pp-to-literal
           3   0%                parse-partial-sexp
           6   0%            - c-forward-decl-or-cast-1
           3   0%             - c-forward-type
           2   0%              - c-forward-name
           2   0%               - c-determine-+ve-limit
           2   0%                  parse-partial-sexp
           1   0%              - c-forward-keyword-clause
           1   0%               - c-forward-sws
           1   0%                  looking-at
           1   0%               scan-sexps
           4   0%            - c-font-lock-single-decl
           4   0%             - c-font-lock-declarators
           4   0%              - c-do-declarators
           3   0%               - c-forward-declarator
           2   0%                - c-forward-name
           2   0%                 - c-determine-+ve-limit
           2   0%                    parse-partial-sexp
           1   0%                - c-forward-decl-arglist
           1   0%                   scan-lists
           1   0%               - c-syntactic-re-search-forward
           1   0%                  re-search-forward
           2   0%            - c-back-over-member-initializers
           1   0%             - c-backward-sws
           1   0%                skip-syntax-backward
           1   0%             - c-parse-state
           1   0%              - c-parse-state-1
           1   0%               - c-remove-stale-state-cache
           1   0%                - c-beginning-of-macro
           1   0%                   looking-at
           2   0%            - c-at-toplevel-p
           1   0%             - c-search-uplist-for-classkey
           1   0%              - c-looking-at-decl-block
           1   0%                 scan-lists
           1   0%             - c-parse-state
           1   0%              - c-parse-state-1
           1   0%                 c-append-to-state-cache
         226  21%           - c-font-lock-declarations
         226  21%            - c-find-decl-spots
         221  21%             - #<byte-code-function 228>
         170  16%              - c-get-fontification-context
         166  16%               - c-inside-bracelist-p
         108  10%                - c-looking-at-or-maybe-in-bracelist
          69   6%                 - c-laomib-loop
          41   3%                  - c-backward-sws
          11   1%                     looking-at
           8   0%                     forward-comment
           6   0%                   - c-beginning-of-macro
           1   0%                      beginning-of-line
           1   0%                    - back-to-indentation
           1   0%                       line-end-position
           1   0%                      re-search-forward
           3   0%                   - c-beginning-of-current-token
           2   0%                      skip-syntax-backward
           1   0%                      looking-at
           2   0%                     skip-syntax-backward
           2   0%                     skip-syntax-forward
           1   0%                     text-property-any
          21   2%                  - c-backward-token-2
          16   1%                   - c-backward-sws
           4   0%                    - c-beginning-of-macro
           2   0%                     - back-to-indentation
           1   0%                        line-end-position
           1   0%                        skip-syntax-forward
           1   0%                       re-search-forward
           1   0%                     - #<byte-code-function 75C>
           1   0%                        set-match-data
           3   0%                      skip-syntax-backward
           2   0%                      looking-at
           1   0%                    - c-beginning-of-current-token
           1   0%                       looking-at
           2   0%                     scan-sexps
           6   0%                  - c-at-macro-vsemi-p
           3   0%                   - c-backward-sws
           2   0%                      looking-at
           1   0%                    - c-beginning-of-current-token
           1   0%                       looking-at
           2   0%                     looking-at
           1   0%                    looking-at
          29   2%                 - c-backward-token-2
          26   2%                    scan-sexps
           2   0%                    looking-at
           1   0%                  - c-backward-sws
           1   0%                     looking-at
           8   0%                 - c-backward-sws
           3   0%                    skip-syntax-backward
           2   0%                    looking-at
           1   0%                    forward-comment
           1   0%                  - c-beginning-of-macro
           1   0%                     match-data
           1   0%                   c-laomib-get-cache
          55   5%                - c-looking-at-inexpr-block
          30   2%                   scan-sexps
          16   1%                 - c-backward-sws
           6   0%                  - c-beginning-of-macro
           2   0%                     match-data
           1   0%                   - back-to-indentation
           1   0%                      line-end-position
           1   0%                     beginning-of-line
           5   0%                    looking-at
           1   0%                  - c-beginning-of-current-token
           1   0%                     skip-syntax-backward
           1   0%                    skip-syntax-backward
           1   0%                    #<byte-code-function FF6>
           7   0%                   looking-at
           2   0%                - c-backward-over-enum-header
           2   0%                   scan-lists
           3   0%               - c-parse-state
           2   0%                - c-parse-state-1
           2   0%                 - c-remove-stale-state-cache
           2   0%                  - c-beginning-of-macro
           2   0%                   - back-to-indentation
           2   0%                      backward-prefix-chars
           1   0%                - c-beginning-of-macro
           1   0%                 - back-to-indentation
           1   0%                    backward-prefix-chars
          43   4%              - c-forward-decl-or-cast-1
          35   3%               - c-forward-type
          21   2%                - c-forward-name
          18   1%                 - c-determine-+ve-limit
          16   1%                    parse-partial-sexp
           1   0%                   skip-syntax-backward
           1   0%                   looking-at
           5   0%                  looking-at
           5   0%                - c-forward-sws
           3   0%                   looking-at
           2   0%                - c-check-qualified-type
           2   0%                 - c-forward-over-compound-identifier
           2   0%                  - c-forward-over-token
           2   0%                   - c-forward-sws
           2   0%                      looking-at
           1   0%                - c-add-type
           1   0%                 - c-add-type-1
           1   0%                  - c-syntactic-content
           1   0%                     re-search-forward
           5   0%               - c-forward-name
           5   0%                - c-determine-+ve-limit
           5   0%                   parse-partial-sexp
           3   0%                 looking-at
           6   0%              - c-font-lock-single-decl
           6   0%               - c-font-lock-declarators
           6   0%                - c-do-declarators
           6   0%                 - c-forward-declarator
           3   0%                  - c-forward-name
           1   0%                   - c-determine-+ve-limit
           1   0%                      parse-partial-sexp
           1   0%                   - c-forward-sws
           1   0%                      looking-at
           1   0%                     looking-at
           2   0%                    c-syntactic-re-search-forward
           1   0%                    looking-at
           1   0%                looking-at
           1   0%              - c-backward-sws
           1   0%                 text-property-any
           5   0%             - c-bs-at-toplevel-p
           5   0%              - c-brace-stack-at
           5   0%               - c-update-brace-stack
           5   0%                - c-syntactic-re-search-forward
           3   0%                   parse-partial-sexp
           2   0%                 - c-beginning-of-macro
           1   0%                    make-closure
           1   0%                  - back-to-indentation
           1   0%                     beginning-of-line
          27   2%           - c-font-lock-enclosing-decls
          12   1%            - c-syntactic-skip-backward
           5   0%             - c-beginning-of-macro
           3   0%              - back-to-indentation
           2   0%                 line-end-position
           1   0%                 backward-prefix-chars
           1   0%                looking-at
           1   0%                line-end-position
           4   0%             - c-literal-start
           4   0%              - c-semi-pp-to-literal
           4   0%                 parse-partial-sexp
           2   0%             - c-backward-sws
           2   0%                skip-syntax-backward
           7   0%            - c-forward-sws
           6   0%               looking-at
           5   0%            - c-determine-limit
           5   0%               parse-partial-sexp
           2   0%              looking-at
           1   0%            - c-parse-state
           1   0%             - c-parse-state-1
           1   0%              - c-append-to-state-cache
           1   0%                 scan-lists
           3   0%           - c-font-lock-enum-tail
           2   0%            - c-parse-state
           2   0%             - c-parse-state-1
           2   0%              - c-append-to-state-cache
           1   0%               - c-beginning-of-macro
           1   0%                - #<byte-code-function 2B4>
           1   0%                   set-match-data
           1   0%                 scan-lists
           1   0%            - c-backward-over-enum-header
           1   0%               scan-lists
           2   0%           - c-font-lock-complex-decl-prepare
           2   0%              c-backward-sws
           1   0%          - font-lock-fontify-syntactically-region
           1   0%           - font-lock-default-fontify-syntactically
           1   0%            - syntax-ppss
           1   0%               parse-partial-sexp
          32   3%         - c-before-context-fl-expand-region
          32   3%          - mapc
          32   3%           - #<byte-code-function 364>
          32   3%            - c-context-expand-fl-region
          16   1%             - c-fl-decl-end
          13   1%              - c-determine-limit
          11   1%               - c-semi-pp-to-literal
          10   0%                  parse-partial-sexp
           1   0%                  looking-at
           1   0%                 parse-partial-sexp
           1   0%               - c-determine-limit-no-macro
           1   0%                - c-beginning-of-macro
           1   0%                   beginning-of-line
           2   0%              - c-forward-declarator
           1   0%               - c-forward-name
           1   0%                - c-determine-+ve-limit
           1   0%                   parse-partial-sexp
           1   0%               - c-syntactic-re-search-forward
           1   0%                - c-beginning-of-macro
           1   0%                   beginning-of-line
           1   0%              - c-backward-sws
           1   0%               - c-beginning-of-current-token
           1   0%                  looking-at
          16   1%             - c-fl-decl-start
           5   0%              - c-forward-type
           4   0%               - c-forward-name
           2   0%                - c-determine-+ve-limit
           2   0%                   parse-partial-sexp
           1   0%                  looking-at
           1   0%                - c-forward-sws
           1   0%                   looking-at
           1   0%                 looking-at
           4   0%              - c-determine-limit
           4   0%                 parse-partial-sexp
           2   0%              - c-syntactic-skip-backward
           1   0%               - c-literal-start
           1   0%                - c-semi-pp-to-literal
           1   0%                   parse-partial-sexp
           1   0%               - c-beginning-of-macro
           1   0%                - back-to-indentation
           1   0%                   line-end-position
           2   0%              - c-looking-at-or-maybe-in-bracelist
           2   0%               - c-backward-token-2
           2   0%                  scan-sexps
           2   0%              - c-literal-start
           2   0%               - c-semi-pp-to-literal
           2   0%                  parse-partial-sexp
           1   0%              - c-parse-state
           1   0%               - c-parse-state-1
           1   0%                - c-remove-stale-state-cache-backwards
           1   0%                 - c-state-literal-at
           1   0%                  - c-state-pp-to-literal
           1   0%                     parse-partial-sexp
         387  37%   Automatic GC
          13   1% - command-execute
          13   1%  - call-interactively
          10   0%   - funcall-interactively
           5   0%    - self-insert-command
           3   0%     - c-after-change
           3   0%      - mapc
           3   0%       - #<byte-code-function B02>
           3   0%        - c-change-expand-fl-region
           3   0%         - c-fl-decl-end
           1   0%            c-backward-sws
           1   0%          - c-forward-declarator
           1   0%           - c-forward-name
           1   0%            - c-forward-sws
           1   0%               looking-at
           2   0%     - c-before-change
           1   0%      - c-determine-limit
           1   0%         parse-partial-sexp
           1   0%      - c-invalidate-sws-region-before
           1   0%       - c-literal-limits
           1   0%          c-full-pp-to-literal
           5   0%    - next-line
           5   0%     - line-move
           5   0%      - line-move-partial
           5   0%       - pos-visible-in-window-p
           4   0%        - jit-lock-function
           4   0%         - jit-lock-fontify-now
           4   0%          - jit-lock--run-functions
           4   0%           - run-hook-wrapped
           4   0%            - #<byte-code-function 9C0>
           4   0%             - font-lock-fontify-region
           4   0%              - c-font-lock-fontify-region
           3   0%               - font-lock-default-fontify-region
           3   0%                - font-lock-fontify-keywords-region
           2   0%                 - c-font-lock-cut-off-declarators
           2   0%                  - c-get-fontification-context
           2   0%                   - c-inside-bracelist-p
           1   0%                    - c-looking-at-or-maybe-in-bracelist
           1   0%                       c-laomib-loop
           1   0%                    - c-looking-at-inexpr-block
           1   0%                       scan-sexps
           1   0%                 - c-font-lock-declarations
           1   0%                  - c-find-decl-spots
           1   0%                   - #<byte-code-function DC4>
           1   0%                    - c-forward-decl-or-cast-1
           1   0%                       looking-at
           1   0%               - c-before-context-fl-expand-region
           1   0%                - mapc
           1   0%                 - #<byte-code-function E22>
           1   0%                  - c-context-expand-fl-region
           1   0%                   - c-fl-decl-end
           1   0%                    - c-determine-limit
           1   0%                     - c-semi-pp-to-literal
           1   0%                        parse-partial-sexp
           3   0%   - byte-code
           3   0%    - read-extended-command
           3   0%     - read-extended-command-1
           3   0%      - completing-read
           3   0%       - completing-read-default
           3   0%        - read-from-minibuffer
           1   0%           redisplay_internal (C function)
           7   0% - timer-event-handler
           7   0%  - apply
           6   0%   - c-force-redisplay
           6   0%    - c-font-lock-fontify-region
           5   0%     - font-lock-default-fontify-region
           4   0%      - font-lock-fontify-keywords-region
           2   0%       - c-font-lock-declarations
           2   0%        - c-find-decl-spots
           2   0%         - c-bs-at-toplevel-p
           2   0%          - c-brace-stack-at
           2   0%           - c-update-brace-stack
           2   0%            - c-syntactic-re-search-forward
           2   0%               parse-partial-sexp
           1   0%       - c-font-lock-enclosing-decls
           1   0%        - c-syntactic-skip-backward
           1   0%         - c-literal-start
           1   0%          - c-semi-pp-to-literal
           1   0%             parse-partial-sexp
           1   0%         re-search-forward
           1   0%      - font-lock-fontify-syntactically-region
           1   0%       - font-lock-default-fontify-syntactically
           1   0%        - syntax-ppss
           1   0%           parse-partial-sexp
           1   0%     - c-before-context-fl-expand-region
           1   0%      - mapc
           1   0%       - #<byte-code-function FA0>
           1   0%        - c-context-expand-fl-region
           1   0%         - c-fl-decl-end
           1   0%          - c-determine-limit
           1   0%           - c-semi-pp-to-literal
           1   0%              parse-partial-sexp
           1   0%   - #<byte-code-function 88A>
           1   0%    - completion--in-region-1
           1   0%     - completion--do-completion
           1   0%      - completion-try-completion
           1   0%       - completion--nth-completion
           1   0%        - seq-some
           1   0%         - seq-do
           1   0%          - mapc
           1   0%           - #<byte-code-function 35C>
           1   0%            - #<byte-code-function 008>
           1   0%             - completion-basic-try-completion
           1   0%              - try-completion
           1   0%               - #<byte-code-function 704>
           1   0%                - complete-with-action
           1   0%                   try-completion
           0   0%   ...





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-15 14:25     ` Eli Zaretskii
@ 2024-11-15 14:45       ` Alan Mackenzie
  2024-11-15 21:43       ` Björn Lindqvist
  1 sibling, 0 replies; 9+ messages in thread
From: Alan Mackenzie @ 2024-11-15 14:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: acm, Björn Lindqvist, 74357

Hello, Eli and Björn.

On Fri, Nov 15, 2024 at 16:25:39 +0200, Eli Zaretskii wrote:
> > From: Björn Lindqvist <bjourne@gmail.com>
> > Date: Fri, 15 Nov 2024 15:08:09 +0100
> > Cc: Alan Mackenzie <acm@muc.de>, 74357@debbugs.gnu.org

> > > I've wrapped the snippet with 50 foo, and I still don't see any
> > > significant lags.

> > > Does it matter where you type, for reproducing the lag?

> > > Also, can you run this under a profiler (M-x profiler-start) and then
> > > show the full expanded profile produced by "M-x profiler-report" after
> > > several tens of seconds of typing with the lag?

> > > Adding Alan to the discussion.

> > Hello Eli, thanks for the swift reply.


> > I've created a much larger example so you can see what I mean with
> > "wrapping foo in foo":

> > https://gist.github.com/bjourne/8f705c5879aa966accf354008623f6bb

> > Open file in c-mode, Go to line 328, place the cursor on "y" in "dy_dim"
> > and press and hold "y". Unless you have a supercomputer the lag will be
> > really apparent. Disable Global Font-lock mode and repeat the exercise.
> > Lag will be gone. Lag is worse if I use non-jitted Emacs, but really
> > apparent in jitted Emacs too. Lag goes away if I use c-ts-mode instead
> > of c-mode.

> Yes, I see the lag now, thanks; the profile is below.  I'll let Alan
> look into this and see how this can be improved.

Thanks, Eli!  I'll look into this.

> > I want to emphasize that lag is present in normal code too, but easier
> > to detect in these specially crafted samples.

> Can you tell where in real life do you see such deeply-nested braces
> in C source files?

> Here's the profile I collected:

[ .... ]

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-15 14:25     ` Eli Zaretskii
  2024-11-15 14:45       ` Alan Mackenzie
@ 2024-11-15 21:43       ` Björn Lindqvist
  2024-11-16 11:00         ` Eli Zaretskii
  2024-11-28 20:03         ` Alan Mackenzie
  1 sibling, 2 replies; 9+ messages in thread
From: Björn Lindqvist @ 2024-11-15 21:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: acm, 74357

Den fre 15 nov. 2024 kl 15:25 skrev Eli Zaretskii <eliz@gnu.org>:
> Can you tell where in real life do you see such deeply-nested braces
> in C source files?

50 is perhaps exaggerating it, but in "modern" C++ with multiple
namespaces, nested classes, and anonymous functions you can easily get
scopes nested over a dozen levels deep.


-- 
mvh/best regards Björn Lindqvist





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-15 21:43       ` Björn Lindqvist
@ 2024-11-16 11:00         ` Eli Zaretskii
  2024-11-28 20:03         ` Alan Mackenzie
  1 sibling, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2024-11-16 11:00 UTC (permalink / raw)
  To: Björn Lindqvist; +Cc: acm, 74357

> From: Björn Lindqvist <bjourne@gmail.com>
> Date: Fri, 15 Nov 2024 22:43:45 +0100
> Cc: acm@muc.de, 74357@debbugs.gnu.org
> 
> Den fre 15 nov. 2024 kl 15:25 skrev Eli Zaretskii <eliz@gnu.org>:
> > Can you tell where in real life do you see such deeply-nested braces
> > in C source files?
> 
> 50 is perhaps exaggerating it, but in "modern" C++ with multiple
> namespaces, nested classes, and anonymous functions you can easily get
> scopes nested over a dozen levels deep.

Can you show such a file from a real-life project?  I'd like us to
have it as a means for judging real-life performance in these cases.

Thanks.





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-15 21:43       ` Björn Lindqvist
  2024-11-16 11:00         ` Eli Zaretskii
@ 2024-11-28 20:03         ` Alan Mackenzie
  2024-11-29 23:18           ` Alan Mackenzie
  1 sibling, 1 reply; 9+ messages in thread
From: Alan Mackenzie @ 2024-11-28 20:03 UTC (permalink / raw)
  To: Björn Lindqvist; +Cc: acm, Eli Zaretskii, 74357

Hello, Björn.

On Fri, Nov 15, 2024 at 22:43:45 +0100, Björn Lindqvist wrote:
> Den fre 15 nov. 2024 kl 15:25 skrev Eli Zaretskii <eliz@gnu.org>:
> > Can you tell where in real life do you see such deeply-nested braces
> > in C source files?

> 50 is perhaps exaggerating it, but in "modern" C++ with multiple
> namespaces, nested classes, and anonymous functions you can easily get
> scopes nested over a dozen levels deep.

In your test file, near the end, holding down the 'y' key as you
describe, most of the time CC Mode is scanning for brace lists (and not
finding them).  ("Brace lists" are things like the initialisation forms
for structs and arrays, not statement blocks.)

There is a cache mechanism to help reduce this scanning, but with the
deep nesting in the test file, it seems to be ineffective, with elements
of that cache continually being overwritten by new elements.  The cache
currently has just four elements.  Maybe it would be better to increase
that number.  Maybe there's some other problem with the cache.  I'm
looking into it.

> -- 
> mvh/best regards Björn Lindqvist

-- 
Alan Mackenzie (Nuremberg, Germany).





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

* bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag
  2024-11-28 20:03         ` Alan Mackenzie
@ 2024-11-29 23:18           ` Alan Mackenzie
  0 siblings, 0 replies; 9+ messages in thread
From: Alan Mackenzie @ 2024-11-29 23:18 UTC (permalink / raw)
  To: Björn Lindqvist; +Cc: acm, Eli Zaretskii, 74357

Hello again, Björn.

On Thu, Nov 28, 2024 at 20:03:33 +0000, Alan Mackenzie wrote:
> On Fri, Nov 15, 2024 at 22:43:45 +0100, Björn Lindqvist wrote:
> > Den fre 15 nov. 2024 kl 15:25 skrev Eli Zaretskii <eliz@gnu.org>:
> > > Can you tell where in real life do you see such deeply-nested braces
> > > in C source files?

> > 50 is perhaps exaggerating it, but in "modern" C++ with multiple
> > namespaces, nested classes, and anonymous functions you can easily get
> > scopes nested over a dozen levels deep.

> In your test file, near the end, holding down the 'y' key as you
> describe, most of the time CC Mode is scanning for brace lists (and not
> finding them).  ("Brace lists" are things like the initialisation forms
> for structs and arrays, not statement blocks.)

> There is a cache mechanism to help reduce this scanning, but with the
> deep nesting in the test file, it seems to be ineffective, with elements
> of that cache continually being overwritten by new elements.  The cache
> currently has just four elements.  Maybe it would be better to increase
> that number.  Maybe there's some other problem with the cache.  I'm
> looking into it.

It turns out that that cache mechanism was almost totally ineffective.
I've put a new cache into c-inside-bracelist-p.  More precisely, I've
reused an existing cache in a new way.

Would you please apply the patch below to your CC Mode, byte compile CC
Mode, and test it a bit to see if it's fast enough.  (If you want any
help applying the patch or byte compiling the result, feel free to send
me private email.)

Thanks!


diff -r 2c1ba136f3f2 cc-engine.el
--- a/cc-engine.el	Mon Oct 28 15:47:50 2024 +0000
+++ b/cc-engine.el	Fri Nov 29 23:12:27 2024 +0000
@@ -13178,7 +13178,7 @@
 	  (setq c-laomib-cache (delq elt c-laomib-cache)))))))
 
 (defun c-looking-at-or-maybe-in-bracelist (&optional containing-sexp lim)
-  ;; Point is at an open brace.  If this starts a brace list, return a list
+  ;; Point is at an open brace.  If this starts a brace list, return a cons
   ;; whose car is the buffer position of the start of the construct which
   ;; introduces the list, and whose cdr is the symbol `in-paren' if the brace
   ;; is directly enclosed in a parenthesis form (i.e. an arglist), t if we
@@ -13411,14 +13411,19 @@
 	   (t t))))			;; The caller can go up one level.
 	))))
 
+;; A list of the form returned by `c-parse-state'.  Each opening brace in it
+;; is not the brace of a brace list.
+(defvar c-no-bracelist-cache nil)
+(make-variable-buffer-local 'c-no-bracelist-cache)
+
 (defun c-inside-bracelist-p (containing-sexp paren-state accept-in-paren)
-  ;; return the buffer position of the beginning of the brace list statement
+  ;; Return the buffer position of the beginning of the brace list statement
   ;; if CONTAINING-SEXP is inside a brace list, otherwise return nil.
   ;;
-  ;; CONTAINING-SEXP is the buffer pos of the innermost containing paren.  NO
-  ;; IT ISN'T!!!  [This function is badly designed, and probably needs
-  ;; reformulating without its first argument, and the critical position being
-  ;; at point.]
+  ;; CONTAINING-SEXP must be at an open brace, and is the buffer pos of the
+  ;; innermost containing brace.  NO IT ISN'T!!!  [This function is badly
+  ;; designed, and probably needs reformulating without its first argument,
+  ;; and the critical position being at point.]
   ;;
   ;; PAREN-STATE is the remainder of the state of enclosing braces.
   ;; ACCEPT-IN-PAREN is non-nil iff we will accept as a brace list a brace
@@ -13432,32 +13437,42 @@
   ;; speed.
   ;;
   ;; This function might do hidden buffer changes.
-  ;; this will pick up array/aggregate init lists, even if they are nested.
-   (save-excursion
-     (let ((bufpos t)
-	    next-containing)
-       (while (and (eq bufpos t)
-		   containing-sexp)
-	 (when paren-state
-	   (setq next-containing (c-pull-open-brace paren-state)))
-
-	 (goto-char containing-sexp)
-	 (if (c-looking-at-inexpr-block next-containing next-containing)
-	     ;; We're in an in-expression block of some kind.  Do not
-	     ;; check nesting.  We deliberately set the limit to the
-	     ;; containing sexp, so that c-looking-at-inexpr-block
-	     ;; doesn't check for an identifier before it.
-	     (setq bufpos nil)
-	   (if (not (eq (char-after) ?{))
-	       (setq bufpos nil)
-	     (when (eq (setq bufpos (c-looking-at-or-maybe-in-bracelist
-					  next-containing next-containing))
-		       t)
-	       (setq containing-sexp next-containing
-		     next-containing nil)))))
-       (and (consp bufpos)
-	    (or accept-in-paren (not (eq (cdr bufpos) 'in-paren)))
-	    (car bufpos)))))
+  ;; It will pick up array/aggregate init lists, even if they are nested.
+  (save-excursion
+    (let ((bufpos t)
+	  next-containing
+	  (whole-paren-state (cons containing-sexp paren-state))
+	  (current-brace containing-sexp))
+      (while (and (eq bufpos t)
+		  current-brace
+		  (not (memq current-brace c-no-bracelist-cache)))
+	(when paren-state
+	  (setq next-containing (c-pull-open-brace paren-state)))
+
+	(goto-char current-brace)
+	(cond
+	 ((c-looking-at-inexpr-block next-containing next-containing)
+	  ;; We're in an in-expression block of some kind.  Do not
+	  ;; check nesting.  We deliberately set the limit to the
+	  ;; containing sexp, so that c-looking-at-inexpr-block
+	  ;; doesn't check for an identifier before it.
+	  (setq bufpos nil))
+	 ((not (eq (char-after) ?{))
+	  (setq bufpos nil))
+	 ((eq (setq bufpos (c-looking-at-or-maybe-in-bracelist
+			    next-containing next-containing))
+	      t)
+	  (setq current-brace
+		next-containing
+		next-containing nil))))
+      (cond
+       ((and (consp bufpos)
+	     (or accept-in-paren (not (eq (cdr bufpos) 'in-paren))))
+	(car bufpos))
+       ((not (memq containing-sexp c-no-bracelist-cache))
+	;; Update `c-no-bracelist-cache'
+	(setq c-no-bracelist-cache (copy-tree whole-paren-state))
+	nil)))))
 
 (defun c-looking-at-special-brace-list ()
   ;; If we're looking at the start of a pike-style list, i.e., `({ })',
diff -r 2c1ba136f3f2 cc-mode.el
--- a/cc-mode.el	Mon Oct 28 15:47:50 2024 +0000
+++ b/cc-mode.el	Fri Nov 29 23:12:27 2024 +0000
@@ -2313,7 +2313,9 @@
      ;; The following must happen after the previous, which likely alters
      ;; the macro cache.
      (when c-opt-cpp-symbol
-       (c-invalidate-macro-cache beg end)))))
+       (c-invalidate-macro-cache beg end))
+     (setq c-no-bracelist-cache
+	   (c-whack-state-after beg c-no-bracelist-cache)))))
 
 (defvar c-in-after-change-fontification nil)
 (make-variable-buffer-local 'c-in-after-change-fontification)


> > -- 
> > mvh/best regards Björn Lindqvist

-- 
Alan Mackenzie (Nuremberg, Germany).





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

end of thread, other threads:[~2024-11-29 23:18 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-14 20:39 bug#74357: c-mode: Some syntactic constructs cause unreasonable typing lag Björn Lindqvist
2024-11-15  7:40 ` Eli Zaretskii
2024-11-15 14:08   ` Björn Lindqvist
2024-11-15 14:25     ` Eli Zaretskii
2024-11-15 14:45       ` Alan Mackenzie
2024-11-15 21:43       ` Björn Lindqvist
2024-11-16 11:00         ` Eli Zaretskii
2024-11-28 20:03         ` Alan Mackenzie
2024-11-29 23:18           ` Alan Mackenzie

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).