1// Copyright (C) 2020 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 16import * as m from 'mithril'; 17 18import {Actions} from '../common/actions'; 19import {QueryResponse} from '../common/queries'; 20 21import {globals} from './globals'; 22import {createPage} from './pages'; 23 24 25interface StatsSectionAttrs { 26 title: string; 27 subTitle: string; 28 sqlConstraints: string; 29 cssClass: string; 30 queryId: string; 31} 32 33// Generic class that generate a <section> + <table> from the stats table. 34// The caller defines the query constraint, title and styling. 35// Used for errors, data losses and debugging sections. 36class StatsSection implements m.ClassComponent<StatsSectionAttrs> { 37 private queryDispatched = false; 38 39 view({attrs}: m.CVnode<StatsSectionAttrs>) { 40 if (!this.queryDispatched) { 41 this.queryDispatched = true; 42 globals.dispatch(Actions.executeQuery({ 43 engineId: '0', 44 queryId: attrs.queryId, 45 query: `select name, value, cast(ifnull(idx, '') as text) as idx, 46 description, severity, source from stats 47 where ${attrs.sqlConstraints || '1=1'} 48 order by name, idx`, 49 })); 50 } 51 52 const resp = globals.queryResults.get(attrs.queryId) as QueryResponse; 53 if (resp === undefined || resp.totalRowCount === 0) { 54 return m(''); 55 } 56 if (resp.error) throw new Error(resp.error); 57 58 const tableRows = []; 59 for (const row of resp.rows) { 60 const help = []; 61 if (row.description) { 62 help.push(m('i.material-icons.contextual-help', 'help_outline')); 63 } 64 const idx = row.idx !== '' ? `[${row.idx}]` : ''; 65 tableRows.push(m( 66 'tr', 67 m('td', {title: row.description}, `${row.name}${idx}`, help), 68 m('td', `${row.value}`), 69 m('td', `${row.severity} (${row.source})`), 70 )); 71 } 72 73 return m( 74 `section${attrs.cssClass}`, 75 m('h2', attrs.title), 76 m('h3', attrs.subTitle), 77 m( 78 'table', 79 m('thead', 80 m('tr', m('td', 'Name'), m('td', 'Value'), m('td', 'Type'))), 81 m('tbody', tableRows), 82 ), 83 ); 84 } 85} 86 87class MetricErrors implements m.ClassComponent { 88 view() { 89 if (!globals.metricError) return; 90 return m( 91 `section.errors`, 92 m('h2', `Metric Errors`), 93 m('h3', `One or more metrics were not computed successfully:`), 94 m('div.metric-error', globals.metricError)); 95 } 96} 97 98class TraceMetadata implements m.ClassComponent { 99 private queryDispatched = false; 100 private readonly QUERY_ID = 'info_metadata'; 101 102 view() { 103 if (!this.queryDispatched) { 104 this.queryDispatched = true; 105 globals.dispatch(Actions.executeQuery({ 106 engineId: '0', 107 queryId: this.QUERY_ID, 108 query: `select name, ifnull(str_value, cast(int_value as text)) as value 109 from metadata order by name`, 110 })); 111 } 112 113 const resp = globals.queryResults.get(this.QUERY_ID) as QueryResponse; 114 if (resp === undefined || resp.totalRowCount === 0) { 115 return m(''); 116 } 117 118 const tableRows = []; 119 for (const row of resp.rows) { 120 tableRows.push(m( 121 'tr', 122 m('td', `${row.name}`), 123 m('td', `${row.value}`), 124 )); 125 } 126 127 return m( 128 'section', 129 m('h2', 'System info and metadata'), 130 m( 131 'table', 132 m('thead', m('tr', m('td', 'Name'), m('td', 'Value'))), 133 m('tbody', tableRows), 134 ), 135 ); 136 } 137} 138 139class PackageList implements m.ClassComponent { 140 private queryDispatched = false; 141 private readonly QUERY_ID = 'info_package_list'; 142 143 view() { 144 if (!this.queryDispatched) { 145 this.queryDispatched = true; 146 globals.dispatch(Actions.executeQuery({ 147 engineId: '0', 148 queryId: this.QUERY_ID, 149 query: `select package_name, version_code, debuggable, 150 profileable_from_shell from package_list`, 151 })); 152 } 153 154 const resp = globals.queryResults.get(this.QUERY_ID) as QueryResponse; 155 if (resp === undefined || resp.totalRowCount === 0) { 156 return m(''); 157 } 158 159 const tableRows = []; 160 for (const row of resp.rows) { 161 tableRows.push(m( 162 'tr', 163 m('td', `${row.package_name}`), 164 m('td', `${row.version_code}`), 165 m('td', 166 `${row.debuggable ? 'debuggable' : ''} ${ 167 row.profileable_from_shell ? 'profileable' : ''}`), 168 )); 169 } 170 171 return m( 172 'section', 173 m('h2', 'Package list'), 174 m( 175 'table', 176 m('thead', 177 m('tr', 178 m('td', 'Name'), 179 m('td', 'Version code'), 180 m('td', 'Flags'))), 181 m('tbody', tableRows), 182 ), 183 ); 184 } 185} 186 187export const TraceInfoPage = createPage({ 188 view() { 189 return m( 190 '.trace-info-page', 191 m(MetricErrors), 192 m(StatsSection, { 193 queryId: 'info_errors', 194 title: 'Import errors', 195 cssClass: '.errors', 196 subTitle: 197 `The following errors have been encountered while importing the 198 trace. These errors are usually non-fatal but indicate that one 199 or more tracks might be missing or showing erroneous data.`, 200 sqlConstraints: `severity = 'error' and value > 0`, 201 202 }), 203 m(StatsSection, { 204 queryId: 'info_data_losses', 205 title: 'Data losses', 206 cssClass: '.errors', 207 subTitle: 208 `These counters are collected at trace recording time. The trace 209 data for one or more data sources was droppped and hence some 210 track contents will be incomplete.`, 211 sqlConstraints: `severity = 'data_loss' and value > 0`, 212 }), 213 m(TraceMetadata), 214 m(PackageList), 215 m(StatsSection, { 216 queryId: 'info_all', 217 title: 'Debugging stats', 218 cssClass: '', 219 subTitle: `Debugging statistics such as trace buffer usage and metrics 220 coming from the TraceProcessor importer stages.`, 221 sqlConstraints: '', 222 223 }), 224 ); 225 } 226}); 227