Repository navigation
fix: keep inspector sections through a move - #1160
Merged
lcottercertinia merged 18 commits intoOct 8, 2026
Merged
Conversation
…ndex Every render of the visible call tree flattened the whole log into an array to list its types. The view now lists them once per log, the first time it is shown, by scanning the LogIndex rows. A log whose call tree is never opened pays nothing. The list drops the blank entry a typeless event added: picking it filtered nothing. Type list on a 100 MB log: - before: 65-85 ms on every render - after: 28 ms once per log
The Timeline legend and the Inspector category bar each walked the whole event tree. They now sum the index's categoryId and self columns. The legend's walk ran synchronously when a log opened: - 100 MB log: 68.4 ms → 0.88 ms - 20 MB sample: 19.4 ms → 0.32 ms
… and @lit/task LogStore.derive(fn) runs fn over the log's index once and shares the result. The Timeline legend, Inspector category bar and Call Tree type filter load through @lit/task Tasks, which drop stale runs and track loading and error. The legend and the bar now share one category sum.
A per-row namespace column is derived once per log; each scope then sums the index's self column over its subtrees. Each new selection walked its whole subtree; now it sums the index: - 100 MB log: whole log 72.1 ms → 0.83 ms after a one-off 32 ms column - 100 MB log, a method's 42,433 calls as one scope: 44.0 ms → 0.92 ms
One sliced pass over the index gives each signature its self time, count and worst call. The self-time spread, Hot Spots and the diagnostics hot spot share it, in place of three walks of eventsById. Each view now loads through a task, so the diagnostics pane only shows the current log's findings. Before: each view walked the whole log on its own, synchronously. After: one shared pass, in slices, then each view reads it. - 100 MB log: spread 311 → 34 ms, hot spots 357 → 133 ms (the remainder is the hot path), diagnostics 244 → 118 ms; shared pass 83–111 ms - 20 MB log: spread 69 → 2 ms, hot spots 58 → 2 ms, diagnostics 59 → 27 ms; shared pass 22 ms
…rapper SignatureTimes gives the views a ranked list of signatures, the log's total self time, and the self times of chosen signatures. The ranking and its tie rule live in one place, so Hot Spots, the spread and the diagnostics hot spot agree: on a tie, the signature timed first comes first. The per-row ids stay private. DerivedValue wraps the task each Inspector and Analysis section used to load a derived value. It answers only for the log the host shows, so a section never shows the last log's data. Log diagnostics is now a LogStore derivation and takes its store as an argument, in place of a module cache and the current-store global. The hot-spot label is now the full method text; before, a text with a '|' lost its start.
The spread collects each lane's self times into an array sized from its call count and sorts it natively. The hot path groups calls through nested maps, so it builds no key string per call, and it hands the thread back between slices. Median of 5 runs, before → after: - spread: 40 MB log 24 → 15 ms, 100 MB log 36 → 19 ms - hot path and hot spots: 40 MB log 67 → 58 ms, 100 MB log 130 → 95 ms, now in slices of about 8 ms in place of one block
Statements come from a statements derivation that reads only SOQL and DML category rows. databaseOverview and rowBudgets are LogStore derivations, so the per-log WeakMap caches and the LogStore statement lists go. The overview finds each statement's enclosing statement with a stack over subtreeEnd, and keeps the old walk order so ties stay the same. The Database call tree shows its grid skeleton while its rows derive, and drops the last log's rows on a log switch.
The variable index reads only the rows the parser gives no category, where variable lines live, rather than walking the whole tree twice. The first pass keeps the writes whose address can resolve, so the second reads only those. variableIndexFor becomes the variableIndex LogStore derivation, so its own per-log caches go.
The series reads only the rows whose category can hold a limit event, in log order, then puts readings tied in time in the order the tree walk met them, so the output is unchanged. apexLimitTimeSeries and its per-log cache become the apexLimitSeries LogStore derivation; the timeline, overview, trends, diagnostics and database views derive it.
The series builder hands the thread back every CHECK_EVERY readings, so the sort, coalesce and fold steps on large logs no longer block. A unit test now pins the order of readings that tie in time.
The Inspector line now names the Analysis and Database views, which this stack also made faster. The Call Tree line drops its ms figure, since no total render time was measured.
The Call Tree and Inspector perf lines become one line that names the tab views and the Inspector sections.
Moving an inspector section detached it. The Call tree, Call stack and Database call tree sections destroyed their table and rebuilt it only for a new selection or log, so they stayed empty, and the Variables section dropped a comparison in progress. A teardown controller now waits a microtask and keeps the live state when the section is back, so a move keeps its scroll, open rows and selection. A real removal still frees the state, and a re-attach after it rebuilds.
lcottercertinia
previously approved these changes
Oct 8, 2026
…eattach # Conflicts: # log-viewer/src/components/CallTreeDetail.ts # log-viewer/src/components/CategoryTimeBar.ts # log-viewer/src/components/LogOverview.ts # log-viewer/src/components/NamespaceTimeBar.ts # log-viewer/src/components/__tests__/NamespaceTimeBar.test.ts # log-viewer/src/components/__tests__/fixtures/logEvents.ts # log-viewer/src/components/namespaceTime.ts # log-viewer/src/core/log/frameVariables.ts # log-viewer/src/features/database/components/DatabaseTimeTree.ts
lcottercertinia
approved these changes
Oct 8, 2026
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.
📝 PR Overview
Moving an Inspector section (drag, or
Alt+Arrow) detaches it and attaches it again. The pane's keyedrepeatdoes this so that a move keeps each section's state. But four sections dropped their state on detach:Now a move keeps the live state: the rows, the scroll position, the open rows and the selection. No table is rebuilt.
🛠️ Changes made
TeardownController(new,core/events/) tears a host's state down only when the host has left the page:DatabaseTime,CallTreeDetail,CallStackDetailandVariablesDetailuse it in place of theirdisconnectedCallback.CallStackDetailbuilds again after its render, so Tabulator measures a host that has its layout.🧩 Type of change (check all applicable)
🔗 Related Issues
Follows #1144 and #1148.
✅ Tests added?
📚 Docs updated?
🧪badge — see RELEASING.md)Anything else we need to know? [optional]
Each of the four sections has a test for a move and a test for a removal followed by a re-attach. All of them fail without this fix. The controller has its own tests for a move, a teardown, a rebuild and a second teardown.
CalltreeViewandTimelineFlameChartkeep their own re-attach code. It works, so this PR does not move it to the controller.