Skip to content

Commit 1e8461f

Browse files
committed
Order profiler-cli counters by display.sortWeight like the timeline
Both `counter list` and the counters nested in `profile info` follow the timeline's track order (sortWeight, then name) instead of profile order.
1 parent 11c320b commit 1e8461f

3 files changed

Lines changed: 52 additions & 6 deletions

File tree

src/profile-query/formatters/counter-info.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ const RANGE_AGGREGATE_SOURCES: Set<CounterTooltipDataSource> = new Set([
4747
'committed-range-total',
4848
]);
4949

50+
const naturalSort = new Intl.Collator('en-US', { numeric: true });
51+
52+
export function getSortedCounterIndexes(store: Store): CounterIndex[] {
53+
const state = store.getState();
54+
const counters = getCounters(state) ?? [];
55+
const order = counters.map((_, index) => index);
56+
if (getMeta(state).keepProfileThreadOrder) {
57+
return order;
58+
}
59+
return order.sort((a, b) => {
60+
const sortWeightDiff =
61+
counters[a].display.sortWeight - counters[b].display.sortWeight;
62+
if (sortWeightDiff !== 0) {
63+
return sortWeightDiff;
64+
}
65+
return naturalSort.compare(counters[a].name, counters[b].name);
66+
});
67+
}
68+
5069
/**
5170
* Format a resolved counter value exactly as the timeline tooltip does, minus
5271
* the React/localization wrapping. Only the range-aggregate sources reach this,
@@ -192,10 +211,9 @@ export function collectCounterList(
192211
store: Store,
193212
threadMap: ThreadMap
194213
): CounterListResult {
195-
const counters = getCounters(store.getState()) ?? [];
196214
return {
197215
type: 'counter-list',
198-
counters: counters.map((_, index) =>
216+
counters: getSortedCounterIndexes(store).map((index) =>
199217
collectCounterSummary(store, threadMap, index)
200218
),
201219
};

src/profile-query/formatters/profile-info.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ import {
66
getProfile,
77
getThreadCPUTimeMs,
88
getRangeFilteredCombinedThreadActivitySlices,
9-
getCounters,
109
} from 'firefox-profiler/selectors/profile';
1110
import { getProfileNameWithDefault } from 'firefox-profiler/selectors/url-state';
1211
import { buildProcessThreadList } from '../process-thread-list';
1312
import { collectSliceTree } from '../cpu-activity';
14-
import { collectCounterSummary } from './counter-info';
13+
import { collectCounterSummary, getSortedCounterIndexes } from './counter-info';
1514
import type { Store } from '../../types/store';
1615
import type { ThreadInfo, ProcessListItem } from '../process-thread-list';
1716
import type { TimestampManager } from '../timestamps';
@@ -110,12 +109,12 @@ export function collectProfileInfo(
110109
: result.processes;
111110

112111
const countersByPid = new Map<string, CounterSummary[]>();
113-
(getCounters(state) ?? []).forEach((_, index) => {
112+
for (const index of getSortedCounterIndexes(store)) {
114113
const counter = collectCounterSummary(store, threadMap, index);
115114
const list = countersByPid.get(counter.pid) ?? [];
116115
list.push(counter);
117116
countersByPid.set(counter.pid, list);
118-
});
117+
}
119118

120119
const processesData: ProfileInfoResult['processes'] = processesToShow.map(
121120
(processItem) => {

src/test/unit/profile-query/profile-querier.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,35 @@ describe('ProfileQuerier', function () {
380380
).toBe(true);
381381
});
382382

383+
it('orders counters by display.sortWeight, not profile order', async function () {
384+
const { profile } = getProfileFromTextSamples(`
385+
0 1 2
386+
A A A
387+
`);
388+
// Listed Memory-first, but Bandwidth (sortWeight 10) should sort before
389+
// Memory (sortWeight 20), matching the timeline track order.
390+
const memory = getCounterForThread(profile.threads[0], 0, {
391+
name: 'malloc',
392+
category: 'Memory',
393+
});
394+
const bandwidth = getCounterForThread(profile.threads[0], 0, {
395+
name: 'eth0',
396+
category: 'Bandwidth',
397+
});
398+
profile.counters = [memory, bandwidth];
399+
400+
const result = await querierFor(profile).counterList();
401+
402+
expect(result.counters.map((c) => c.label)).toEqual([
403+
'Bandwidth',
404+
'Memory',
405+
]);
406+
expect(result.counters.map((c) => c.counterHandle)).toEqual([
407+
'c-1',
408+
'c-0',
409+
]);
410+
});
411+
383412
it('profileInfo nests each counter under its owning process', async function () {
384413
const { profile, counter } = profileWithMemoryCounter();
385414
const info = await querierFor(profile).profileInfo();

0 commit comments

Comments
 (0)