abingham / emacs-ycmd

Emacs client for ycmd, the code completion system.
MIT License
383 stars 46 forks source link

Performance issues #416

Closed quicknir closed 7 years ago

quicknir commented 7 years ago

I'm using ycmd in quite a large project, where single TU's tend to be rather large as there are many #includes. I have auto completion set to only occur when I hit C-tab, which is bound to this:

      (defun ycm ()
        (interactive)
        (company-cancel)
        (let ((ycmd-force-semantic-completion (not (company-ycmd--in-include))))
          (setq company-backend 'company-ycmd)
          (company-manual-begin)))

As was suggested here in an earlier issue.

I don't begrudge ycmd taking a moment or two when I manually ask for auto completion. However, even when I don't ask for auto completion, ycmd is constantly causing long delays. Like the world will just freeze for 2 seconds. I have ycmd flycheck and ycmd eldoc running. Are there any settings that I can try messing with which will help with this issue? Is there any easy way to use the logs to verify which exact component is causing the delays?

abingham commented 7 years ago

emacs-ycmd itself should be pretty good about doing its work asynchronously; at least, that's the plan! So my first guess is that the delays are coming from either ycmd-eldoc, flycheck-ycmd, or the company integration stuff. I would start by deactivating each of these in turn to see if one of them is the culprit. I would guess it's sufficient to just turn off eldoc-mode, flycheck-mode, and company-mode to accomplish this.

You might start with ycmd-eldoc. It contains a synchronous call to ycmd-get-completions, and that's a bit suspect to me. The company-ycmd also contains a synchronous call, but it looks like you've got company under control already.

I wish I could give you better advice right now, but there are a lot of moving parts with the ycmd ecosystem. Hopefully we'll get this sorted for you.

ptrv commented 7 years ago

Yes, my suggestion would also be to disable ycmd-eldoc first, because it's making a completion request for each symbol your cursur is on.

It contains a synchronous call to ycmd-get-completions, and that's a bit suspect to me.

That's not the case anymore. We changed it recently to a async call.

The thing is also that I'm also using emacs-ycmd in a quite large c++ project with lots of includes and with the boost library, but haven't experienced your particular issue. Since we have an async call in ycmd-eldoc I also have it enabled in that project.

Can you maybe provide more infos about your setup? And maybe the values of any customizable emacs-ycmd setting that is not default?

quicknir commented 7 years ago

Nah that's a great first answer, I will give that a shot. I've been suspicious of eldoc-mode in fact, but turning it off didn't seem to actually turn anything off (maybe it's one of those things where it has to be off before the buffer starts). @ptrv Yes I will write back with more details about variables that I have set, maybe I misunderstood one of them.

abingham commented 7 years ago

That's not the case anymore. We changed it recently to a async call.

Ah, right, sorry about that!

quicknir commented 7 years ago

Things I've changed that have even the tiniest chance to be related:

  (setq company-ycmd-request-sync-timeout 1.0)
  (setq ycmd-parse-conditions '(save new-line mode-enabled idle-change))
  (setq ycmd-idle-change-delay 2.0)

That should be it, I think. In what version of ycmd was the eldoc sync/async fixed? I'm running ycmd-20161222.1039.

ptrv commented 7 years ago

Your version is quite old. Please try out the latest versions of all ycmd packages.

ptrv commented 7 years ago

(setq company-ycmd-request-sync-timeout 1.0)

This is sending a blocking completion request and blocks up to 1 second and if completion takes longer the blocking request is dismissed and another non-blocking is sent. For large project I recommend to set it to 0, so you only have an async request for completion.

Also set ycmd-idle-change-delay to a higher number so, you don't have many file parse requests. Actually since one of the last commits we check the buffer modified time and if it hasn't changed we don't reparse the file.

Or remove idle-change from ycmd-parse-condition. I however use it also in my large c++ project but with ycmd-idle-change-delay set to 4 seconds. It's working fine.

But I think the major thing is ycmd-eldoc. Your version still has a blocking call and for large projects it will "freeze" Emacs.

Please update all your ycmd packages and see if the issue still exists.

quicknir commented 7 years ago

I've upgraded, I didn't have much time to test before I left work (Sing time), Monday I'll either close this or update with more information.

@ptrv Yes, but based on the name I'm assuming this timeout is used only for company, and not for flycheck or eldoc? The thing is, I only use ycmd's completer manually, I have simple identifier based completion for automatic. So if I hit the auto completion shortcut, I am generally fine with waiting a second, because that means I really want semantic auto completion. If I knew what to type I would just type it (and usually the identified based completion would help me). This may seem odd but I just found that ycmd wasn't fast enough; if it started automatically then it would cause stuttering even in situations where I knew exactly what to type (which is often... can I get a v.push_back(x) from my fellow programmers?). I may give it another shot with the settings you suggest, we'll see.

What's the interaction between ycmd-idle-change-delay and the flycheck delay? If I have the former set to 4 seconds, and the latter to 2, won't flycheck anyway need to reparse the file after 2 idle seconds to update error messages?

abingham commented 7 years ago

What's the interaction between ycmd-idle-change-delay and the flycheck delay?

The ycmd-idle-change-delay is the important variable here, I think. flycheck-idle-change-delay should never trigger a re-parse. flycheck-ycmd is passive in the sense that it only receives parse results when ycmd has some to offer. So the ycmd-parse-conditions and related control variable are the ones to worry about in your case, I think.

quicknir commented 7 years ago

So far it seems the perf is better, thanks for pointing me towards updating. However, my company completion is no longer occurring synchronously. So what is happening now is that I type some variable out quickly and hit C-\<tab>, and it immediately responds with "No completion found". So I end up having to hit C-\<tab> a couple more times (waiting briefly each time) so I can get the completion as soon as the parse finishes. company-ycmd-request-sync-timeout is still 1.0 so I'm not sure why this is happening.

abingham commented 7 years ago

I don't have a C++ project big enough to trigger what you're seeing, but it looks like company is what produces that message. I guess that it immediately realizes that it doesn't have a completion for, prints that message, and returns back to ycmd. So the timeout you've got is short-circuited: since company isn't waiting for results, then it's effectively ignored.

With that said, since I can't really reproduce what you're seeing I could be way off base.

ptrv commented 7 years ago

@quicknir Can you disable ycmd-eldoc and see if it works again as it used to. It might be that completion request are interfering because ycmd-eldoc sends out a completion request asynchronously and the you try to complete synchronously.

quicknir commented 7 years ago

@ptrv Very nice catch. Indeed it is exactly as you say. I guess the question then: is there an easy way of changing this behavior?

ptrv commented 7 years ago

Ok, thanks for testing. I have to think about it and find a solution to manage the completion requests better for company and eldoc so that they don't interfere.

quicknir commented 7 years ago

@ptrv Alright, cool, thanks for your help. If it helps, I can close this issue and open a new one where I have a more appropriate title and concise summary. Cheers.

ptrv commented 7 years ago

If it helps, I can close this issue and open a new one where I have a more appropriate title and concise summary

Would be great, thanks.