• 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 {Actions, DeferredAction} from '../common/actions';
17import {createEmptyState, State} from '../common/state';
18
19import {FrontendLocalState} from './frontend_local_state';
20import {RafScheduler} from './raf_scheduler';
21
22type Dispatch = (action: DeferredAction) => void;
23type TrackDataStore = Map<string, {}>;
24type QueryResultsStore = Map<string, {}>;
25export interface SliceDetails {
26  ts?: number;
27  dur?: number;
28  priority?: number;
29  endState?: string;
30  wakeupTs?: number;
31  wakerUtid?: number;
32  wakerCpu?: number;
33}
34
35export interface QuantizedLoad {
36  startSec: number;
37  endSec: number;
38  load: number;
39}
40type OverviewStore = Map<string, QuantizedLoad[]>;
41
42export interface ThreadDesc {
43  utid: number;
44  tid: number;
45  threadName: string;
46  pid?: number;
47  procName?: string;
48}
49type ThreadMap = Map<number, ThreadDesc>;
50
51/**
52 * Global accessors for state/dispatch in the frontend.
53 */
54class Globals {
55  private _dispatch?: Dispatch = undefined;
56  private _controllerWorker?: Worker = undefined;
57  private _state?: State = undefined;
58  private _frontendLocalState?: FrontendLocalState = undefined;
59  private _rafScheduler?: RafScheduler = undefined;
60
61  // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
62  private _trackDataStore?: TrackDataStore = undefined;
63  private _queryResults?: QueryResultsStore = undefined;
64  private _overviewStore?: OverviewStore = undefined;
65  private _threadMap?: ThreadMap = undefined;
66  private _sliceDetails?: SliceDetails = undefined;
67  private _pendingTrackRequests?: Set<string> = undefined;
68
69  initialize(dispatch: Dispatch, controllerWorker: Worker) {
70    this._dispatch = dispatch;
71    this._controllerWorker = controllerWorker;
72    this._state = createEmptyState();
73    this._frontendLocalState = new FrontendLocalState();
74    this._rafScheduler = new RafScheduler();
75
76    // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
77    this._trackDataStore = new Map<string, {}>();
78    this._queryResults = new Map<string, {}>();
79    this._overviewStore = new Map<string, QuantizedLoad[]>();
80    this._threadMap = new Map<number, ThreadDesc>();
81    this._sliceDetails = {};
82    this._pendingTrackRequests = new Set<string>();
83  }
84
85  get state(): State {
86    return assertExists(this._state);
87  }
88
89  set state(state: State) {
90    this._state = assertExists(state);
91  }
92
93  get dispatch(): Dispatch {
94    return assertExists(this._dispatch);
95  }
96
97  get frontendLocalState() {
98    return assertExists(this._frontendLocalState);
99  }
100
101  get rafScheduler() {
102    return assertExists(this._rafScheduler);
103  }
104
105  // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
106  get overviewStore(): OverviewStore {
107    return assertExists(this._overviewStore);
108  }
109
110  get trackDataStore(): TrackDataStore {
111    return assertExists(this._trackDataStore);
112  }
113
114  get queryResults(): QueryResultsStore {
115    return assertExists(this._queryResults);
116  }
117
118  get threads() {
119    return assertExists(this._threadMap);
120  }
121
122  get sliceDetails() {
123    return assertExists(this._sliceDetails);
124  }
125
126  set sliceDetails(click: SliceDetails) {
127    this._sliceDetails = assertExists(click);
128  }
129
130  setTrackData(id: string, data: {}) {
131    this.trackDataStore.set(id, data);
132    assertExists(this._pendingTrackRequests).delete(id);
133  }
134
135  getCurResolution() {
136    // Truncate the resolution to the closest power of 10.
137    const resolution = this.frontendLocalState.timeScale.deltaPxToDuration(1);
138    return Math.pow(10, Math.floor(Math.log10(resolution)));
139  }
140
141  requestTrackData(trackId: string) {
142    const pending = assertExists(this._pendingTrackRequests);
143    if (pending.has(trackId)) return;
144
145    const {visibleWindowTime} = globals.frontendLocalState;
146    const resolution = this.getCurResolution();
147    const start = visibleWindowTime.start - visibleWindowTime.duration;
148    const end = visibleWindowTime.end + visibleWindowTime.duration;
149
150    pending.add(trackId);
151    globals.dispatch(Actions.reqTrackData({
152      trackId,
153      start,
154      end,
155      resolution,
156    }));
157  }
158
159  resetForTesting() {
160    this._dispatch = undefined;
161    this._state = undefined;
162    this._frontendLocalState = undefined;
163    this._rafScheduler = undefined;
164
165    // TODO(hjd): Unify trackDataStore, queryResults, overviewStore, threads.
166    this._trackDataStore = undefined;
167    this._queryResults = undefined;
168    this._overviewStore = undefined;
169    this._threadMap = undefined;
170    this._sliceDetails = undefined;
171    this._pendingTrackRequests = undefined;
172  }
173
174  // Used when switching to the legacy TraceViewer UI.
175  // Most resources are cleaned up by replacing the current |window| object,
176  // however pending RAFs and workers seem to outlive the |window| and need to
177  // be cleaned up explicitly.
178  shutdown() {
179    this._controllerWorker!.terminate();
180    this._rafScheduler!.shutdown();
181  }
182}
183
184export const globals = new Globals();
185