Skip to content

100 CPU load and infinite loop #4500

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

Closed
giftal opened this issue May 17, 2020 · 22 comments
Closed

100 CPU load and infinite loop #4500

giftal opened this issue May 17, 2020 · 22 comments
Labels
A-parser parser issues A-perf performance issues S-unactionable Issue requires feedback, design decisions or is blocked on other work

Comments

@giftal
Copy link

giftal commented May 17, 2020

A lot of if-then-else compositions cause rust-analyzer to load CPU 100%.
A corner case .rs file attached that leads to rust analyzer crash.
Please add annotation for rust analyzer to avoid analysis of complicated functions (like the one attached). E.g. rust fmt has #[rustfmt::skip], maybe offer something like #[rustanalyzer::skip]

rust_analyzer1

rust_analyzer2

rust_code_example.zip

@flodiebold
Copy link
Member

flodiebold commented May 17, 2020

Is the file you provided the actual code? It's not even valid syntactically, since you can't make a variable named return. (Edit: Ok, the loop is actually in the parser, so this isn't so surprising.)

@giftal
Copy link
Author

giftal commented May 18, 2020

It is the actual code. Please rename the variable "return" to "ret" or whatever.

@giftal
Copy link
Author

giftal commented May 18, 2020

rust_code_example.zip

attached it the syntactically correct code. Please use it for tests.

@flodiebold
Copy link
Member

Does the problem actually happen with the syntactically correct code?

@giftal
Copy link
Author

giftal commented May 18, 2020

Yes I confirm this! The problems always happens with the code that compiles successfully.
The one I attached 2nd time is correct as well.

@dignifiedquire
Copy link

Running into this as well. I was able to attach lldb to it and gather the following traces

git commit: 190a0595a478d059fdd95a179fe38d59cb6379be

Executable module set to "/Users/dignifiedquire/.cargo/bin/rust-analyzer".
Architecture set to: x86_64h-apple-macosx.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00007fff7f0ca56e libsystem_pthread.dylib`_pthread_cond_wait + 722
    frame #2: 0x0000000107269f12 rust-analyzer`std::thread::park::hde008ae05bf6ce2e [inlined] std::sys::unix::condvar::Condvar::wait::haf711209224495da at condvar.rs:73:17 [opt]
    frame #3: 0x0000000107269f0d rust-analyzer`std::thread::park::hde008ae05bf6ce2e [inlined] std::sys_common::condvar::Condvar::wait::hbda63240707accba at condvar.rs:50 [opt]
    frame #4: 0x0000000107269f0d rust-analyzer`std::thread::park::hde008ae05bf6ce2e [inlined] std::sync::condvar::Condvar::wait::h176016a76bad0c38 at condvar.rs:200 [opt]
    frame #5: 0x0000000107269ef3 rust-analyzer`std::thread::park::hde008ae05bf6ce2e at mod.rs:919 [opt]
    frame #6: 0x0000000107260785 rust-analyzer`crossbeam_channel::context::Context::wait_until::h4c4da7e476636502 + 325
    frame #7: 0x0000000107260415 rust-analyzer`crossbeam_channel::context::Context::with::_$u7b$$u7b$closure$u7d$$u7d$::h6657e7b32116da97 + 485
    frame #8: 0x0000000107260998 rust-analyzer`crossbeam_channel::select::run_select::h58f57381a0cf5b86 + 408
    frame #9: 0x00000001062caba8 rust-analyzer`rust_analyzer::main_loop::main_loop::h86d8e7a76e6b731a + 5096
    frame #10: 0x000000010614d881 rust-analyzer`rust_analyzer::main::hb300eef24b10a083 + 5921
    frame #11: 0x0000000106177326 rust-analyzer`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h44458d503897e783 + 6
    frame #12: 0x000000010727a2d9 rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hc4eba503b68bbb2b at rt.rs:52:13 [opt]
    frame #13: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::panicking::try::do_call::h55672a70972b9078 at panicking.rs:297 [opt]
    frame #14: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::panicking::try::h6d9221801de1cfe0 at panicking.rs:274 [opt]
    frame #15: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::panic::catch_unwind::h382eeb03b10b2ef0 at panic.rs:394 [opt]
    frame #16: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 at rt.rs:51 [opt]
    frame #17: 0x000000010614e0f9 rust-analyzer`main + 41
    frame #18: 0x00007fff7eed33d5 libdyld.dylib`start + 1
(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00007fff7f0ca56e libsystem_pthread.dylib`_pthread_cond_wait + 722
    frame #2: 0x0000000107269f12 rust-analyzer`std::thread::park::hde008ae05bf6ce2e [inlined] std::sys::unix::condvar::Condvar::wait::haf711209224495da at condvar.rs:73:17 [opt]
    frame #3: 0x0000000107269f0d rust-analyzer`std::thread::park::hde008ae05bf6ce2e [inlined] std::sys_common::condvar::Condvar::wait::hbda63240707accba at condvar.rs:50 [opt]
    frame #4: 0x0000000107269f0d rust-analyzer`std::thread::park::hde008ae05bf6ce2e [inlined] std::sync::condvar::Condvar::wait::h176016a76bad0c38 at condvar.rs:200 [opt]
    frame #5: 0x0000000107269ef3 rust-analyzer`std::thread::park::hde008ae05bf6ce2e at mod.rs:919 [opt]
    frame #6: 0x0000000107260785 rust-analyzer`crossbeam_channel::context::Context::wait_until::h4c4da7e476636502 + 325
    frame #7: 0x0000000107260415 rust-analyzer`crossbeam_channel::context::Context::with::_$u7b$$u7b$closure$u7d$$u7d$::h6657e7b32116da97 + 485
    frame #8: 0x0000000107260998 rust-analyzer`crossbeam_channel::select::run_select::h58f57381a0cf5b86 + 408
    frame #9: 0x00000001062caba8 rust-analyzer`rust_analyzer::main_loop::main_loop::h86d8e7a76e6b731a + 5096
    frame #10: 0x000000010614d881 rust-analyzer`rust_analyzer::main::hb300eef24b10a083 + 5921
    frame #11: 0x0000000106177326 rust-analyzer`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h44458d503897e783 + 6
    frame #12: 0x000000010727a2d9 rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::hc4eba503b68bbb2b at rt.rs:52:13 [opt]
    frame #13: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::panicking::try::do_call::h55672a70972b9078 at panicking.rs:297 [opt]
    frame #14: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::panicking::try::h6d9221801de1cfe0 at panicking.rs:274 [opt]
    frame #15: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 [inlined] std::panic::catch_unwind::h382eeb03b10b2ef0 at panic.rs:394 [opt]
    frame #16: 0x000000010727a2ce rust-analyzer`std::rt::lang_start_internal::h2d2d7c5f224149f7 at rt.rs:51 [opt]
    frame #17: 0x000000010614e0f9 rust-analyzer`main + 41
    frame #18: 0x00007fff7eed33d5 libdyld.dylib`start + 1
(lldb) threads
error: 'threads' is not a valid command.
(lldb) threads list
error: 'threads' is not a valid command.
(lldb) thread list
Process 18697 stopped
* thread #1: tid = 0x3a7c35, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  thread #2: tid = 0x3a7c36, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #3: tid = 0x3a7c37, 0x00007fff7f009ef2 libsystem_kernel.dylib`read + 10
  thread #4: tid = 0x3a7c5a, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'vfs'
  thread #5: tid = 0x3a7c5b, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #6: tid = 0x3a7c5c, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10, name = 'notify-convertor'
  thread #7: tid = 0x3a7c6b, 0x00007fff7f009bfe libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #8: tid = 0x3a7d33, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #9: tid = 0x3a7d34, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #10: tid = 0x3a7d35, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #11: tid = 0x3a7d36, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #12: tid = 0x3a7d37, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #13: tid = 0x3a7d38, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #14: tid = 0x3a7d39, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #15: tid = 0x3a7d3a, 0x0000000107255e09 rust-analyzer`rowan::cursor::SyntaxNode::next_sibling_or_token::h7819dbb68e04663a + 25
  thread #16: tid = 0x3a7d3b, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #17: tid = 0x3a7d3c, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #18: tid = 0x3a7d3d, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #19: tid = 0x3a7d3e, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #20: tid = 0x3a7d3f, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #21: tid = 0x3a7d40, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #22: tid = 0x3a7d41, 0x00007fff7f00af06 libsystem_kernel.dylib`__psynch_mutexwait + 10
  thread #23: tid = 0x3a7d42, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #24: tid = 0x3a7d43, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #25: tid = 0x3a7d44, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #26: tid = 0x3a7d45, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #27: tid = 0x3a7d46, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #28: tid = 0x3a7d47, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #29: tid = 0x3a7d48, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #30: tid = 0x3a7d49, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #31: tid = 0x3a7d4a, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #32: tid = 0x3a7d4b, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #33: tid = 0x3a7d4d, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #34: tid = 0x3a7d4e, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #35: tid = 0x3a7d4f, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #36: tid = 0x3a7d50, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #37: tid = 0x3a7d51, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #38: tid = 0x3a7d52, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #39: tid = 0x3a7d53, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #40: tid = 0x3a7d54, 0x00007fff7f00b86a libsystem_kernel.dylib`__psynch_cvwait + 10
  thread #41: tid = 0x3abb60, 0x00007fff7f00822a libsystem_kernel.dylib`mach_msg_trap + 10

@bjorn3
Copy link
Member

bjorn3 commented May 29, 2020

What is the backtrace for thread #15: tid = 0x3a7d3a, 0x0000000107255e09 rust-analyzerrowan::cursor::SyntaxNode::next_sibling_or_token::h7819dbb68e04663a + 25`?

@giftal
Copy link
Author

giftal commented Jul 24, 2020

Folks, any update here or plans?

@giftal
Copy link
Author

giftal commented Jul 24, 2020

It got even worse these days. I put the code into external crate. But now rust-analyzer tries it's best and finds the crate ... Then kills my machine trying to analyze this

@lnicola
Copy link
Member

lnicola commented Jul 24, 2020

There are a couple of performance and possibly crash issues in the parser, e.g. #5397, #5392 and some stack overflows I've noticed while fuzz testing. One potential improvement here would be changing the syntax tree representation, but that's still pending.


That said, your code sample is horrible and it's almost 13 MB (but that's not to say that the current performance is fine). This won't solve your problem, but at some point I've had the same idea for compiling decision trees into if-chains. I've never implemented it, but my gut feeling is that it's not worth blowing up the code size. Did you ever compare it to a more traditional (tree) implementation? This is only for my personal curiosity, of course.

@kdy1
Copy link
Contributor

kdy1 commented Sep 12, 2020

I hit this with a code generated by a proc-macro. I think there should be an option to opt-out or at least ignore code generated by proc-macros.

For context, I'm trying to use https://github.com./maciejhirsz/logos to make lexer faster.
logos creates lots of branches and lookup tables.

@lnicola
Copy link
Member

lnicola commented Sep 12, 2020

@kdy1 there is an option, proc macro support is disabled by default.

@kdy1
Copy link
Contributor

kdy1 commented Sep 12, 2020

@lnicola I'm using default option, and items generated by proc macro does not show up in autocomplete. But cpu usage is 100%.

@lnicola
Copy link
Member

lnicola commented Sep 12, 2020

Might be related to trait solving, there are a couple of open issues mentioning Diesel, for example.

@kdy1
Copy link
Contributor

kdy1 commented Sep 12, 2020

It seems like a temporary issue. I killed process and it works like a charm.
Thanks for quick response.

@lnicola lnicola added the A-perf performance issues label Jan 26, 2021
@lnicola
Copy link
Member

lnicola commented Jan 26, 2021

Triage: we now panic with "the parser seems stuck".

The code is a single expression with 200950 if-else pairs implementing a decision tree.

@lnicola lnicola added the S-unactionable Issue requires feedback, design decisions or is blocked on other work label Jan 26, 2021
@giftal
Copy link
Author

giftal commented Jan 26, 2021

Triage: we now panic with "the parser seems stuck".

The code is a single expression with 200950 if-else pairs implementing a decision tree.

Super!!! This is a nice mitigation!

@giftal
Copy link
Author

giftal commented Jan 26, 2021

Though an annotation like #[rustanalyzer::skip] would be nice for some fuctions we do not want to be analyzed.

@lnicola
Copy link
Member

lnicola commented Jan 26, 2021

But really, it's still unusable. But everything I've tried balks at that file anyway: cargo check, rustfmt.

@edwin0cheng
Copy link
Member

@giftal , right now you could use this weird trick to bypass that if you really needed:

//!- main.rs
include!("foo.txt");   // the extension is important here.

fn main() {    
    let a = f();
    println!("{}", a);
}
//!- foo.txt
fn f() -> usize {  // your very compilicated code 
  ...
}

It is because currently RA will only include *.rs files, so that foo.txt will not be included.

@Veykril
Copy link
Member

Veykril commented May 27, 2022

I'm closing this as the issue is quite old and doesn't seem to contain much usable information. Please open a new issue if you encounter something like this.

@Veykril Veykril closed this as completed May 27, 2022
@lnicola
Copy link
Member

lnicola commented May 27, 2022

This still happens, but I don't know if we can do much about it right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parser parser issues A-perf performance issues S-unactionable Issue requires feedback, design decisions or is blocked on other work
Projects
None yet
Development

No branches or pull requests

9 participants