-
Notifications
You must be signed in to change notification settings - Fork 63
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
Faster completions #65
Conversation
32944bc
to
99adfb2
Compare
(if (string= cmd "completion") "filter=StartsWith" "")))) | ||
(let ((linestr (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) | ||
(log-psendstr fsharp-ac-completion-process | ||
(format "%s \"%s\" \"%s\" %d %d %d %s\n" cmd file linestr line col |
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.
probably need a better way to escape the linestr here.
Reducing the idle delay means the popup is triggered faster, but then we lose the benefit of the StartsWith filter which seems to help a lot with the deserialization cost for large lists. |
These PRs definitely aren't ready to be merged. I just submitted them so that you could try them out and get a feel for the difference. There are problems with this approach, e.g. lambda completions don't work so well now. Maybe a parse command could be triggered when typing |
I also had the idea of serializing directly to an elisp structure. Emacs seems to struggle with large json objects. No idea if it would help or not. |
That is an interesting idea, I can imagine it might help quite a bit. We could also trigger parsing after shorter idle delays perhaps? I'll give it a go and see how it feels. |
I noticed too that emacs doesn't use all the columns that are returned by autocomplete. Maybe we could specify on the request which columns we want? |
It's possible, but it would complicate the serialization code in FsAutoComplete quite a bit. I'm surprised that the deserialization is so slow. |
As far as I can tell, the only time the parse step is needed is at the start of a new line and moving into a new lambda context. |
For me completion is quite fast. I instrumented the
So handling of the completion response just takes 0.086 seconds in the whole System namespace. |
Looks to be a lot of time sunk on reading json there. This PR is about speeding up the time between calling fsharp-ac-make-completion-request and getting the response on fsharp-ac-handle-completion. I don't think that you are measuring that. |
Yes. Because the request/respone is async the results just reflect the time spent on the Elisp side. I wonder whiy
What's also interesting is the fact, that most time of
|
Maybe we should start a new ticket to talk about serialization. This PR wasn't meant to be about that. Nor am I saying it's slow. Just that it can be faster :) In my mind, it should be almost as fast as XS. This is a gif recorded from F# interactive in my latest code from Xamarin Studio. These completions are also out of process and there is almost zero lag. |
The optimisation that I'm describing here is the same one that has been in Xamarin Studio for a few weeks now and it's made a dramatic improvement there. |
👍 @rneatherway fsprojects/zarchive-fsharpbinding#233 But i can't complete backticked identifiers. Can you confirm? Maybe reopen? |
@juergenhoetzel can you confirm if the json-read times are from emacs-fsharp-mode or from something else? Regarding This duplication could probably be removed too and maybe replaced with a bool flag |
This is possible, but historically it was also necessary to use it so that
Where |
I can confirm the times are from Now I evaluated:
and so profiled only completion handling:
|
@rneatherway Yeah... that makes sense. It's also currently being used to parse every completion returned here emacs-fsharp-mode/fsharp-mode-completion.el Line 372 in 7389ac8
@juergenhoetzel That's interesting. Looks like around 80% of the processing time in emacs is spent parsing json. |
Thanks so much for putting some hard numbers on this guys, it's really helpful. @nosami I agree changes to the serialization would be a different PR. We just need to nail down escaping of double quotes in the lineStr here. As I said on the other PR either backslashes or using JSON in both directions would work. What do you think? I did find one slightly annoying case where I type:
Just after I press the I was testing the lambda completion like you suggested, and when I put |
This is what I meant about triggering a parse as soon as
This is probably a good idea. My biggest worry about this is that the other editors would need to change too. |
Yes, good point. We've looped in @ionide, so that part is fine, we need to check with @kjnilsson for VIM, and @guillermooo for Sublime (although I think that is dormant). They will continue to work with their version of FsAutoComplete until they upgrade, so it won't affect existing functionality. I think the change is small enough (as long as the escaping is easy). |
This would require an FParsec change in FSAC. I'm not so good with that yet :) |
@rneatherway My plan is to resume work on the Sublime plugin, but I don't know when yet 😢 Feel free to make breaking changes, as I intend to rewrite a good deal of the plugin anyway, 😱 including the interaction with fsac. |
This makes things a fair bit more complicated as vim is not async I want to interact with fsac as little as possible, especially when editing text. I assume I can still keep my current reparse strategy just add the additional current line? Parsing on going into insert mode doesn't make sense as I only display errors in normal mode. |
@guillermooo both fsautocomplete and FSC are both line based. You can probably make it work somehow though. @kjnilsson Yeah... you don't need to make any other changes if you don't want to other than adding the line text. Parsing on entering normal mode will probably work too. This change means that you need to interact with fsautocomplete less than you do now. |
@nosami doesn't this mean I have to reparse the file for each line edit in insert mode? currently I don't parse at all in insert mode unless completion is requested. I will give it a go and see how it works out but as long as I can keep my current strategy in case it doesn't then I'm all for it. |
No.... So - right now, when you press tab with supertab or whatever, you issue 2 commands, If you implement this, then on the first completion on a line, you would invoke |
AAH! I get it now. doh. :) |
Wow, looking really great! Do you not need to send the |
Yeah. The PosCommand code is common between those commands, so that works by default :) I think the typesig command was slowing completions down previously. |
Oops obviously! Thanks. |
Happy to merge this and the FSAC PR once the tests pass. Thanks for working on this! |
Cool... It's almost done. Just need to reparse on I also spotted a bug that must have been there before (maybe introduced in my company PR) but needs fixing. If you have a line like this I also figure there could be another gain to be had by not requiring the initial parse on a line if the background parse was triggered there. |
I suppose if you close a bracket then that will indicate that a new typed expression could do with being given a type, so that it one possibility. Are you thinking of triggering the parse immediately? For large files it could be a bit of an issue due to Emacs being single-threaded. Parsing on idle isn't really noticeable, but in the middle of typing it might be. Of course, if we could just send differences that would be great, but a) each editor would be different, b) I don't know how to get that info easily in Emacs, and c) it's a separate PR if at all! Ah, I hadn't seen that bug, but yes it would be good to fix. |
Yeah, I was thinking of issuing a parse as soon as I already have some code for sending changes as they happen for Emacs. This is usually a single keypress and location, but can be a selection replacement etc too. It means that the server always has the same state as the editor. Now that we aren't sending the buffer for each completion request, I'm not so sure it's needed any more. It would definitely need to be a separate PR :) |
I just had an idea. Now we are sending the lineStr with requests, it should be possible to do a background parse in FSAC with the new reconstructed source without it affecting the editor at all. This would probably help with the |
in fsharp-ac-residue
The tests are passing for me locally when I run against my locally compiled FSAC. |
Thanks a lot for this! |
Thanks for merging / testing :) On Tue, Apr 5, 2016 at 8:37 PM, Robin Neatherway notifications@github.com
|
I just tried with the new 0.28 release. And got:
Any hints appreciated. BTW. Seems the version Info-String wasn't updated in the 0.28 release:
|
Are you on the master branch of emacs-fsharp-mode? Background parse is working here with the MELPA build.
|
Yes, master branch, commit 70c238e |
Deleted any |
Sry 😢 I had a long day. Indeed i had outdated elc files. I was misled by the outdated version string. |
@juergenhoetzel you are 100% right about the version string issue though, I am looking into that thanks! |
This makes completions faster by not requiring a full parse to complete before issuing completions.
We parse once per line, and subsequent requests send the lineStr to FSAC. Corresponding FSAC PR incoming.