Merge "Create a reusable thread_state table"
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index e2f692e..ffa27e1 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -276,6 +276,7 @@
await this.listThreads();
await this.loadTimelineOverview(traceTime);
+ await this.initaliseHelperViews();
return engineMode;
}
@@ -796,6 +797,68 @@
globals.publish('OverviewData', slicesData);
}
+ async initaliseHelperViews() {
+ const engine = assertExists<Engine>(this.engine);
+ let event = 'sched_waking';
+ const waking = await engine.query(
+ `select * from instants where name = 'sched_waking' limit 1`);
+ if (waking.numRecords === 0) {
+ // Only use sched_wakeup if sched_waking is not in the trace.
+ event = 'sched_wakeup';
+ }
+ await engine.query(`create view runnable AS
+ select
+ ts,
+ lead(ts, 1, (select end_ts from trace_bounds))
+ OVER(partition by ref order by ts) - ts as dur,
+ ref as utid
+ from instants
+ where name = '${event}'`);
+
+ // Get the first ts for each utid - whether a sched wakeup/waking
+ // or sched event.
+ await engine.query(`create view first_thread as
+ select min(ts) as ts, utid from
+ (select min(ts) as ts, utid from runnable group by utid
+ UNION
+ select min(ts) as ts,utid from sched group by utid)
+ group by utid`);
+
+ // Create an entry from first ts to either the first sched_wakeup/waking
+ // or to the end if there are no sched wakeup/ings. This means we will
+ // show all information we have even with no sched_wakeup/waking events.
+ await engine.query(`create view fill as
+ select first_thread.ts as ts,
+ coalesce(min(runnable.ts), (select end_ts from trace_bounds)) -
+ first_thread.ts as dur,
+ runnable.utid as utid
+ from runnable
+ JOIN first_thread using(utid) group by utid`);
+
+ await engine.query(`create view full_runnable as
+ select * from runnable UNION
+ select * from fill`);
+
+ await engine.query(`create virtual table thread_span
+ using span_left_join(
+ full_runnable partitioned utid,
+ sched partitioned utid)`);
+
+ // For performance reasons we need to create a table here.
+ // Once b/145350531 is fixed this should be able to revert to a
+ // view and we can recover the extra memory use.
+ await engine.query(`create table thread_state as
+ select ts, dur, utid, cpu,
+ case when end_state is not null then 'Running'
+ when lag(end_state) over ordered is not null
+ then lag(end_state) over ordered else 'Runnable'
+ end as state
+ from thread_span window ordered as
+ (partition by utid order by ts)`);
+
+ await engine.query(`create index utid_index on thread_state(utid)`);
+ }
+
private updateStatus(msg: string): void {
globals.dispatch(Actions.updateStatus({
msg,
diff --git a/ui/src/tracks/thread_state/controller.ts b/ui/src/tracks/thread_state/controller.ts
index 7c29edb..2c90c0d 100644
--- a/ui/src/tracks/thread_state/controller.ts
+++ b/ui/src/tracks/thread_state/controller.ts
@@ -42,81 +42,21 @@
}
if (this.setup === false) {
- let event = 'sched_waking';
- const waking = await this.query(
- `select * from instants where name = 'sched_waking' limit 1`);
- if (waking.numRecords === 0) {
- // Only use sched_wakeup if sched_waking is not in the trace.
- event = 'sched_wakeup';
- }
- await this.query(`create view ${this.tableName('runnable')} AS
- select
- ts,
- lead(ts, 1, (select end_ts from trace_bounds))
- OVER(order by ts) - ts as dur,
- ref as utid
- from instants
- where name = '${event}'
- and utid = ${this.config.utid}`);
-
await this.query(
`create virtual table ${this.tableName('window')} using window;`);
- // Get the first ts for this utid - whether a sched wakeup/waking
- // or sched event.
- await this.query(`create view ${this.tableName('start')} as
- select min(ts) as ts from
- (select ts from ${this.tableName('runnable')} UNION
- select ts from sched where utid = ${this.config.utid})`);
-
- // Create an entry from first ts to either the first sched_wakeup/waking
- // or to the end if there are no sched wakeup/ings. This means we will
- // show all information we have even with no sched_wakeup/waking events.
- await this.query(`create view ${this.tableName('fill')} AS
- select
- (select ts from ${this.tableName('start')}),
- (select coalesce(
- (select min(ts) from ${this.tableName('runnable')}),
- (select end_ts from trace_bounds)
- )) - (select ts from ${this.tableName('start')}) as dur,
- ${this.config.utid} as utid
- `);
-
- await this.query(`create view ${this.tableName('full_runnable')} as
- select * from ${this.tableName('runnable')} UNION
- select * from ${this.tableName('fill')}`);
-
- await this.query(`create virtual table ${this.tableName('span')}
- using span_left_join(
- ${this.tableName('full_runnable')} partitioned utid,
- sched partitioned utid)`);
-
- // Need to compute the lag(end_state) before joining with the window
- // table to avoid the first visible slice always having a null prev
- // end state.
- await this.query(`create view ${this.tableName('span_view')} as
- select ts, dur, utid, cpu,
- case
- when end_state is not null
- then 'Running'
- when lag(end_state) over ${this.tableName('ordered')} is not null
- then lag(end_state) over ${this.tableName('ordered')}
- else 'Runnable'
- end as state
- from ${this.tableName('span')}
- where utid = ${this.config.utid}
- window ${this.tableName('ordered')} as (order by ts)`);
-
await this.query(`create view ${this.tableName('long_states')} as
- select * from ${this.tableName('span_view')} where dur >= ${minNs}`);
+ select * from thread_state where dur >= ${minNs} and utid = ${
+ this.config.utid}`);
// Create a slice from the first ts to the end of the trace. To
// be span joined with the long states - This effectively combines all
// of the short states into a single 'Busy' state.
await this.query(`create view ${this.tableName('fill_gaps')} as select
- (select min(ts) from ${this.tableName('span_view')}) as ts,
+ (select min(ts) from thread_state where utid = ${this.config.utid}) as ts,
(select end_ts from trace_bounds) -
- (select min(ts) from ${this.tableName('span_view')}) as dur,
+ (select min(ts) from thread_state where utid = ${
+ this.config.utid}) as dur,
${this.config.utid} as utid`);
await this.query(`create virtual table ${this.tableName('summarized')}
@@ -128,7 +68,6 @@
${this.tableName('window')},
${this.tableName('summarized')} partitioned utid)`);
-
this.setup = true;
}
@@ -143,13 +82,15 @@
this.query(`drop view if exists ${this.tableName('fill_gaps')}`);
await this.query(`create view ${this.tableName('long_states')} as
- select * from ${this.tableName('span_view')} where dur > ${minNs}`);
+ select * from thread_state where dur >= ${minNs} and utid = ${
+ this.config.utid}`);
await this.query(`create view ${this.tableName('fill_gaps')} as select
- (select min(ts) from ${this.tableName('span_view')}) as ts,
- (select end_ts from trace_bounds) - (select min(ts) from ${
- this.tableName('span_view')}) as dur,
- ${this.config.utid} as utid, -1 as cpu`);
+ (select min(ts) from thread_state where utid = ${this.config.utid}) as ts,
+ (select end_ts from trace_bounds) -
+ (select min(ts) from thread_state where utid = ${
+ this.config.utid}) as dur,
+ ${this.config.utid} as utid`);
const query = `select ts, cast(dur as double), utid,
case when state is not null then state else 'Busy' end as state,
@@ -197,13 +138,8 @@
onDestroy(): void {
if (this.setup) {
this.query(`drop table ${this.tableName('window')}`);
- this.query(`drop table ${this.tableName('span')}`);
this.query(`drop table ${this.tableName('current')}`);
this.query(`drop table ${this.tableName('summarized')}`);
- this.query(`drop view ${this.tableName('runnable')}`);
- this.query(`drop view ${this.tableName('fill')}`);
- this.query(`drop view ${this.tableName('full_runnable')}`);
- this.query(`drop view ${this.tableName('span_view')}`);
this.query(`drop view ${this.tableName('long_states')}`);
this.query(`drop view ${this.tableName('fill_gaps')}`);
this.setup = false;