Open mcclure opened 1 year ago
In addition, chokidar actually does seem to do quite a bit of activity when I do hg commit
. As Sublime does, rust-analyzer should also probably by default be ignoring common version control directories such as .hg
, .git
etc.
Rust registers watcher for all *.rs files in all directories within the project basically:
{
"registrations": [
{
"id": "workspace/didChangeWatchedFiles",
"method": "workspace/didChangeWatchedFiles",
"registerOptions": {
"watchers": [
{
"globPattern": "/usr/local/workspace/temp/rs-hello/**/*.rs"
},
{
"globPattern": "/usr/local/workspace/temp/rs-hello/**/Cargo.toml"
},
{
"globPattern": "/usr/local/workspace/temp/rs-hello/**/Cargo.lock"
}
]
}
}
]
}
There is only one *.rs file (rs-hello/target/debug/build/thiserror-3f11b3c4b8efe876/out/probe.rs
) in the target
directory here but I guess setting up a watcher for that directory could still cause extra CPU usage.
I could experiment with overriding the pattern and checking if it still reproduces but I would need a better way to reproduce because here building takes very short time and I don't see a major increase in CPU usage. Also the build directory takes just ~300MB here. Also cargo build
takes basically no time if project is already built. I've tried cargo clean
first and then cargo build
but it still doesn't really reproduce.
In addition, chokidar actually does seem to do quite a bit of activity when I do
hg commit
. As Sublime does, rust-analyzer should also probably by default be ignoring common version control directories such as.hg
,.git
etc.
By default patterns from those global ST settings are ignored:
// folder_exclude_patterns and file_exclude_patterns control which files are
// listed in folders on the sidebar. These can also be set on a per-
// project basis.
"folder_exclude_patterns": [".svn", ".git", ".hg", "CVS", ".Trash", ".Trash-*"],
"file_exclude_patterns": ["*.pyc", "*.pyo", "*.exe", "*.dll", "*.obj","*.o", "*.a", "*.lib", "*.so", "*.dylib", "*.ncb", "*.sdf", "*.suo", "*.pdb", "*.idb", ".DS_Store", ".directory", "desktop.ini", "*.class", "*.psd", "*.db", "*.sublime-workspace"],
But note that ignoring doesn't mean that the directory won't be watched. It just means that any matching file changes will be filtered out and won't be reported to the LSP server. If the main watch pattern includes those then the OS-specific file watching implementation will likely still watch those and might cause higher CPU usage. It would have to be verified whether that's the case though and it also can differ per OS.
There is only one *.rs file (rs-hello/target/debug/build/thiserror-3f11b3c4b8efe876/out/probe.rs) in the target directory here but I guess setting up a watcher for that directory could still cause extra CPU usage.
As you can see in the screenshot, rust-analyzer.exe is taking up little or no CPU during this time. All the CPU cost is chokidar (the watcher). So the problem is not probe.rs, it's the directory as a whole.
I think it would make sense to put target into "folder_exclude_patterns". However, if Chokidar is expending significant resource usage even on the already excluded folders such as .hg
and contents of "folder_exclude_patterns", then maybe the bug is on chokidar or lsp-file-watcher-chokidar. Maybe I should be filing there :(
ignoring doesn't mean that the directory won't be watched. It just means that any matching file changes will be filtered out and won't be reported to the LSP server
Looking, I find chokidar has a documented "ignored" option in its options structure.
Looking, I find LSP-file-watcher-chokidar has an "ignores" option in its options structure which gets translated to chokidar "ignored".
It sounds like these flags should be enough to prevent the behavior I am trying to avoid (heavy CPU usage from chokidar watching unimportant directories).
I am not familiar with the stack but looking at the LSP-rust-analyzer code I do not find lsp-file-watcher-chokidar's "ignores" getting set, and based on your comment it seems you believe you are not setting such a flag. Do (lsp-rust-analyzer settings / ST global) folder_exclude_patterns get passed to LSP-file-watcher-chokidar "ignores"? If not, could they be?
There is only one *.rs file (rs-hello/target/debug/build/thiserror-3f11b3c4b8efe876/out/probe.rs) in the target directory here but I guess setting up a watcher for that directory could still cause extra CPU usage.
As you can see in the screenshot, rust-analyzer.exe is taking up little or no CPU during this time. All the CPU cost is chokidar (the watcher). So the problem is not probe.rs, it's the directory as a whole.
I think it would make sense to put target into "folder_exclude_patterns". However, if Chokidar is expending significant resource usage even on the already excluded folders such as
.hg
and contents of "folder_exclude_patterns", then maybe the bug is on chokidar or lsp-file-watcher-chokidar. Maybe I should be filing there :(
You can try yourself putting target
in global folder_exclude_patterns
. You will not see that folder in ST's project view also then. And as a bonus avoid ST indexing it.
(Note that a better place for adding this exclude would be project settings but unfortunately LSP doesn't respect those for the purpose of file watching currently.)
I am not familiar with the stack but looking at the LSP-rust-analyzer code I do not find lsp-file-watcher-chokidar's "ignores" getting set, and based on your comment it seems you believe you are not setting such a flag. Do (lsp-rust-analyzer settings / ST global) folder_exclude_patterns get passed to LSP-file-watcher-chokidar "ignores"? If not, could they be?
Base LSP package creates the watcher in: https://github.com/sublimelsp/LSP/blob/0d149265408824b73184709619af4497d9044650/plugin/core/sessions.py#L1492-L1493
If ignores
is not specified in watcher settings then it defaults to global ignore rules: https://github.com/sublimelsp/LSP/blob/0d149265408824b73184709619af4497d9044650/plugin/core/sessions.py#L1507-L1518
It sounds like these flags should be enough to prevent the behavior I am trying to avoid (heavy CPU usage from chokidar watching unimportant directories).
As I've mentioned before, setting ignores
might not help the CPU usage if the parent folder is being watched. Depending on OS-specific implementation, the watcher will likely still need to be set up and include all child folders. Only that chokidar will filter out those event later. Windows might be especially inefficient here but I'm speculating.
Okay, so there are a few things going on here. There are two questions I think are worth asking:
You can try yourself putting
target
in globalfolder_exclude_patterns
. You will not see that folder in ST's project view also then. And as a bonus avoid ST indexing it. (Note that a better place for adding this exclude would be project settings but unfortunately LSP doesn't respect those for the purpose of file watching currently.)
Talking about question 1: Sublime Text has three different ignore settings.
My "expected behavior" (in addition to including target/, and maybe pkg/ and node_modules/ in the ignore defaults) is that you should be passing folder_exclude_patterns and index_exclude_patterns to Chokidar to be ignored. Using my configuration as an example, I have .hg in folder_exclude_patterns, but I have target/ in index_exclude_patterns but not folder_exclude_patterns (because I don't want it to track those files, but I might occasionally want to inspect a build product in the sidebar).
Question 2— I will try testing putting target/ in folder_exclude_patterns and see if anything changes. If the problem persists I will file that bug on chokidar because I think there are ways they could handle this correctly regardless of OS.
Question 2— I will try testing putting target/ in folder_exclude_patterns and see if anything changes. If the problem persists I will file that bug on chokidar because I think there are ways they could handle this correctly regardless of OS.
That sounds very optimistic :) Chokidar is 11 years old. I'd think that they have figured out the most efficient ways of handling things by now.
Its readme states:
On most other platforms, the fs.watch-based implementation is the default, which avoids polling and keeps CPU usage down. Be advised that chokidar will initiate watchers recursively for everything within scope of the paths that have been specified, so be judicious about not wasting system resources by watching much more than needed.
The pattern that rust-analyzer chooses to watch is [...]/rs-hello/**/*.rs
which means that the whole rs-hello
folder and all subfolders need to be watched recursively. Even if target
directory is excluded using ignores
, I'm pretty sure that the implemenation might have to watch it anyway and just filter out all events after they happen.
But feel free to create issue there to discuss it. You can probably reproduce the same using chokidar-cli which would be easier for authors of chokidar to reason about.
BTW. Maybe you can tell rust to create build files outside of the project directory? Then you could workaround the issue that way.
I have a rust project that uses wgpu. WGPU results in the
target/
being very very large, like 4GB even though the executable is much smaller.I have noticed whenever I do a
cargo.exe run
orcargo.exe build
on this project in a terminal window, if I have Sublime Text open, it suddenly slams to 100% CPU and stays there for some time. This causes problems for the build, which is noticeably slowed down by the Sublime Text CPU peg, as well as for my program, as it has a very low framerate right after it opens (due to the CPU being taken up by Sublime). If I do "LSP: Disable Language Server" before I do the build, I do not seem to see this problem. My Rust helper plugin is preventing me from running Rust.If I have Task Manger open, I see basically all of this stems from a nodejs subprocess of Sublime Text:
If I look in Process Explorer, I see the problematic node is executing something called "lsp-file-watcher-chokidar", which I am told is a common helper for sublime lsp for watching for file changes.
I believe that rust-analyzer has spawned this chokidar to check for .rs files changing, but it has failed to configure the
target/
directory to be ignored. Therefore, when my build starts changing many files rapidly insidetarget/
, it does a lot of unnecessary work.Expected behavior: Because rust-analyzer is designed to assist with Rust, it should predict the
target/
directory exists and configure chokidar to ignore it by default. In general it should be possible to configure lsp-rust-analyzer to ignore build artifact directories liketarget/
,pkg/
or (for wasm-bindgen projects)node_modules/
.Configuration: I am on Windows 10 Build 19045. I have Rust 1.69.0, Sublime Text 4143, LSP v1.23.0, LSP-rust-analyzer v1.3.1, LSP-file-watcher-chokidar v1.0.2. My settings contains
Without
index_exclude_patterns
, Sublime Text does its own chugging during the build, but with this setting added it acts normal.I also tried adding this to the lsp-rust-analyzer settings and restarting:
But it had no effect on the problem.