fix(android-profiler): explain an empty CPU section instead of rendering it as an idle app - #669
Open
filip131311 wants to merge 1 commit into
Open
fix(android-profiler): explain an empty CPU section instead of rendering it as an idle app#669filip131311 wants to merge 1 commit into
filip131311 wants to merge 1 commit into
Conversation
…ing it as an idle app A Perfetto trace can contain perf samples that carry no call stack. Every such row is dropped for having no leaf function, so the report showed no CPU section and the footer read 'showing top 0 CPU hotspots', while thread_breakdown — which counts samples and never joins the symbol tables — reported hundreds. Two statements about one trace that cannot both be true, with nothing explaining it. The pipeline now detects that state and says so, naming the sample count and the package. It is deliberately not an exportErrors entry: nothing errored, and the all-clear banner counts those as failed queries, so routing it there would have printed 'N of 3 queries errored' about queries that all succeeded. Two causes are told apart with data already on the row. leaf_mapping comes from the same join chain as leaf_function, so a mapping with no name means the stack was unwound and only the symbol is missing (stripped libraries), while neither means nothing was ever unwound (the process was not profileable). They need different fixes, so guessing between them would send people down the wrong path. Measured on a Pixel_9 while diagnosing this: com.android.settings, a platform package with no DEBUGGABLE flag, yielded 296 samples with zero callsites and an empty stack_profile_frame, and perf_samples_skipped equal to the sample count. A debug build on the same emulator yielded 86 samples, 86 callsites, 723 frames and a populated hotspot table — so the advice the message gives is verified on the device it describes, and this is not an emulator limitation. The existing no-samples-at-all hint is left gated on there being no hangs. That gate is deliberate and tested: once hangs come back the app clearly was traced, so blaming the manifest would be wrong. This is a different state and carries no such gate, which matters because a real capture almost always has hangs. The footer no longer claims to show 'top 0 CPU hotspots' when there are none.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #629.
Reproduced, then diagnosed harder than the report
Pixel_9 / API 36,
com.android.settings, real interaction — all three symptoms reproduced:The report infers "unsymbolized frames". It's stronger than that — I queried the
.pftracedirectly:callsite_idstack_profile_framerows (trace-wide)stats.perf_samples_skippedunwind_errorThe unwinder never ran. There are no frames to symbolize. That's why
thread_breakdown— which countsperf_samplerows and never joins the symbol tables — reports 296 while every stack-dependent view is empty.Positive control: same emulator, debuggable app
perf_samples_skippedwritel48.72%,internal_get_user_pages_fast6.41%So this is not an emulator limitation and not symbolization — it's target profileability. The remedy the message gives is verified to work on the very device it describes.
The fix
The pipeline detects "samples exist, none carry a usable stack" and says so. It names the count and the package, and distinguishes two causes using
leaf_mapping, already on the row — no new query needed. It comes from the same join chain asleaf_function, so a mapping with no name means the stack was unwound and only the symbol is missing (stripped.sos), while neither means nothing was unwound (not profileable). Different problems, different fixes.Live output on the bad trace:
Not routed through
exportErrors. That looked free — it renders above the Summary with no plumbing — butrenderAllClearcounts its entries as failed queries and would print "1 of 3 queries errored" about three queries that all succeeded. It goes through acpuDiagnosticnote instead, alongside the existingfreshnessNote, andstatusstaysok.Also fixed: the footer no longer says "showing top 0 CPU hotspots" — the literal artifact in the report title.
What I deliberately did NOT touch
The existing no-samples-at-all manifest hint stays gated on
hangRows.length === 0. That gate is intentional and pinned bymanifest-hint.test.ts:52("does NOT emit a manifest hint when hangs were found but CPU was empty") — once hangs come back the app clearly was traced, so blaming the manifest is wrong advice.It also wouldn't have helped: in the reported case
cpuRows.lengthis 9, not 0, so state A is never reached. Ungating it would have fired the hint on ~6 more existing fixtures and flipped theirstatus, for no benefit. I only corrected its text, which claimed "Perfetto silently drops the linux.perf data source" — this issue proves a non-profileable app still yields samples.Verified live, both directions
com.android.settings)showing top 3 hangsok,exportErrors: {}showing top 2 CPU hotspots and top 3 hangsokDeliberately deferred (filed separately)
thread_breakdown/function_callersnotes — the issue's "and ideally" half. Needs a newthread-breakdown.sqlaggregate plus fixture updates in two test files.Checks
tool-description-quality.ymldoesn't run (path-filtered tosrc/tools/**); prettier, eslint, both typechecks clean; lock untouched.