mirror of https://github.com/astral-sh/ruff
[ty] Enable LRU collection for parsed module (#21749)
This commit is contained in:
parent
21e5a57296
commit
92c5f62ec0
|
|
@ -21,7 +21,11 @@ use crate::source::source_text;
|
||||||
/// reflected in the changed AST offsets.
|
/// reflected in the changed AST offsets.
|
||||||
/// The other reason is that Ruff's AST doesn't implement `Eq` which Salsa requires
|
/// The other reason is that Ruff's AST doesn't implement `Eq` which Salsa requires
|
||||||
/// for determining if a query result is unchanged.
|
/// for determining if a query result is unchanged.
|
||||||
#[salsa::tracked(returns(ref), no_eq, heap_size=ruff_memory_usage::heap_size)]
|
///
|
||||||
|
/// The LRU capacity of 200 was picked without any empirical evidence that it's optimal,
|
||||||
|
/// instead it's a wild guess that it should be unlikely that incremental changes involve
|
||||||
|
/// more than 200 modules. Parsed ASTs within the same revision are never evicted by Salsa.
|
||||||
|
#[salsa::tracked(returns(ref), no_eq, heap_size=ruff_memory_usage::heap_size, lru=200)]
|
||||||
pub fn parsed_module(db: &dyn Db, file: File) -> ParsedModule {
|
pub fn parsed_module(db: &dyn Db, file: File) -> ParsedModule {
|
||||||
let _span = tracing::trace_span!("parsed_module", ?file).entered();
|
let _span = tracing::trace_span!("parsed_module", ?file).entered();
|
||||||
|
|
||||||
|
|
@ -92,14 +96,9 @@ impl ParsedModule {
|
||||||
self.inner.store(None);
|
self.inner.store(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the pointer address of this [`ParsedModule`].
|
/// Returns the file to which this module belongs.
|
||||||
///
|
pub fn file(&self) -> File {
|
||||||
/// The pointer uniquely identifies the module within the current Salsa revision,
|
self.file
|
||||||
/// regardless of whether particular [`ParsedModuleRef`] instances are garbage collected.
|
|
||||||
pub fn addr(&self) -> usize {
|
|
||||||
// Note that the outer `Arc` in `inner` is stable across garbage collection, while the inner
|
|
||||||
// `Arc` within the `ArcSwap` may change.
|
|
||||||
Arc::as_ptr(&self.inner).addr()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,46 @@
|
||||||
use std::sync::{LazyLock, Mutex};
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use get_size2::{GetSize, StandardTracker};
|
use get_size2::{GetSize, StandardTracker};
|
||||||
use ordermap::{OrderMap, OrderSet};
|
use ordermap::{OrderMap, OrderSet};
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static TRACKER: RefCell<Option<StandardTracker>>= const { RefCell::new(None) };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TrackerGuard(Option<StandardTracker>);
|
||||||
|
|
||||||
|
impl Drop for TrackerGuard {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
TRACKER.set(self.0.take());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attach_tracker<R>(tracker: StandardTracker, f: impl FnOnce() -> R) -> R {
|
||||||
|
let prev = TRACKER.replace(Some(tracker));
|
||||||
|
let _guard = TrackerGuard(prev);
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_tracker<F, R>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(Option<&mut StandardTracker>) -> R,
|
||||||
|
{
|
||||||
|
TRACKER.with(|tracker| {
|
||||||
|
let mut tracker = tracker.borrow_mut();
|
||||||
|
f(tracker.as_mut())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the memory usage of the provided object, using a global tracker to avoid
|
/// Returns the memory usage of the provided object, using a global tracker to avoid
|
||||||
/// double-counting shared objects.
|
/// double-counting shared objects.
|
||||||
pub fn heap_size<T: GetSize>(value: &T) -> usize {
|
pub fn heap_size<T: GetSize>(value: &T) -> usize {
|
||||||
static TRACKER: LazyLock<Mutex<StandardTracker>> =
|
with_tracker(|tracker| {
|
||||||
LazyLock::new(|| Mutex::new(StandardTracker::new()));
|
if let Some(tracker) = tracker {
|
||||||
|
value.get_heap_size_with_tracker(tracker).0
|
||||||
value
|
} else {
|
||||||
.get_heap_size_with_tracker(&mut *TRACKER.lock().unwrap())
|
value.get_heap_size()
|
||||||
.0
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An implementation of [`GetSize::get_heap_size`] for [`OrderSet`].
|
/// An implementation of [`GetSize::get_heap_size`] for [`OrderSet`].
|
||||||
|
|
|
||||||
|
|
@ -379,6 +379,16 @@ pub(crate) fn symbols_for_file_global_only(db: &dyn Db, file: File) -> FlatSymbo
|
||||||
global_only: true,
|
global_only: true,
|
||||||
};
|
};
|
||||||
visitor.visit_body(&module.syntax().body);
|
visitor.visit_body(&module.syntax().body);
|
||||||
|
|
||||||
|
if file
|
||||||
|
.path(db)
|
||||||
|
.as_system_path()
|
||||||
|
.is_none_or(|path| !db.project().is_file_included(db, path))
|
||||||
|
{
|
||||||
|
// Eagerly clear ASTs of third party files.
|
||||||
|
parsed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
FlatSymbols {
|
FlatSymbols {
|
||||||
symbols: visitor.symbols,
|
symbols: visitor.symbols,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ pub use self::changes::ChangeResult;
|
||||||
use crate::CollectReporter;
|
use crate::CollectReporter;
|
||||||
use crate::metadata::settings::file_settings;
|
use crate::metadata::settings::file_settings;
|
||||||
use crate::{ProgressReporter, Project, ProjectMetadata};
|
use crate::{ProgressReporter, Project, ProjectMetadata};
|
||||||
|
use get_size2::StandardTracker;
|
||||||
use ruff_db::Db as SourceDb;
|
use ruff_db::Db as SourceDb;
|
||||||
use ruff_db::diagnostic::Diagnostic;
|
use ruff_db::diagnostic::Diagnostic;
|
||||||
use ruff_db::files::{File, Files};
|
use ruff_db::files::{File, Files};
|
||||||
|
|
@ -129,7 +130,10 @@ impl ProjectDatabase {
|
||||||
/// Returns a [`SalsaMemoryDump`] that can be use to dump Salsa memory usage information
|
/// Returns a [`SalsaMemoryDump`] that can be use to dump Salsa memory usage information
|
||||||
/// to the CLI after a typechecker run.
|
/// to the CLI after a typechecker run.
|
||||||
pub fn salsa_memory_dump(&self) -> SalsaMemoryDump {
|
pub fn salsa_memory_dump(&self) -> SalsaMemoryDump {
|
||||||
let memory_usage = <dyn salsa::Database>::memory_usage(self);
|
let memory_usage = ruff_memory_usage::attach_tracker(StandardTracker::new(), || {
|
||||||
|
<dyn salsa::Database>::memory_usage(self)
|
||||||
|
});
|
||||||
|
|
||||||
let mut ingredients = memory_usage
|
let mut ingredients = memory_usage
|
||||||
.structs
|
.structs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use ruff_db::files::File;
|
||||||
use ruff_db::parsed::ParsedModuleRef;
|
use ruff_db::parsed::ParsedModuleRef;
|
||||||
use ruff_python_ast::{AnyNodeRef, NodeIndex};
|
use ruff_python_ast::{AnyNodeRef, NodeIndex};
|
||||||
use ruff_python_ast::{AnyRootNodeRef, HasNodeIndex};
|
use ruff_python_ast::{AnyRootNodeRef, HasNodeIndex};
|
||||||
|
|
@ -44,7 +46,7 @@ pub struct AstNodeRef<T> {
|
||||||
// cannot implement `Eq`, as indices are only unique within a given instance of the
|
// cannot implement `Eq`, as indices are only unique within a given instance of the
|
||||||
// AST.
|
// AST.
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
module_addr: usize,
|
file: File,
|
||||||
|
|
||||||
_node: PhantomData<T>,
|
_node: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +74,7 @@ where
|
||||||
Self {
|
Self {
|
||||||
index,
|
index,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
module_addr: module_ref.module().addr(),
|
file: module_ref.module().file(),
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
kind: AnyNodeRef::from(node).kind(),
|
kind: AnyNodeRef::from(node).kind(),
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|
@ -88,8 +90,7 @@ where
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn node<'ast>(&self, module_ref: &'ast ParsedModuleRef) -> &'ast T {
|
pub fn node<'ast>(&self, module_ref: &'ast ParsedModuleRef) -> &'ast T {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(module_ref.module().addr(), self.module_addr);
|
assert_eq!(module_ref.module().file(), self.file);
|
||||||
|
|
||||||
// The user guarantees that the module is from the same file and Salsa
|
// The user guarantees that the module is from the same file and Salsa
|
||||||
// revision, so the file contents cannot have changed.
|
// revision, so the file contents cannot have changed.
|
||||||
module_ref
|
module_ref
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ impl std::fmt::Debug for Module<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::ref_option)]
|
#[allow(clippy::ref_option)]
|
||||||
#[salsa::tracked(returns(ref))]
|
#[salsa::tracked(returns(ref), heap_size=ruff_memory_usage::heap_size)]
|
||||||
fn all_submodule_names_for_package<'db>(
|
fn all_submodule_names_for_package<'db>(
|
||||||
db: &'db dyn Db,
|
db: &'db dyn Db,
|
||||||
module: Module<'db>,
|
module: Module<'db>,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue