New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memoize syntax-ppss
in a couple places
#629
Conversation
@@ -8062,6 +8072,10 @@ the opening delimiter or before the closing delimiter." | |||
|
|||
(defvar sp-show-pair-enc-overlays nil) | |||
|
|||
(defvar-local sp-last-point nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, we had this variable before, I got rid of it at some point (but it was used for different purpose).
To save the state I've added the defstruct
called sp-state
. Please extend that. I'll slowly refactor all the code to use it as the only source of the buffer-local state (less buffer-local variable = better performance, and we have quite a few).
Also I think we could use better name, this is only related to point at which we test syntax-ppss
, whereas it, at least to me, invokes the idea of the last position of the point before current command.
Otherwise this seems like a fine idea!
@Fuco1 Updated, thanks for the pointer. Please let me know if you'd like me to squash the commits, otherwise I think github's squash and merge would probably do a fine job of it. |
577e3bf
to
8ddd577
Compare
(let ((result (syntax-ppss p))) | ||
(setf (sp-state-last-syntax-ppss-point sp-state) p | ||
(sp-state-last-syntax-ppss-result sp-state) result) | ||
result)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently I could inline the let
and remove the final result
here and it'd do the same thing because of the behavior of setf
of returning the last val. This would be more concise but maybe not more clear if that behavior is not a well known one:
(defun sp--syntax-ppss (&optional p)
"Memoize the last result of syntax-ppss."
(let ((p (or p (point))))
(if (eq p (sp-state-last-syntax-ppss-point sp-state))
(sp-state-last-syntax-ppss-result sp-state)
(setf (sp-state-last-syntax-ppss-point sp-state) p
(sp-state-last-syntax-ppss-result sp-state) (syntax-ppss p)))))
let me know if you prefer this form
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use that often with setq
so I don't think it will be a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, be8e135
I don't see the squash option, the only button available is "Merge pull request". Do I need to enable it somewhere? |
Once you click "Merge pull request" the button changes to one with a dropdown where you can select between the two options. If you don't see the squash option, it can be enabled here: https://github.com/Fuco1/smartparens/settings in the "Merge button" section |
@Fuco1 is something in this branch causing the builds to timeout? I may need a hand diagnosing that.. that seems tricky |
Probably just travis glitches, it sometimes happens. One possible cause I can think of is that while the point might remain the same, the state of the buffer might change (e.g. some character is replaced without the point ever changing position). Then the parse state might change but you never catch it. I don't think hashing the buffer content might be a great idea as that can take quite some time. Maybe checking the buffer-modified flag as well? (I don't know how that behaves with respect to atomicity though... is it only set after the entire series of functions is called from a command or does it really change right after each buffer content change?) |
What about clearing on idle? Seems like a super edge case |
I guess it's not an edge case, there are probably things like revert that could do this? The other option is to build it into a wrapping macro/function like |
I reset the memoization in the post command hook 56c5b74, do you think that is sufficient? |
Is it really? How does that happen? Even if elixir-mode has a relatively slow syntax-propertize-function, if you're calling |
@dgutov Thanks for pointing that out. Seems like it already does some form of caching by default. I've checked the code of
It is probably safer to assume the bug is on our side then. But where could lie the problem (if there even is one??). Tests are green at least. |
@aaronjensen re timeouts, it seems as an infinite loop to me. Aren't you doing some recursion somewhere? Because some half of the tests seem to run and then suddenly it stops. |
@dgutov As a matter of fact, there is a related comment:
I wonder if elixir presents this exact "degenerate" case. Either way, the slow bit is the |
@Fuco1 The tests actually pointed to a problem. Thanks to |
That one test failed before as well. It was introduced by some change in advices which I can't track down. It should be completely unrelated. |
@Fuco1 Maybe the bug is here. A bug is Emacs is also possible (I've only recently found a problem in jit-lock where re-fontifying an already fontified region was an order of magnitude more expensive than it has to be). Finding and fixing it would be a great result. |
When does this happen? Normally,
IIUC, that branch is only taken when |
It doesn't assign it at the end if this is true, which it is in elixir when you're inside a module. (if (and old-pos (< (- pos old-pos)
;; The time to use syntax-begin-function and
;; find PPSS is assumed to be about 2 * distance.
(* 2 (/ (cdr (aref syntax-ppss-stats 5))
(1+ (car (aref syntax-ppss-stats 5)))))))
(progn
(cl-incf (car (aref syntax-ppss-stats 0)))
(cl-incf (cdr (aref syntax-ppss-stats 0)) (- pos old-pos))
(parse-partial-sexp old-pos pos nil nil old-ppss)) I added logging for pos and old-pos and got:
Yes, I think that's correct, that branch isn't taken, the comment just seemed related. Probably it's not. |
What do you mean? Judging by the code, it's always assigned.
Does it take the syntax-ppss-stats branch? |
Not in the true branch of the
Yes, the |
Here is the full code w/ the meaty
|
You're right. That looks like a bug, BTW.
And here, it seems, the performance heuristic misfires. Not really sure about that: maybe it'll be sufficient to set Do you mind filing a "syntax-ppss is slow" bug with a reproducible scenario? What mode to install, what buffer contents to have, that sort of steps. Thanks! |
Something in this pull breaks automatic insertion of |
These places are called many times each operation with the same point. `syntax-ppss` can be slow in some modes, like elixir-mode.
bcedebe
to
0823d01
Compare
This was a red herring. It was actually spacemacs that broke this: syl20bnr/spacemacs#6660 I've rebased this pull request and simplified the condition for adding the reset hook, this should be ready to merge now @Fuco1 |
@Fuco1 this is ready for a merge if you're good with it. Any additional feedback? Thanks! |
I rebased and merged this, thanks! |
@Fuco1 np, thanks for the merge. Btw, Squash and merge does a similar thing as rebasing manually but it marks the pull request as merged, so that's nice for tracking. It won't maintain the commit history, but I wasn't intending to maintain that any way 😄 |
Yea, but it doesn't create a merge commit. I just wanted to move the branch at top. I don't know why they don't provide that option :/ But. I guess I could've just squash it anyway. shrug |
These places are called many times each operation with the same point.
syntax-ppss
can be slow in some modes, like elixir-mode.Before
After
These profiles were taken with #628 included as well.