diff options
-rw-r--r-- | docs/dev/architecture.md | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md index 2ba8b7967..56ebaa3df 100644 --- a/docs/dev/architecture.md +++ b/docs/dev/architecture.md | |||
@@ -373,8 +373,48 @@ There's no additional checks in CI, formatting and tidy tests are run with `carg | |||
373 | 373 | ||
374 | **Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible. | 374 | **Architecture Invariant:** tests do not depend on any kind of external resources, they are perfectly reproducible. |
375 | 375 | ||
376 | ### Error Handling | ||
377 | |||
378 | **Architecture Invariant:** core parts of rust-analyzer (`ide`/`hir`) don't interact with the outside world and thus can't fail. | ||
379 | Only parts touching LSP are allowed to do IO. | ||
380 | |||
381 | Internals of rust-analyzer need to deal with broken code, but this is not an error condition. | ||
382 | rust-analyzer is robust: various analysis compute `(T, Vec<Error>)` rather than `Result<T, Error>`. | ||
383 | |||
384 | rust-analyzer is a complex long-running process. | ||
385 | It will always have bugs and panics. | ||
386 | But a panic in an isolated feature should not bring down the whole process. | ||
387 | Each LSP-request is protected by a `catch_unwind`. | ||
388 | We use `always` and `never` macros instead of `assert` to gracefully recover from impossible conditions. | ||
389 | |||
376 | ### Observability | 390 | ### Observability |
377 | 391 | ||
378 | I've run out of steam here :) | ||
379 | rust-analyzer is a long-running process, so its important to understand what's going on inside. | 392 | rust-analyzer is a long-running process, so its important to understand what's going on inside. |
380 | We have hierarchical profiler (`RA_PROFILER=1`) and object counting (`RA_COUNT=1`). | 393 | We have several instruments for that. |
394 | |||
395 | The event loop that runs rust-analyzer is very explicit. | ||
396 | Rather than spawning futures or scheduling callbacks (open), the event loop accepts an `enum` of possible events (closed). | ||
397 | It's easy to see all the things that trigger rust-analyzer processing, together with their performance | ||
398 | |||
399 | rust-analyzer includes a simple hierarchical profiler (`hprof`). | ||
400 | It is enabled with `RA_PROFILE='*>50` env var (log all (`*`) actions which take more than `50` ms) and produces output like: | ||
401 | |||
402 | ``` | ||
403 | 85ms - handle_completion | ||
404 | 68ms - import_on_the_fly | ||
405 | 67ms - import_assets::search_for_relative_paths | ||
406 | 0ms - crate_def_map:wait (804 calls) | ||
407 | 0ms - find_path (16 calls) | ||
408 | 2ms - find_similar_imports (1 calls) | ||
409 | 0ms - generic_params_query (334 calls) | ||
410 | 59ms - trait_solve_query (186 calls) | ||
411 | 0ms - Semantics::analyze_impl (1 calls) | ||
412 | 1ms - render_resolution (8 calls) | ||
413 | 0ms - Semantics::analyze_impl (5 calls) | ||
414 | ``` | ||
415 | |||
416 | This is cheap enough to enable in production. | ||
417 | |||
418 | |||
419 | Similarly, we save live object counting (`RA_COUNT=1`). | ||
420 | It is not cheap enough to enable in prod, and this is a bug which should be fixed. | ||