Skip to content
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

Default behavior of deleting/recreating ipch Intellisense files is a bug for large projects #5522

Closed
boocs opened this issue May 18, 2020 · 10 comments

Comments

@boocs
Copy link

boocs commented May 18, 2020

Type: LanguageService

Describe the bug

  • OS and Version: Windows 10 1909

  • VS Code Version: 1.45.1

  • C/C++ Extension Version: 0.28.0

  • Any change to a header, that a cpp file includes, causes it’s default individual Intellisense ipch file to be deleted and recreated.

  • This results in deleting and recreating it’s default Intellisense file multiple upon multiple times with every change.

  • This is normal because it happens with barebones projects.

  • This should be considered a bug on large projects.

On large projects, default individual ipch Intellisense files can be ~1 Gigabyte in size. Deleting and recreating this default Intellisense file at these file sizes causes Intellisense to stall until done. About 20 seconds.

  • If you rename the same header file, so that no cpp file includes it, the default Intellisense file it creates is about 0.2 Gigabytes and Intellisense doesn’t stall on changes. 0.3 seconds vs 20 seconds. Intellisense now seemingly works great on the header.
    It also modifies the default Intellisense file instead of deleting it and recreating it.
    The header needs to include another header for this to work so I’m guessing it’s just acting how a source file acts now that nothing includes it.

  • Modifying the source file(cpp) doesn’t seem to have this issue. It’ll modify the ipch Intellisense file instead of deleting and recreating.

Steps to reproduce

  1. Blank test.h and a test.cpp that has #include “test.h”
  2. Switch back to test.h
  3. Create a float foo;
  4. TEST.ipch is deleted and recreated.
  5. Create another float bar;
  6. TEST.ipch is deleted and recreated.
@sean-mcmanus
Copy link
Contributor

You're describing "by design" behavior. Project size doesn't matter, just the size of the TU (i.e. source and and all it's dependent includes)...unless you're using recursive includes and you see cpptools using CPU instead of cpptools-srv (in which case project size would matter, but IPCH files are not relevant in that case). The reason compiling the header by itself is fast is because it's not parsing all the other parts of the TU from the source file. The IPCH files just makes updating of the source file faster as you observed. The basic performance and implementation is derived from VS.

@boocs
Copy link
Author

boocs commented May 19, 2020

  • In Windows 10 Resource monitor 3.76 average for cpptool-srv 2.56 for cpptools. I created two floats in a header class in a Unreal Engine 4 project.

  • So for now if you wanted to save some hard drive writes, while creating headers, it would be better to run with Intellisense cache set to 0. I tried it quickly and it didn't seem to effect performance.

  • I guess I could try creating a simple extension where you can hotkey toggle the name of your header file. Seems like this should get you fast header Intellisense with the testing I did.

@boocs boocs closed this as completed May 19, 2020
@sean-mcmanus
Copy link
Contributor

Oh, you're saying when edits to a header file occur we should disable the IntelliSense cache for that TU? That would prevent the unnecessary disk writing. I think turning the cache off/on requires restarting the IntelliSense process though.

@boocs
Copy link
Author

boocs commented May 19, 2020

Yeah that would be nice to have an auto switch option for headers!

For now I'll just run with "C_Cpp.intelliSenseCacheSize": 0 on all the time.

Of course this doesn't fix the Intellisense header performance issue. Hopefully my silly extension idea works for that.

@boocs
Copy link
Author

boocs commented Jun 11, 2020

I've thought about different ways to do this. Hopefully this is all possible in an extension until this gets fixed. I had another project that I finished so now I can try this.

  1. Mentioned before, temporarily change "C_Cpp.intelliSenseCacheSize" to 0 when you switch to a header file.

This fixes the massive writes issue but doesn't help header Intellisense slowness.

  1. Temporarily change C_Cpp.intelliSenseEngine to 'Tag Parser' when you switch to a header file.

Fixes write issue and speed issue. Not sure how much you'd miss the 'default' Intellisense when writing headers. Would have to test.

  1. My rename header idea. Probably dead.

@boocs
Copy link
Author

boocs commented Jan 14, 2022

I did end up writing that extension: https://github.com/boocs/fast-header-intellisense

It's ok. The only problem is no default Intellisense error messages can cause confusion when switching back to source files. It also requires a workspace config file.

Any possibility of adding this feature natively? A native option can remove the quirks from the extension version. Maybe it's also possible for an option of header files having speedy Tag Parser completions + Default Intellisense error squiggles.

For Default Intellisense, I think I've figured out a way to give source file speed to header files by using old symbols and not updating the code completion symbols every time you type in a header. It's a little 'hacky' but the proof of concept seems to work. I still need to write the extension. I've only tested it on Window with cl.exe and clang and c++14. I'm sure they concept will fail at some point but I'm sill going to try.

I'm wondering if it's possible to get this additional mode added natively for Default Intellisense?
For header code completion, symbols will only get updated after a manual command or by switching to a source file. Some people ,when writing a header file, don't need the updated symbols until switching to the source file. The error squiggle will still be updated as you type.

Thanks!

@sean-mcmanus
Copy link
Contributor

It would be possible/simple to have a C_Cpp.autoComplete "Tag Parser" setting -- we recall we talked about that previously, but decided against it (our extension already falls back to the tag parser completion when IntelliSense completions aren't available for various reasons).

I don't understand what you mean by "updating symbols", when you type, IntelliSense will update symbols and errors in the background (they're connected), but it'll also re-tag parse for global symbols (i.e. symbols in the Outline view, not local scope symbols), which is separate.

I'm not sure how your extension works, but you might want to consider a PR to our extension with some special "intelliSenseEngine" "sourceOnly" mode if you hit any maintenance issues related to our extension switching to per-OS marketplace vsix's.

It seems like it could be implemented natively, but it's not on our list of stuff to add soon.

@boocs
Copy link
Author

boocs commented Jan 15, 2022

Large project header file, Default Intellisense, auto completion is too slow. Or maybe it's just an Unreal Engine project issue. Unreal Engine project code completion, for headers, has always taken between 6-25 seconds for the completion window to pop up making it unusable. That's what prompted me to create the extension.

I meant a Default Intellisense mode like this:

  1. Switch to header and gather code completion symbols
  2. Never update the code completion symbols again until
    I. You manually do it with some command you add
    II. Default rules you already have when switching files
  3. Code completion will always use the symbols list that loaded when you first switched to the header.
  4. Still if possible provide updated error squiggles as you type in headers.
  5. A lot of people don't need a constantly updating symbol list when writing a header file.
  6. I know this slowness probably only affects very large projects so probably not beneficial to add to cpptools but would be nice. Never hurts to ask!

My new extension idea and proof of concept mimics this behavior and seems to work. Less than 2 second code completion when writing headers in an Unreal Project(with code completion delay set to 750). This is also with Intellisense cache off.


Here's the silly way I mimic this. If you want, please tell me some obvious reason this would never work. Just remember I know this is dumb :)

You create a separate source(cpp) file and copy the header inside it. The class declaration has to be inside a function. The #include statements have to be outside the function. This all is wrapped in a #ifdef __INTELLISENSE__

You'll still have to be able to exclude the directory these files would be in when building. I should be able to create an error if the files are ever compiled. Also some quirks would be some macros aren't liked. Like a macro in Unreal that uses the __LINE__ macro(it's fine in normal headers). This isn't a deal breaker.

@sean-mcmanus
Copy link
Contributor

I think the performance issue would be fixed by #3628 .

Are you talking about global symbols/completion or member scoped completion? It sounds like you're referring only to the global scope symbols.

The IntelliSense updating isn't just for updating the symbols, but also for error squiggles too, which I'm guessing would also be slow in your scenario.

@boocs
Copy link
Author

boocs commented Jan 18, 2022

Yeah it should since Unreal does create a 1GB+ pch file in it's default build setting.

I won't be creating the 'hacky' extension but I've been learning about libclang and it's completion ability. Better use of my time learning about the issue.

@boocs boocs closed this as completed Jan 18, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Mar 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants