• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2018 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import {assertExists} from '../base/logging';
16import {DeferredAction} from '../common/actions';
17import {AggregateData} from '../common/aggregation_data';
18import {CurrentSearchResults, SearchSummary} from '../common/search_data';
19import {CallsiteInfo, createEmptyState, State} from '../common/state';
20
21import {FrontendLocalState} from './frontend_local_state';
22import {RafScheduler} from './raf_scheduler';
23import {ServiceWorkerController} from './service_worker_controller';
24
25type Dispatch = (action: DeferredAction) => void;
26type TrackDataStore = Map<string, {}>;
27type QueryResultsStore = Map<string, {}>;
28type AggregateDataStore = Map<string, AggregateData>;
29type Description = Map<string, string>;
30export type Arg = string|{kind: 'SLICE', trackId: string, sliceId: number};
31export type Args = Map<string, Arg>;
32export interface SliceDetails {
33  ts?: number;
34  dur?: number;
35  priority?: number;
36  endState?: string;
37  cpu?: number;
38  id?: number;
39  utid?: number;
40  wakeupTs?: number;
41  wakerUtid?: number;
42  wakerCpu?: number;
43  category?: string;
44  name?: string;
45  args?: Args;
46  description?: Description;
47}
48
49export interface CounterDetails {
50  startTime?: number;
51  value?: number;
52  delta?: number;
53  duration?: number;
54}
55
56export interface HeapProfileDetails {
57  type?: string;
58  id?: number;
59  ts?: number;
60  tsNs?: number;
61  pid?: number;
62  upid?: number;
63  flamegraph?: CallsiteInfo[];
64  expandedCallsite?: CallsiteInfo;
65  viewingOption?: string;
66  expandedId?: number;
67}
68
69export interface CpuProfileDetails {
70  id?: number;
71  ts?: number;
72  utid?: number;
73  stack?: CallsiteInfo[];
74}
75
76export interface QuantizedLoad {
77  startSec: number;
78  endSec: number;
79  load: number;
80}
81type OverviewStore = Map<string, QuantizedLoad[]>;
82
83export interface ThreadDesc {
84  utid: number;
85  tid: number;
86  threadName: string;
87  pid?: number;
88  procName?: string;
89}
90type ThreadMap = Map<number, ThreadDesc>;
91
92/**
93 * Global accessors for state/dispatch in the frontend.
94 */
95class Globals {
96  private _dispatch?: Dispatch = undefined;
97  private _controllerWorker?: Worker = undefined;
98  private _state?: State = undefined;
99  private _frontendLocalState?: FrontendLocalState = undefined;
100  private _rafScheduler?: RafScheduler = undefined;
101  private _serviceWorkerController?: ServiceWorkerController = undefined;
102
103  // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
104  private _trackDataStore?: TrackDataStore = undefined;
105  private _queryResults?: QueryResultsStore = undefined;
106  private _overviewStore?: OverviewStore = undefined;
107  private _aggregateDataStore?: AggregateDataStore = undefined;
108  private _threadMap?: ThreadMap = undefined;
109  private _sliceDetails?: SliceDetails = undefined;
110  private _counterDetails?: CounterDetails = undefined;
111  private _heapProfileDetails?: HeapProfileDetails = undefined;
112  private _cpuProfileDetails?: CpuProfileDetails = undefined;
113  private _numQueriesQueued = 0;
114  private _bufferUsage?: number = undefined;
115  private _recordingLog?: string = undefined;
116
117  private _currentSearchResults: CurrentSearchResults = {
118    sliceIds: new Float64Array(0),
119    tsStarts: new Float64Array(0),
120    utids: new Float64Array(0),
121    trackIds: [],
122    sources: [],
123    totalResults: 0,
124  };
125  searchSummary: SearchSummary = {
126    tsStarts: new Float64Array(0),
127    tsEnds: new Float64Array(0),
128    count: new Uint8Array(0),
129  };
130
131  // This variable is set by the is_internal_user.js script if the user is a
132  // googler. This is used to avoid exposing features that are not ready yet
133  // for public consumption. The gated features themselves are not secret.
134  isInternalUser = false;
135
136  initialize(dispatch: Dispatch, controllerWorker: Worker) {
137    this._dispatch = dispatch;
138    this._controllerWorker = controllerWorker;
139    this._state = createEmptyState();
140    this._frontendLocalState = new FrontendLocalState();
141    this._rafScheduler = new RafScheduler();
142    this._serviceWorkerController = new ServiceWorkerController();
143
144    // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
145    this._trackDataStore = new Map<string, {}>();
146    this._queryResults = new Map<string, {}>();
147    this._overviewStore = new Map<string, QuantizedLoad[]>();
148    this._aggregateDataStore = new Map<string, AggregateData>();
149    this._threadMap = new Map<number, ThreadDesc>();
150    this._sliceDetails = {};
151    this._counterDetails = {};
152    this._heapProfileDetails = {};
153    this._cpuProfileDetails = {};
154  }
155
156  get state(): State {
157    return assertExists(this._state);
158  }
159
160  set state(state: State) {
161    this._state = assertExists(state);
162  }
163
164  get dispatch(): Dispatch {
165    return assertExists(this._dispatch);
166  }
167
168  get frontendLocalState() {
169    return assertExists(this._frontendLocalState);
170  }
171
172  get rafScheduler() {
173    return assertExists(this._rafScheduler);
174  }
175
176  get serviceWorkerController() {
177    return assertExists(this._serviceWorkerController);
178  }
179
180  // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
181  get overviewStore(): OverviewStore {
182    return assertExists(this._overviewStore);
183  }
184
185  get trackDataStore(): TrackDataStore {
186    return assertExists(this._trackDataStore);
187  }
188
189  get queryResults(): QueryResultsStore {
190    return assertExists(this._queryResults);
191  }
192
193  get threads() {
194    return assertExists(this._threadMap);
195  }
196
197  get sliceDetails() {
198    return assertExists(this._sliceDetails);
199  }
200
201  set sliceDetails(click: SliceDetails) {
202    this._sliceDetails = assertExists(click);
203  }
204
205  get counterDetails() {
206    return assertExists(this._counterDetails);
207  }
208
209  set counterDetails(click: CounterDetails) {
210    this._counterDetails = assertExists(click);
211  }
212
213  get aggregateDataStore(): AggregateDataStore {
214    return assertExists(this._aggregateDataStore);
215  }
216
217  get heapProfileDetails() {
218    return assertExists(this._heapProfileDetails);
219  }
220
221  set heapProfileDetails(click: HeapProfileDetails) {
222    this._heapProfileDetails = assertExists(click);
223  }
224
225  get cpuProfileDetails() {
226    return assertExists(this._cpuProfileDetails);
227  }
228
229  set cpuProfileDetails(click: CpuProfileDetails) {
230    this._cpuProfileDetails = assertExists(click);
231  }
232
233  set numQueuedQueries(value: number) {
234    this._numQueriesQueued = value;
235  }
236
237  get numQueuedQueries() {
238    return this._numQueriesQueued;
239  }
240
241  get bufferUsage() {
242    return this._bufferUsage;
243  }
244
245  get recordingLog() {
246    return this._recordingLog;
247  }
248
249  get currentSearchResults() {
250    return this._currentSearchResults;
251  }
252
253  set currentSearchResults(results: CurrentSearchResults) {
254    this._currentSearchResults = results;
255  }
256
257  setBufferUsage(bufferUsage: number) {
258    this._bufferUsage = bufferUsage;
259  }
260
261  setTrackData(id: string, data: {}) {
262    this.trackDataStore.set(id, data);
263  }
264
265  setRecordingLog(recordingLog: string) {
266    this._recordingLog = recordingLog;
267  }
268
269  setAggregateData(kind: string, data: AggregateData) {
270    this.aggregateDataStore.set(kind, data);
271  }
272
273  getCurResolution() {
274    // Truncate the resolution to the closest power of 2.
275    // This effectively means the resolution changes every 6 zoom levels.
276    const resolution = this.frontendLocalState.timeScale.deltaPxToDuration(1);
277    return Math.pow(2, Math.floor(Math.log2(resolution)));
278  }
279
280  makeSelection(action: DeferredAction<{}>) {
281    // A new selection should cancel the current search selection.
282    globals.frontendLocalState.searchIndex = -1;
283    globals.frontendLocalState.currentTab =
284        action.type === 'deselect' ? undefined : 'current_selection';
285    globals.dispatch(action);
286  }
287
288  resetForTesting() {
289    this._dispatch = undefined;
290    this._state = undefined;
291    this._frontendLocalState = undefined;
292    this._rafScheduler = undefined;
293    this._serviceWorkerController = undefined;
294
295    // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
296    this._trackDataStore = undefined;
297    this._queryResults = undefined;
298    this._overviewStore = undefined;
299    this._threadMap = undefined;
300    this._sliceDetails = undefined;
301    this._aggregateDataStore = undefined;
302    this._numQueriesQueued = 0;
303    this._currentSearchResults = {
304      sliceIds: new Float64Array(0),
305      tsStarts: new Float64Array(0),
306      utids: new Float64Array(0),
307      trackIds: [],
308      sources: [],
309      totalResults: 0,
310    };
311  }
312
313  // Used when switching to the legacy TraceViewer UI.
314  // Most resources are cleaned up by replacing the current |window| object,
315  // however pending RAFs and workers seem to outlive the |window| and need to
316  // be cleaned up explicitly.
317  shutdown() {
318    this._controllerWorker!.terminate();
319    this._rafScheduler!.shutdown();
320  }
321}
322
323export const globals = new Globals();
324