smartparens icon indicating copy to clipboard operation
smartparens copied to clipboard

Use input-pending-p to short-circuit sp-show--pair-function

Open aaronjensen opened this issue 6 years ago • 8 comments

sp-show--pair-function can be relatively slow (150ms in some of my files). When using show-smartparens-mode this can be stutters in moving around or typing if it kicks in.

I've had a lot of success increasing perceived performance by monitoring (input-pending-p) in tight loops for things that become irrelevant after the point moves. For example: https://github.com/company-mode/company-mode/pull/720

I tried adding a (not (input-pending-p)) to the and in the while of sp--looking-back and it fixed the stutter for me. I don't know if that's the most appropriate place to put it and/or if that will have bad effects in other was (it probably will). So I'm curious if there's somewhere off of sp-show--pair-function that would be more appropriate to short circuit when there is pending input?

Thanks!

aaronjensen avatar Apr 21 '18 19:04 aaronjensen

Here's a profile fwiw:

- timer-event-handler                                            1737  83%
 - apply                                                         1737  83%
  - sp-show--pair-function                                       1596  76%
   - when                                                        1596  76%
    - if                                                         1595  76%
     - progn                                                     1595  76%
      - sp--with-case-sensitive                                  1595  76%
       - if                                                      1595  76%
        - let                                                    1593  76%
         - save-match-data                                       1593  76%
          - let                                                  1593  76%
           - unwind-protect                                      1593  76%
            - progn                                              1593  76%
             - cl-labels                                         1586  76%
              - let                                              1586  76%
               - let*                                            1586  76%
                - cond                                           1583  75%
                 - funcall                                       1583  75%
                  - #<lambda 0x170d4ad7f9184e28>                 1581  75%
                   - let                                         1581  75%
                    - sp-get-thing                               1581  75%
                     - sp--with-case-sensitive                   1581  75%
                      - if                                       1581  75%
                       - cond                                    1581  75%
                        - if                                     1581  75%
                         - if                                    1581  75%
                          - save-excursion                       1581  75%
                           - cond                                1581  75%
                            - cond                               1581  75%
                             - and                               1578  75%
                              - or                               1578  75%
                               - and                             1578  75%
                                - sp--looking-back               1578  75%
                                 - sp--with-case-sensitive               1578  75%
                                  - if                           1578  75%
                                   - let                         1578  75%
                                    - if                         1578  75%
                                     - save-excursion               1578  75%
                                      - save-match-data               1578  75%
                                       - let                     1578  75%
                                        - unwind-protect               1578  75%
                                         - progn                 1578  75%
                                          - while                1577  75%
                                           - if                  1552  74%
                                            - and                1528  73%
                                               save-excursion               1489  71%

aaronjensen avatar Apr 21 '18 19:04 aaronjensen

Oh this is interesting.

We are using a timer to start the "show job" after 0.125s of inactivity which is enough for most people's typing speed, but when navigating around I can see how you might fall into that interval and get blocked.

I don't know where to put the short circuit, but I would most definitely not put it inside the sp--looking-back function. I'm probably misunderstanding you though.

Can you open a pull request with your change? I like the proposal and it seems you have a solution so I'll be very happy to move this forward.

Fuco1 avatar Apr 21 '18 21:04 Fuco1

I think another question is... why does this js file (rjsx-mode) that I have run so many loop iterations:

;; within the sp--looking-at-p while loop:
                (message "%S %S %S" regexp limit sp-max-pair-length)
"\\(?:\\(?:\\(?:\\\\\\(?:\\\\[()]\\|[(){}]\\)\\|[]()<>[{}]\\)\\)\\)" 10 10 [10 times]
"\\(?:\\\\\"\\|[\"'`]\\)" 10 10 [10 times]
">" 10 10 [10 times]
"</?" 15222 10 [15222 times]
"\\\\" 2 10 [2 times]

aaronjensen avatar Apr 22 '18 01:04 aaronjensen

I've been experiencing dropped keystrokes on Windows when typing quickly and bisecting led me to suspect smartparens. Adding this change eliminated the drops in buffers. Now Emacs hangs for a second but then will finish accepting characters. Before it would ignore any keystrokes from during the hang. However, I'm still experiencing dropped keystrokes while isearching which may or may not be related. I know that some of my packages have exhibited weird performance due to Windows Emacs' GC peculiarities.

In any case would like to move this issue forward, let me know what the best way to help is.

jaccarmac avatar Aug 02 '18 19:08 jaccarmac

/cc #943

Fuco1 avatar Dec 12 '18 19:12 Fuco1

Not on Windows any more so I can't say if it fixed my usecase or not. I'll update and cross my fingers though!

jaccarmac avatar Dec 13 '18 00:12 jaccarmac

What's the current status on this? As far as I could find, the while-no-input solution was merged and reverted because it was causing bugs. The solution suggested here might not be as pretty, but it seems to do the job. Does it cause the same bugs?

I guess that the best solution to the underlying problem would be to run it asynchronously and interrupt it if no longer necessary (e.g. point moved or text inserted), but it is also a lot more complicated. Adding short-circuits seems to work as a cheaper work-around.

The emacs manual has this warning:

Do not write an idle timer function containing a loop which does a certain amount of processing each time around, and exits when (input-pending-p) is non-nil. This approach seems very natural but has two problems:

  • It blocks out all process output (since Emacs accepts process output only while waiting).
  • It blocks out any idle timers that ought to run during that time.

It's not quite the same situation, but it means that the function will still block some emacs functions while running. Sadly, the manual doesn't seem to offer any alternative.

ThibautVerron avatar Oct 31 '20 12:10 ThibautVerron

@ThibautVerron It's likely that https://github.com/Fuco1/smartparens/pull/958 is still the best option. Now that Emacs 27 is released, we could pull the actual release version if it's any different and use that.

I've rebased the PR and confirmed that while-no-input is the same version as in Emacs 27.1

aaronjensen avatar Oct 31 '20 17:10 aaronjensen