# PerfettoSQL Common Queries

This page acts as a reference guide for queries which often appear when
performing ad-hoc analysis.

## Computing CPU time for slices
If collecting traces which including scheduling information (i.e. from ftrace)
as well as userspace slices (i.e. from atrace), the actual time spent running
on a CPU for each userspace slice can be computed: this is commonly known as
the "CPU time" for a slice.

Firstly, setup the views to simplify subsequent queries:
```
DROP VIEW IF EXISTS slice_with_utid;
CREATE VIEW slice_with_utid AS
SELECT
  ts,
  dur,
  slice.name as slice_name,
  slice.id as slice_id, utid,
  thread.name as thread_name
FROM slice
JOIN thread_track ON thread_track.id = slice.track_id
JOIN thread USING (utid);

DROP TABLE IF EXISTS slice_thread_state_breakdown;
CREATE VIRTUAL TABLE slice_thread_state_breakdown
USING SPAN_LEFT_JOIN(
  slice_with_utid PARTITIONED utid,
  thread_state PARTITIONED utid
);
```

Then, to compute the CPU time for all slices in the trace:
```
SELECT slice_id, slice_name, SUM(dur) AS cpu_time
FROM slice_thread_state_breakdown
WHERE state = 'Running'
GROUP BY slice_id;
```

You can also compute CPU time for a specific slice:
```
SELECT slice_name, SUM(dur) AS cpu_time
FROM slice_thread_state_breakdown
WHERE slice_id = <your slice id> AND state = 'Running';
```

These queries can be varied easily to compute other similar metrics.
For example to get the time spent "runnable" and in "uninterruptible sleep":
```
SELECT
  slice_id,
  slice_name,
  SUM(IIF(state = 'R', dur, 0)) AS runnable_time,
  SUM(IIF(state = 'D', dur, 0)) AS uninterruptible_time
FROM slice_thread_state_breakdown
GROUP BY slice_id;
```

## Computing scheduling time by woken threads
A given thread might cause other threads to wake up i.e. because work was
scheduled on them. For a given thread, the amount of time threads it
woke up ran for can be a good proxy to understand how much work is being
spawned.

To compute this, the following query can be used:
```
SELECT
  SUM((
    SELECT dur FROM sched
    WHERE
      sched.ts > wakee_runnable.ts AND
      wakee_runnable.utid = wakee_runnable.utid
    ORDER BY ts
    LIMIT 1
  )) AS scheduled_dur
FROM thread AS waker
JOIN thread_state AS wakee_runnable ON waker.utid = wakee_runnable.waker_utid
WHERE waker.name = <your waker thread name here>
```

To do this for all the threads in the trace simultaenously:
```
SELECT
  waker_process.name AS process_name,
  waker.name AS thread_name,
  SUM((
    SELECT dur FROM sched
    WHERE
      sched.ts > wakee_runnable.ts AND
      sched.utid = wakee_runnable.utid
    ORDER BY ts
    LIMIT 1
  )) AS scheduled_dur
FROM thread AS waker
JOIN process AS waker_process USING (upid)
JOIN thread_state AS wakee_runnable ON waker.utid = wakee_runnable.waker_utid
WHERE waker.utid != 0
GROUP BY 1, 2
ORDER BY 3 desc
```
