Skip to content

Make recording of query cache hits in self-profiler much cheaper #142978

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Kobzol
Copy link
Contributor

@Kobzol Kobzol commented Jun 24, 2025

Self-profile can record various types of things, some of them are not enabled, like query cache hits. Rustc currently records cache hits as "instant" measureme events, which records the thread ID, current timestamp, and constructs an individual event for each such cache hit. This is incredibly expensive, in a small hello world benchmark that just depends on serde, it makes compilation with nightly go from ~3s (with -Zself-profile) to ~15s (with -Zself-profile -Zself-profile-events=default,query-cache-hit).

We'd like to add query cache hits to rustc-perf (rust-lang/rustc-perf#2168), but there we only need the actualy cache hit counts, not the timestamp/thread ID metadata associated with it.

This PR changes the behavior of the query-cache-hit event. Instead of generating individual instant events, it simply aggregates cache hit counts per query invocation (so a combination of a query and its arguments, if I understand it correctly) using an atomic counter. At the end of the compilation session, these counts are then dumped to the self-profile log using integer events (in a similar fashion as how we record artifact sizes). I suppose that we could dedup the query invocations in rustc directly, but I don't think it's really required. In local experiments with the hello world + serde case, the query invocation records generated ~30 KiB more data in the self-profile, which was ~10% increase in this case.

This changes the behavior of an existing event. But it's ofc unstable, and tbh I doubt that anyone uses this flag, when it makes compilation so much slower. I think that it will be more useful when it actually records the most useful subset of the previously gathered data (the actual query cache hit counts) with a fraction of the overhead. An alternative would be to create a new event. I used a different event kind though, so that old analyzeme won't choke on newly generated profiles

With this PR, the overhead of -Zself-profile-events=default,query-cache-hit seems to be miniscule vs just -Zself-profile, so I also enabled query cache hits by default when self profiling is enabled.

We should also modify analyzeme, specifically this, and make it load the integer events with query cache hit counts instead. I can do that as a follow-up, it's not required to be done in sync with this PR, and it doesn't require changes in rustc.

CC @cjgillot

r? @oli-obk

@rustbot rustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 24, 2025
@Kobzol
Copy link
Contributor Author

Kobzol commented Jun 24, 2025

https://github.com/search?type=code&q=query-cache-hits looks like no one used this anyway.. 😆

/// With this approach, we don't know the individual thread IDs and timestamps
/// of cache hits, but it has very little overhead on top of `-Zself-profile`.
/// Recording the cache hits as individual events made compilation 3-5x slower.
query_hits: RwLock<FxHashMap<QueryInvocationId, AtomicU64>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you switch this to using a dense map, e.g. IndexVec? QueryInvocationId should be monotonically assigned I think and so this should end up dense.

|profiler| profiler.query_cache_hit_event_kind,
query_invocation_id,
);
profiler_ref.profiler.as_ref().unwrap().increment_query_cache_hit(query_invocation_id);
}

if unlikely(self.event_filter_mask.contains(EventFilter::QUERY_CACHE_HITS)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to change the existing event rather than adding a new one that only tracks counts?

I think this is losing the information for the query "tree" that was previously present, right? It used to be possible to generate a flamegraph of queries but now since there's no timing/thread information we can't track the parent relationships.

That doesn't seem consistently useful, but it also doesn't seem useless to me...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants