blob: 073814cb6687893f7c266f5f4cf7f7e2e0bbf2d7 [file] [log] [blame]
Michail Schwab20bab202018-08-02 18:17:44 -04001// 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 * as m from 'mithril';
16
Hector Dearman03f962c2018-08-09 17:00:32 +010017import {
Hector Dearman5ae82472018-10-03 08:30:35 +010018 Actions,
Hector Dearman03f962c2018-08-09 17:00:32 +010019 createPermalink,
20 navigate,
21 openTraceFromFile,
22 openTraceFromUrl
23} from '../common/actions';
Primiano Tucci21b91bf2018-08-06 16:42:07 +010024
25import {globals} from './globals';
Primiano Tucci21b91bf2018-08-06 16:42:07 +010026
Hector Dearman59fc2ae2018-09-18 10:30:59 +010027const ALL_PROCESSES_QUERY = 'select name, pid from process order by name;';
28
29const CPU_TIME_FOR_PROCESSES = `
30select
31 process.name,
32 tot_proc/1e9 as cpu_sec
33from
34 (select
35 upid,
36 sum(tot_thd) as tot_proc
37 from
38 (select
39 utid,
40 sum(dur) as tot_thd
41 from sched group by utid)
42 join thread using(utid) group by upid)
43join process using(upid)
44order by cpu_sec desc limit 100;`;
45
46const CYCLES_PER_P_STATE_PER_CPU = `
47select ref as cpu, value as freq, sum(dur * value)/1e6 as mcycles
48from counters group by cpu, freq order by mcycles desc limit 20;`;
49
50const CPU_TIME_BY_CLUSTER_BY_PROCESS = `
51select
52thread.name as comm,
53case when cpug = 0 then 'big' else 'little' end as core,
54cpu_sec from
55 (select cpu/4 cpug, utid, sum(dur)/1e9 as cpu_sec
56 from sched group by utid, cpug order by cpu_sec desc)
57left join thread using(utid)
58limit 20;`;
59
60function createCannedQuery(query: string): (_: Event) => void {
61 return (e: Event) => {
62 e.preventDefault();
Hector Dearman5ae82472018-10-03 08:30:35 +010063 globals.dispatch(Actions.executeQuery({
64 engineId: '0',
65 queryId: 'command',
66 query,
67 }));
Hector Dearman59fc2ae2018-09-18 10:30:59 +010068 };
69}
70
Hector Dearman8f247a32018-09-19 15:45:32 +010071const EXAMPLE_ANDROID_TRACE_URL =
Primiano Tucci21b91bf2018-08-06 16:42:07 +010072 'https://storage.googleapis.com/perfetto-misc/example_trace_30s';
73
Hector Dearman8f247a32018-09-19 15:45:32 +010074const EXAMPLE_CHROME_TRACE_URL =
75 'https://storage.googleapis.com/perfetto-misc/example_chrome_trace_10s.json';
76
Primiano Tucci21b91bf2018-08-06 16:42:07 +010077const SECTIONS = [
78 {
79 title: 'Traces',
80 summary: 'Open or record a trace',
81 expanded: true,
82 items: [
83 {t: 'Open trace file', a: popupFileSelectionDialog, i: 'folder_open'},
Hector Dearman8f247a32018-09-19 15:45:32 +010084 {
85 t: 'Open Android example',
86 a: openTraceUrl(EXAMPLE_ANDROID_TRACE_URL),
87 i: 'description'
88 },
89 {
90 t: 'Open Chrome example',
91 a: openTraceUrl(EXAMPLE_CHROME_TRACE_URL),
92 i: 'description'
93 },
Hector Dearman4544f372018-09-19 12:32:36 +010094 {t: 'Record new trace', a: navigateRecord, i: 'fiber_smart_record'},
Hector Dearman03f962c2018-08-09 17:00:32 +010095 {t: 'Share current trace', a: dispatchCreatePermalink, i: 'share'},
Primiano Tucci21b91bf2018-08-06 16:42:07 +010096 ],
Michail Schwab20bab202018-08-02 18:17:44 -040097 },
Primiano Tucci21b91bf2018-08-06 16:42:07 +010098 {
99 title: 'Workspaces',
100 summary: 'Custom and pre-arranged views',
101 items: [
102 {t: 'Big Picture', a: navigateHome, i: 'art_track'},
103 {t: 'Apps and process', a: navigateHome, i: 'apps'},
104 {t: 'Storage and I/O', a: navigateHome, i: 'storage'},
105 {t: 'Add custom...', a: navigateHome, i: 'library_add'},
106 ],
107 },
108 {
109 title: 'Tracks and views',
110 summary: 'Add new tracks to the workspace',
111 items: [
112 {t: 'User interactions', a: navigateHome, i: 'touch_app'},
113 {t: 'Device info', a: navigateHome, i: 'perm_device_information'},
114 {t: 'Scheduler trace', a: navigateHome, i: 'blur_linear'},
115 {t: 'Process list', a: navigateHome, i: 'equalizer'},
116 {t: 'Battery and power', a: navigateHome, i: 'battery_alert'},
117 ],
118 },
119 {
120 title: 'Metrics and auditors',
121 summary: 'Add new tracks to the workspace',
122 items: [
Hector Dearman59fc2ae2018-09-18 10:30:59 +0100123 {
124 t: 'All Processes',
125 a: createCannedQuery(ALL_PROCESSES_QUERY),
126 i: 'search',
127 },
128 {
129 t: 'CPU Time by process',
130 a: createCannedQuery(CPU_TIME_FOR_PROCESSES),
131 i: 'search',
132 },
133 {
134 t: 'Cycles by p-state by CPU',
135 a: createCannedQuery(CYCLES_PER_P_STATE_PER_CPU),
136 i: 'search',
137 },
138 {
139 t: 'CPU Time by cluster by process',
140 a: createCannedQuery(CPU_TIME_BY_CLUSTER_BY_PROCESS),
141 i: 'search',
142 },
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100143 ],
144 },
145];
146
147function popupFileSelectionDialog(e: Event) {
148 e.preventDefault();
149 (document.querySelector('input[type=file]')! as HTMLInputElement).click();
150}
151
Hector Dearman8f247a32018-09-19 15:45:32 +0100152function openTraceUrl(url: string): (e: Event) => void {
153 return e => {
154 e.preventDefault();
155 globals.dispatch(openTraceFromUrl(url));
156 };
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100157}
158
159function onInputElementFileSelectionChanged(e: Event) {
160 if (!(e.target instanceof HTMLInputElement)) {
161 throw new Error('Not an input element');
162 }
163 if (!e.target.files) return;
164 globals.dispatch(openTraceFromFile(e.target.files[0]));
165}
166
Hector Dearman4544f372018-09-19 12:32:36 +0100167function navigateHome(e: Event) {
168 e.preventDefault();
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100169 globals.dispatch(navigate('/'));
170}
171
Hector Dearman4544f372018-09-19 12:32:36 +0100172function navigateRecord(e: Event) {
173 e.preventDefault();
174 globals.dispatch(navigate('/record'));
175}
176
Deepanjan Roy112ff6a2018-09-10 08:31:43 -0400177function dispatchCreatePermalink(e: Event) {
178 e.preventDefault();
Hector Dearman03f962c2018-08-09 17:00:32 +0100179 globals.dispatch(createPermalink());
180}
181
Deepanjan Roy97f63242018-09-20 15:32:01 -0400182export class Sidebar implements m.ClassComponent {
Michail Schwab20bab202018-08-02 18:17:44 -0400183 view() {
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100184 const vdomSections = [];
185 for (const section of SECTIONS) {
186 const vdomItems = [];
187 for (const item of section.items) {
188 vdomItems.push(
189 m('li',
190 m(`a[href=#]`,
Deepanjan Roy112ff6a2018-09-10 08:31:43 -0400191 {onclick: item.a},
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100192 m('i.material-icons', item.i),
193 item.t)));
194 }
195 vdomSections.push(
196 m(`section${section.expanded ? '.expanded' : ''}`,
Hector Dearman250376b2018-08-07 11:15:52 +0100197 m('.section-header',
Deepanjan Roy112ff6a2018-09-10 08:31:43 -0400198 {
199 onclick: () => {
200 section.expanded = !section.expanded;
201 globals.rafScheduler.scheduleFullRedraw();
202 }
203 },
Hector Dearman250376b2018-08-07 11:15:52 +0100204 m('h1', section.title),
205 m('h2', section.summary), ),
206 m('.section-content', m('ul', vdomItems))));
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100207 }
Michail Schwab20bab202018-08-02 18:17:44 -0400208 return m(
209 'nav.sidebar',
210 m('header', 'Perfetto'),
Deepanjan Roy112ff6a2018-09-10 08:31:43 -0400211 m('input[type=file]', {onchange: onInputElementFileSelectionChanged}),
Primiano Tucci21b91bf2018-08-06 16:42:07 +0100212 ...vdomSections);
Deepanjan Roy97f63242018-09-20 15:32:01 -0400213 }
214}