Home | History | Annotate | Download | only in frontend
      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 
     15 import {assertExists} from '../base/logging';
     16 import {Actions, DeferredAction} from '../common/actions';
     17 import {createEmptyState, State} from '../common/state';
     18 
     19 import {FrontendLocalState} from './frontend_local_state';
     20 import {RafScheduler} from './raf_scheduler';
     21 
     22 type Dispatch = (action: DeferredAction) => void;
     23 type TrackDataStore = Map<string, {}>;
     24 type QueryResultsStore = Map<string, {}>;
     25 export 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 
     35 export interface QuantizedLoad {
     36   startSec: number;
     37   endSec: number;
     38   load: number;
     39 }
     40 type OverviewStore = Map<string, QuantizedLoad[]>;
     41 
     42 export interface ThreadDesc {
     43   utid: number;
     44   tid: number;
     45   threadName: string;
     46   pid?: number;
     47   procName?: string;
     48 }
     49 type ThreadMap = Map<number, ThreadDesc>;
     50 
     51 /**
     52  * Global accessors for state/dispatch in the frontend.
     53  */
     54 class 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 
    184 export const globals = new Globals();
    185