aboutsummaryrefslogtreecommitdiff
path: root/ui/src/common/actions.ts
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/common/actions.ts')
-rw-r--r--ui/src/common/actions.ts330
1 files changed, 54 insertions, 276 deletions
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index e982bc9d9..d297813f4 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -14,30 +14,19 @@
import {Draft} from 'immer';
-import {assertExists, assertTrue} from '../base/logging';
-import {randomColor} from '../common/colorizer';
-import {ConvertTrace, ConvertTraceToPprof} from '../controller/trace_converter';
-import {ACTUAL_FRAMES_SLICE_TRACK_KIND} from '../tracks/actual_frames/common';
-import {ASYNC_SLICE_TRACK_KIND} from '../tracks/async_slices/common';
-import {COUNTER_TRACK_KIND} from '../tracks/counter/common';
-import {DEBUG_SLICE_TRACK_KIND} from '../tracks/debug_slices/common';
-import {
- EXPECTED_FRAMES_SLICE_TRACK_KIND
-} from '../tracks/expected_frames/common';
-import {HEAP_PROFILE_TRACK_KIND} from '../tracks/heap_profile/common';
+import {assertExists} from '../base/logging';
import {
- PROCESS_SCHEDULING_TRACK_KIND
-} from '../tracks/process_scheduling/common';
-import {PROCESS_SUMMARY_TRACK} from '../tracks/process_summary/common';
+ Area,
+ CallsiteInfo,
+ HeapProfileFlamegraphViewingOption
+} from '../common/state';
+import {ConvertTrace, ConvertTraceToPprof} from '../controller/trace_converter';
import {DEFAULT_VIEWING_OPTION} from './flamegraph_util';
import {
AdbRecordingTarget,
- Area,
- CallsiteInfo,
createEmptyState,
EngineMode,
- HeapProfileFlamegraphViewingOption,
LogsPagination,
NewEngineMode,
OmniboxState,
@@ -46,38 +35,26 @@ import {
SCROLLING_TRACK_GROUP,
State,
Status,
+ TimestampedAreaSelection,
TraceSource,
TraceTime,
- TrackKindPriority,
TrackState,
VisibleState,
} from './state';
type StateDraft = Draft<State>;
-const highPriorityTrackOrder = [
- PROCESS_SCHEDULING_TRACK_KIND,
- PROCESS_SUMMARY_TRACK,
- EXPECTED_FRAMES_SLICE_TRACK_KIND,
- ACTUAL_FRAMES_SLICE_TRACK_KIND
-];
-
-const lowPriorityTrackOrder =
- [HEAP_PROFILE_TRACK_KIND, COUNTER_TRACK_KIND, ASYNC_SLICE_TRACK_KIND];
-
export interface AddTrackArgs {
id?: string;
engineId: string;
kind: string;
name: string;
- trackKindPriority: TrackKindPriority;
trackGroup?: string;
config: {};
}
export interface PostedTrace {
title: string;
- fileName?: string;
url?: string;
buffer: ArrayBuffer;
}
@@ -87,7 +64,6 @@ function clearTraceState(state: StateDraft) {
const recordConfig = state.recordConfig;
const route = state.route;
const recordingTarget = state.recordingTarget;
- const updateChromeCategories = state.updateChromeCategories;
const extensionInstalled = state.extensionInstalled;
const availableAdbDevices = state.availableAdbDevices;
const chromeCategories = state.chromeCategories;
@@ -98,27 +74,12 @@ function clearTraceState(state: StateDraft) {
state.recordConfig = recordConfig;
state.route = route;
state.recordingTarget = recordingTarget;
- state.updateChromeCategories = updateChromeCategories;
state.extensionInstalled = extensionInstalled;
state.availableAdbDevices = availableAdbDevices;
state.chromeCategories = chromeCategories;
state.newEngineMode = newEngineMode;
}
-function rank(ts: TrackState): number[] {
- const hpRank = rankIndex(ts.kind, highPriorityTrackOrder);
- const lpRank = rankIndex(ts.kind, lowPriorityTrackOrder);
- // TODO(hjd): Create sortBy object on TrackState to avoid this cast.
- const tid = (ts.config as {tid?: number}).tid || 0;
- return [hpRank, ts.trackKindPriority.valueOf(), lpRank, tid];
-}
-
-function rankIndex<T>(element: T, array: T[]): number {
- const index = array.indexOf(element);
- if (index === -1) return array.length;
- return index;
-}
-
export const StateActions = {
navigate(state: StateDraft, args: {route: string}): void {
@@ -176,9 +137,8 @@ export const StateActions = {
// TODO(b/141359485): Actions should only modify state.
convertTraceToJson(
- state: StateDraft, args: {file: Blob, truncate?: 'start'|'end'}): void {
- state.traceConversionInProgress = true;
- ConvertTrace(args.file, 'json', args.truncate);
+ _: StateDraft, args: {file: Blob, truncate?: 'start'|'end'}): void {
+ ConvertTrace(args.file, args.truncate);
},
convertTraceToPprof(
@@ -187,10 +147,6 @@ export const StateActions = {
ConvertTraceToPprof(args.pid, args.src, args.ts1, args.ts2);
},
- clearConversionInProgress(state: StateDraft, _args: {}): void {
- state.traceConversionInProgress = false;
- },
-
addTracks(state: StateDraft, args: {tracks: AddTrackArgs[]}) {
args.tracks.forEach(track => {
const id = track.id === undefined ? `${state.nextId++}` : track.id;
@@ -206,7 +162,7 @@ export const StateActions = {
addTrack(state: StateDraft, args: {
id?: string; engineId: string; kind: string; name: string;
- trackGroup?: string; config: {}; trackKindPriority: TrackKindPriority;
+ trackGroup?: string; config: {};
}): void {
const id = args.id !== undefined ? args.id : `${state.nextId++}`;
state.tracks[id] = {
@@ -214,7 +170,6 @@ export const StateActions = {
engineId: args.engineId,
kind: args.kind,
name: args.name,
- trackKindPriority: args.trackKindPriority,
trackGroup: args.trackGroup,
config: args.config,
};
@@ -234,62 +189,11 @@ export const StateActions = {
collapsed: boolean;
}): void {
state.trackGroups[args.id] = {
- engineId: args.engineId,
- name: args.name,
- id: args.id,
- collapsed: args.collapsed,
- tracks: [args.summaryTrackId],
+ ...args,
+ tracks: [],
};
},
- addDebugTrack(state: StateDraft, args: {engineId: string, name: string}):
- void {
- if (state.debugTrackId !== undefined) return;
- const trackId = `${state.nextId++}`;
- state.debugTrackId = trackId;
- this.addTrack(state, {
- id: trackId,
- engineId: args.engineId,
- kind: DEBUG_SLICE_TRACK_KIND,
- name: args.name,
- trackKindPriority: TrackKindPriority.ORDINARY,
- trackGroup: SCROLLING_TRACK_GROUP,
- config: {
- maxDepth: 1,
- }
- });
- this.toggleTrackPinned(state, {trackId});
- },
-
- removeDebugTrack(state: StateDraft, _: {}): void {
- const {debugTrackId} = state;
- if (debugTrackId === undefined) return;
- delete state.tracks[debugTrackId];
- state.scrollingTracks =
- state.scrollingTracks.filter(id => id !== debugTrackId);
- state.pinnedTracks = state.pinnedTracks.filter(id => id !== debugTrackId);
- state.debugTrackId = undefined;
- },
-
- sortThreadTracks(state: StateDraft, _: {}): void {
- // Use a numeric collator so threads are sorted as T1, T2, ..., T10, T11,
- // rather than T1, T10, T11, ..., T2, T20, T21 .
- const coll = new Intl.Collator([], {sensitivity: 'base', numeric: true});
- for (const group of Object.values(state.trackGroups)) {
- group.tracks.sort((a: string, b: string) => {
- const aRank = rank(state.tracks[a]);
- const bRank = rank(state.tracks[b]);
- for (let i = 0; i < aRank.length; i++) {
- if (aRank[i] !== bRank[i]) return aRank[i] - bRank[i];
- }
-
- const aName = state.tracks[a].name.toLocaleLowerCase();
- const bName = state.tracks[b].name.toLocaleLowerCase();
- return coll.compare(aName, bName);
- });
- }
- },
-
updateAggregateSorting(
state: StateDraft, args: {id: string, column: string}) {
let prefs = state.aggregatePreferences[args.id];
@@ -391,23 +295,11 @@ export const StateActions = {
trackGroup.collapsed = !trackGroup.collapsed;
},
- requestTrackReload(state: StateDraft, _: {}) {
- if (state.lastTrackReloadRequest) {
- state.lastTrackReloadRequest++;
- } else {
- state.lastTrackReloadRequest = 1;
- }
- },
-
setEngineReady(
state: StateDraft,
args: {engineId: string; ready: boolean, mode: EngineMode}): void {
- const engine = state.engines[args.engineId];
- if (engine === undefined) {
- return;
- }
- engine.ready = args.ready;
- engine.mode = args.mode;
+ state.engines[args.engineId].ready = args.ready;
+ state.engines[args.engineId].mode = args.mode;
},
setNewEngineMode(state: StateDraft, args: {mode: NewEngineMode}): void {
@@ -422,12 +314,8 @@ export const StateActions = {
}
},
- createPermalink(state: StateDraft, args: {isRecordingConfig: boolean}): void {
- state.permalink = {
- requestId: `${state.nextId++}`,
- hash: undefined,
- isRecordingConfig: args.isRecordingConfig
- };
+ createPermalink(state: StateDraft, _: {}): void {
+ state.permalink = {requestId: `${state.nextId++}`, hash: undefined};
},
setPermalink(state: StateDraft, args: {requestId: string; hash: string}):
@@ -438,7 +326,10 @@ export const StateActions = {
},
loadPermalink(state: StateDraft, args: {hash: string}): void {
- state.permalink = {requestId: `${state.nextId++}`, hash: args.hash};
+ state.permalink = {
+ requestId: `${state.nextId++}`,
+ hash: args.hash,
+ };
},
clearPermalink(state: StateDraft, _: {}): void {
@@ -481,7 +372,7 @@ export const StateActions = {
addNote(
state: StateDraft,
args: {timestamp: number, color: string, isMovie: boolean}): void {
- const id = `${state.nextNoteId++}`;
+ const id = `${state.nextId++}`;
state.notes[id] = {
noteType: 'DEFAULT',
id,
@@ -495,56 +386,21 @@ export const StateActions = {
this.selectNote(state, {id});
},
- markCurrentArea(
- state: StateDraft, args: {color: string, persistent: boolean}):
+ addAreaNote(
+ state: StateDraft, args: {timestamp: number, area: Area, color: string}):
void {
- if (state.currentSelection === null ||
- state.currentSelection.kind !== 'AREA') {
- return;
- }
- const id = args.persistent ? `${state.nextNoteId++}` : '0';
- const color = args.persistent ? args.color : '#344596';
+ const id = `${state.nextId++}`;
state.notes[id] = {
noteType: 'AREA',
id,
- areaId: state.currentSelection.areaId,
- color,
+ timestamp: args.timestamp,
+ area: args.area,
+ color: args.color,
text: '',
};
- state.currentSelection.noteId = id;
+ this.selectNote(state, {id});
},
- toggleMarkCurrentArea(state: StateDraft, args: {persistent: boolean}) {
- const selection = state.currentSelection;
- if (selection != null && selection.kind === 'AREA' &&
- selection.noteId !== undefined) {
- this.removeNote(state, {id: selection.noteId});
- } else {
- const color = randomColor();
- this.markCurrentArea(state, {color, persistent: args.persistent});
- }
- },
-
- markArea(state: StateDraft, args: {area: Area, persistent: boolean}): void {
- const areaId = `${state.nextAreaId++}`;
- assertTrue(args.area.endSec >= args.area.startSec);
- state.areas[areaId] = {
- id: areaId,
- startSec: args.area.startSec,
- endSec: args.area.endSec,
- tracks: args.area.tracks
- };
- const id = args.persistent ? `${state.nextNoteId++}` : '0';
- const color = args.persistent ? randomColor() : '#344596';
- state.notes[id] = {
- noteType: 'AREA',
- id,
- areaId,
- color,
- text: '',
- };
- },
-
toggleVideo(state: StateDraft, _: {}): void {
state.videoEnabled = !state.videoEnabled;
if (!state.videoEnabled) {
@@ -587,23 +443,16 @@ export const StateActions = {
},
removeNote(state: StateDraft, args: {id: string}): void {
- if (state.notes[args.id] === undefined) return;
if (state.notes[args.id].noteType === 'MOVIE') {
state.videoNoteIds = state.videoNoteIds.filter(id => {
return id !== args.id;
});
}
delete state.notes[args.id];
- // For regular notes, we clear the current selection but for an area note
- // we only want to clear the note/marking and leave the area selected.
if (state.currentSelection === null) return;
if (state.currentSelection.kind === 'NOTE' &&
state.currentSelection.id === args.id) {
state.currentSelection = null;
- } else if (
- state.currentSelection.kind === 'AREA' &&
- state.currentSelection.noteId === args.id) {
- state.currentSelection.noteId = undefined;
}
},
@@ -638,6 +487,11 @@ export const StateActions = {
ts: args.ts,
type: args.type,
};
+ },
+
+ showHeapProfileFlamegraph(
+ state: StateDraft,
+ args: {id: number, upid: number, ts: number, type: string}): void {
state.currentHeapProfileFlamegraph = {
kind: 'HEAP_PROFILE_FLAMEGRAPH',
id: args.id,
@@ -689,14 +543,24 @@ export const StateActions = {
};
},
- selectThreadState(state: StateDraft, args: {id: number, trackId: string}):
- void {
- state.currentSelection = {
- kind: 'THREAD_STATE',
- id: args.id,
- trackId: args.trackId,
- };
- },
+ selectThreadState(state: StateDraft, args: {
+ utid: number,
+ ts: number,
+ dur: number,
+ state: string,
+ cpu: number,
+ trackId: string
+ }): void {
+ state.currentSelection = {
+ kind: 'THREAD_STATE',
+ utid: args.utid,
+ ts: args.ts,
+ dur: args.dur,
+ state: args.state,
+ cpu: args.cpu,
+ trackId: args.trackId,
+ };
+ },
deselect(state: StateDraft, _: {}): void {
state.currentSelection = null;
@@ -733,10 +597,6 @@ export const StateActions = {
state.recordingTarget = args.target;
},
- setUpdateChromeCategories(state: StateDraft, args: {update: boolean}): void {
- state.updateChromeCategories = args.update;
- },
-
setAvailableAdbDevices(
state: StateDraft, args: {devices: AdbRecordingTarget[]}): void {
state.availableAdbDevices = args.devices;
@@ -746,63 +606,8 @@ export const StateActions = {
state.frontendLocalState.omniboxState = args;
},
- selectArea(state: StateDraft, args: {area: Area}): void {
- const areaId = `${state.nextAreaId++}`;
- assertTrue(args.area.endSec >= args.area.startSec);
- state.areas[areaId] = {
- id: areaId,
- startSec: args.area.startSec,
- endSec: args.area.endSec,
- tracks: args.area.tracks
- };
- state.currentSelection = {kind: 'AREA', areaId};
- },
-
- editArea(state: StateDraft, args: {area: Area, areaId: string}): void {
- assertTrue(args.area.endSec >= args.area.startSec);
- state.areas[args.areaId] = {
- id: args.areaId,
- startSec: args.area.startSec,
- endSec: args.area.endSec,
- tracks: args.area.tracks
- };
- },
-
- reSelectArea(state: StateDraft, args: {areaId: string, noteId: string}):
- void {
- state.currentSelection = {
- kind: 'AREA',
- areaId: args.areaId,
- noteId: args.noteId
- };
- },
-
- toggleTrackSelection(
- state: StateDraft, args: {id: string, isTrackGroup: boolean}) {
- const selection = state.currentSelection;
- if (selection === null || selection.kind !== 'AREA') return;
- const areaId = selection.areaId;
- const index = state.areas[areaId].tracks.indexOf(args.id);
- if (index > -1) {
- state.areas[areaId].tracks.splice(index, 1);
- if (args.isTrackGroup) { // Also remove all child tracks.
- for (const childTrack of state.trackGroups[args.id].tracks) {
- const childIndex = state.areas[areaId].tracks.indexOf(childTrack);
- if (childIndex > -1) {
- state.areas[areaId].tracks.splice(childIndex, 1);
- }
- }
- }
- } else {
- state.areas[areaId].tracks.push(args.id);
- if (args.isTrackGroup) { // Also add all child tracks.
- for (const childTrack of state.trackGroups[args.id].tracks) {
- if (!state.areas[areaId].tracks.includes(childTrack)) {
- state.areas[areaId].tracks.push(childTrack);
- }
- }
- }
- }
+ selectArea(state: StateDraft, args: TimestampedAreaSelection): void {
+ state.frontendLocalState.selectedArea = args;
},
setVisibleTraceTime(state: StateDraft, args: VisibleState): void {
@@ -825,34 +630,7 @@ export const StateActions = {
setAnalyzePageQuery(state: StateDraft, args: {query: string}): void {
state.analyzePageQuery = args.query;
- },
-
- requestSelectedMetric(state: StateDraft, _: {}): void {
- if (!state.metrics.availableMetrics) throw Error('No metrics available');
- if (state.metrics.selectedIndex === undefined) {
- throw Error('No metric selected');
- }
- state.metrics.requestedMetric =
- state.metrics.availableMetrics[state.metrics.selectedIndex];
- },
-
- resetMetricRequest(state: StateDraft, args: {name: string}): void {
- if (state.metrics.requestedMetric !== args.name) return;
- state.metrics.requestedMetric = undefined;
- },
-
- setAvailableMetrics(state: StateDraft, args: {metrics: string[]}): void {
- state.metrics.availableMetrics = args.metrics;
- if (args.metrics.length > 0) state.metrics.selectedIndex = 0;
- },
-
- setMetricSelectedIndex(state: StateDraft, args: {index: number}): void {
- if (!state.metrics.availableMetrics ||
- args.index >= state.metrics.availableMetrics.length) {
- throw Error('metric selection out of bounds');
- }
- state.metrics.selectedIndex = args.index;
- },
+ }
};
// When we are on the frontend side, we don't really want to execute the