-
-
Notifications
You must be signed in to change notification settings - Fork 450
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
Registering many errors blocks emacs for a noticeable amount of time #1168
Comments
@jyp Thank you for this issue, but with all due respect I think you're underestimating the issue.
It's not as if we kind of deliberately slowed down error reporting to make someone find that hidden potential. Flycheck uses overlays (they are the only reasonable API for our purposes) which are known to have poor performance. As far as I know they even have quadratic complexity, i.e. adding 1000 overlays is a hundred times slower than adding 100 overlays. Please go ahead and profile our code, but I do think that you'll find a tenfold speedup in there. As for asynchronous reporting, I'm not sure whether that'd fix the issue. We can't add overlays asychronously, so all we'd achieve is splitting a 0.5s freeze into a couple of smaller freezes. |
Spooky. There was some discussion on emacs-devel of migrating overlays to the interval tree used by text properties. @jyp could you try adding @lunaryorn Do you think the issue actually comes from overlay placement, though? IIUC each newly placed overlay requires calling |
@cpitclaudel Overlays in and by themselves are, but that part surely doesn't improve performance. That said, it's the only idea I got to move from lines which is what we get from syntax checkers to buffer positions which is what we need to add overlays. This will always involve scanning over lines. So yes, we could even go as far as to say that adding a Flycheck error has cubic complexity to the number of lines in the buffer. |
Makes sense :) We could shave of a linear factor, though: if errors are on line 1, 5, 9, 153, and 1044, we should be able to just scan from 0 to 1, then 1 to 5, then 5 to 9, then 9 to 153, and finally 153 to 1044, instead of scanning from 0 to 1, then 0 to 5, then 0 to 9, then 0 to 153, then 0 to 1044. This should provide significant time savings; though indeed the quadratic overlays remain |
Relevant thread: http://lists.gnu.org/archive/html/emacs-devel/2016-09/msg00582.html |
@jyp, do you have a concrete example that I could look at? |
I've implemented the change above in branch 1168-faster-overlays. On a 1500-errors python file, overlay placement goes down from 0.24 seconds to 0.08 seconds. @jyp, Can you try that branch out and see whether it helps? @lunaryorn, I've opened a PR#1169 to discuss the change there. |
Ok, I've collected more data on a large buffer. All examples below are with caching on, except the last one:
Interestingly, the line number cache of #1169 only makes a small difference here; if I disable it, I get:
I also ran measurements on a more realistic buffer, with 468 errors (just above our limit of 400 errors):
So the caching in fact makes relatively little difference here. I looked at the C sources, and indeed forward-line already uses a cache (!). So maybe my quick measurements of earlier were not too relevant (?). In any case, all these optimizations together yield an 8 to 9-fold speedup for buffers with huge numbers of errors, and a close-to-2-fold speedup for more reasonable buffers :) It's still far from ideal, because the sheer number of overlays makes Emacs itself slow (very slow in the first case, and a bit in the second one). But at least with these optimizations Flycheck doesn't contribute quite as much :) Do I update PR #1169 to include all optimizations, or do I make separate PRs? And do I remove the line cache, since further testing suggests that it makes at best a small difference compared to the the other optimizations? |
A new profile with all these optimizations on a reasonable buffer suggests that 40% of the time is spent in delete-overlay, 30% in line-end-position, and the rest in various places, so I don't think there's much we can do beyond this. |
@cpitclaudel Impressive work! I'll try it when I get the chance. |
@cpitclaudel 😍 Thanks so much, that's amazing work. Just a quick recap to make sure that I understand things correctly:
Does that more or less nail down your results? |
Absolutely. Based on this, I'd suggest dropping the line cache, and merging 3 and 4. I'll post the files I used for testing so that we can compare results (I'm surprised by the impact of inhibit-field-text-motion). |
Here's the fist, very large file: https://gist.github.com/cpitclaudel/7bb627e25fe5a5027f823e0044e5c82c |
@cpitclaudel Thanks for confirming. I'd suggest to make a separate pull request for recentering and inhibit text field motion and merge that first. Let's keep #1169 open meanwhile; we can reevaluate it after merging the other optimisations. I wonder whether we should look into integrating automated profiles for these critical code paths in our testing on Travis CI 😎 I don't have time to investigate whether and how that's possible, but I hope to find a quiet evening or weekend to go down that road: Looks really interesting, and a thorough profile of Flycheck's critical code paths would probably reveal some other potentials. I didn't particularly care for performance when I wrote Flycheck 😊 Besides, I love how the ELisp reference documents this:
"Can run faster" 😂 Indeed it does; lesson learned: Always read the manual very carefully and to the very end, for the best things seem to be documented in subordinate clauses down at the very bottom of the screen. Gems are always hardest to find 😎 |
Ah, blast, I already edited #1169; let's do it the other way around (I'll open a new PR with the line cache reintroduced after we merge the clear-win optimizations). |
Yup :) When I saw this post I had a vague feeling of "I wonder if I read something about this somewhere" :) |
This sounds like a fun task — and a useful thing to have, too :) |
@cpitclaudel Whatever way you see fit, as long as we've got the commit implementing the line cache available somewhere. Would be a shame if it gets lost, and we later realize that it would have been a good idea |
@cpitclaudel What's the status on that? #1169 has been merged, so has it improved the situation for you @jyp, or are there other venues for optimization? |
I think things are a lot better now. There's ongoing work on the Emacs side to improve overlay performance, and i can't think of much that we could do on our side. That being said, there's still space for improvement for cases where too many errors are reported. We could e.g.
The last two in particular would make things much better when using Flycheck on e.g. large minified javascript files (right now we freeze Emacs for a while just writing the whole file to the checker's stdin) |
@cpitclaudel All of this looks good and doable. I've opened an issue for that. Thanks! |
Thanks! |
This is not so much a bug report, more of a question and perhaps a feature request.
My situation is that I sometimes flycheck big files, which may contain a lot of warnings (maybe a thousand). In this situation, flycheck sometimes blocks emacs for half a second or so. This happens even when the checker is run asynchronously. (I have written my own checker, so I am familiar with the internals. The blocking happens when the
checker
function calls its callback with the list of warnings.)There could be two ways to solve the problem:
checker
function (that which is stored in the:start
property) could call its callback several times. Say, in addition ofwe would have
Perhaps this would be easy to implement? Perhaps there is even a way today to report errors asynchronously? I can offer help implementing the feature.
The text was updated successfully, but these errors were encountered: