'Per-TID top CPU usage', [
('process', 'Process', mi.Process),
('migrations', 'Migration count', mi.Integer, 'migrations'),
- ('priority', 'Priority', mi.Integer),
+ ('prio_list', 'Chronological priorities', mi.String),
('usage', 'CPU usage', mi.Ratio),
]
),
for tid in sorted(self._analysis.tids.values(),
key=operator.attrgetter('usage_percent'),
reverse=True):
+ prio_list = str([prio_evt.prio for
+ prio_evt in tid.prio_list])
+
result_table.append_row(
process=mi.Process(tid.comm, tid=tid.tid),
migrations=mi.Integer(tid.migrate_count),
- priority=mi.Integer(tid.prio),
+ prio_list=mi.String(prio_list),
usage=mi.Ratio.from_percentage(tid.usage_percent)
)
count += 1
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+from . import stats
from .analysis import Analysis
notification_cbs = {
'sched_migrate_task': self._process_sched_migrate_task,
'sched_switch_per_cpu': self._process_sched_switch_per_cpu,
- 'sched_switch_per_tid': self._process_sched_switch_per_tid
+ 'sched_switch_per_tid': self._process_sched_switch_per_tid,
+ 'prio_changed': self._process_prio_changed,
}
super().__init__(state, conf)
self._ev_count += 1
def reset(self):
- for cpu_id in self.cpus:
- self.cpus[cpu_id].reset(self._last_event_ts)
+ for cpu_stats in self.cpus.values():
+ cpu_stats.reset()
+ if cpu_stats.last_sched_ts is not None:
+ cpu_stats.current_task_start_ts = self._last_event_ts
- for tid in self.tids:
- self.tids[tid].reset(self._last_event_ts)
+ for proc_stats in self.tids.values():
+ proc_stats.reset()
+ if proc_stats.last_sched_ts is not None:
+ proc_stats.last_sched_ts = self._last_event_ts
def _end_period_cb(self):
self._compute_stats()
return
if next_tid not in self.tids:
- self.tids[next_tid] = ProcessCpuStats(next_tid, next_comm)
+ self.tids[next_tid] = ProcessCpuStats(None, next_tid, next_comm)
+ self.tids[next_tid].update_prio(timestamp, wakee_proc.prio)
next_proc = self.tids[next_tid]
next_proc.last_sched_ts = timestamp
- next_proc.prio = wakee_proc.prio
+
def _process_sched_migrate_task(self, **kwargs):
cpu_id = kwargs['cpu_id']
self.tids[tid].migrate_count += 1
+ def _process_prio_changed(self, **kwargs):
+ timestamp = kwargs['timestamp']
+ prio = kwargs['prio']
+ tid = kwargs['tid']
+
+ if tid not in self.tids:
+ return
+
+ self.tids[tid].update_prio(timestamp, prio)
+
def _filter_process(self, proc):
# Exclude swapper
if proc.tid == 0:
else:
self.usage_percent = 0
- def reset(self, timestamp):
+ def reset(self):
self.total_usage_time = 0
self.usage_percent = None
- if self.current_task_start_ts is not None:
- self.current_task_start_ts = timestamp
-class ProcessCpuStats():
- def __init__(self, tid, comm):
- self.tid = tid
- self.comm = comm
- # Currently only the latest prio is tracked
- self.prio = None
+class ProcessCpuStats(stats.Process):
+ def __init__(self, pid, tid, comm):
+ super().__init__(pid, tid, comm)
+
# CPU Time and timestamp in nanoseconds (ns)
self.total_cpu_time = 0
self.last_sched_ts = None
self.migrate_count = 0
self.usage_percent = None
- @classmethod
- def new_from_process(cls, proc):
- return cls(proc.tid, proc.comm)
-
def compute_stats(self, duration):
if duration != 0:
self.usage_percent = self.total_cpu_time * 100 / duration
else:
self.usage_percent = 0
- def reset(self, timestamp):
+ def reset(self):
+ super().reset()
self.total_cpu_time = 0
self.migrate_count = 0
self.usage_percent = None
- if self.last_sched_ts is not None:
- self.last_sched_ts = timestamp
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-from collections import namedtuple
+from . import stats
from .analysis import Analysis
-PrioEvent = namedtuple('PrioEvent', ['timestamp', 'prio'])
-
-
class SchedAnalysis(Analysis):
def __init__(self, state, conf):
notification_cbs = {
if waker_proc is not None and waker_proc.tid not in self.tids:
self.tids[waker_proc.tid] = \
- SchedStats.new_from_process(waker_proc)
+ ProcessSchedStats.new_from_process(waker_proc)
self.tids[waker_proc.tid].update_prio(switch_ts, waker_proc.prio)
if next_tid not in self.tids:
- self.tids[next_tid] = SchedStats.new_from_process(wakee_proc)
+ self.tids[next_tid] = \
+ ProcessSchedStats.new_from_process(wakee_proc)
self.tids[next_tid].update_prio(switch_ts, wakee_proc.prio)
sched_event = SchedEvent(
self.sched_list.append(sched_event)
-class SchedStats():
- def __init__(self, tid, comm):
- self.tid = tid
- self.comm = comm
+class ProcessSchedStats(stats.Process):
+ def __init__(self, pid, tid, comm):
+ super().__init__(pid, tid, comm)
+
self.min_latency = None
self.max_latency = None
self.total_latency = 0
self.sched_list = []
- self.prio_list = []
-
- @classmethod
- def new_from_process(cls, proc):
- return cls(proc.tid, proc.comm)
@property
def count(self):
self.total_latency += sched_event.latency
self.sched_list.append(sched_event)
- def update_prio(self, timestamp, prio):
- self.prio_list.append(PrioEvent(timestamp, prio))
-
def reset(self):
+ super().reset()
self.min_latency = None
self.max_latency = None
self.total_latency = 0
self.sched_list = []
- if self.prio_list:
- # Keep the last prio as the first for the next period
- self.prio_list = self.prio_list[-1:]
class SchedEvent():
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+from collections import namedtuple
+
+
+PrioEvent = namedtuple('PrioEvent', ['timestamp', 'prio'])
+
+
class Stats():
def reset(self):
raise NotImplementedError()
self.pid = pid
self.tid = tid
self.comm = comm
+ self.prio_list = []
@classmethod
def new_from_process(cls, proc):
return cls(proc.pid, proc.tid, proc.comm)
+ def update_prio(self, timestamp, prio):
+ self.prio_list.append(PrioEvent(timestamp, prio))
+
+ def reset(self):
+ if self.prio_list:
+ # Keep the last prio as the first for the next period
+ self.prio_list = self.prio_list[-1:]
+
class IO(Stats):
def __init__(self):
else:
proc = self._state.tids[tid]
- self._check_prio_changed(event.timestamp, tid, prio)
self._state.send_notification_cb(
'sched_migrate_task', proc=proc, cpu_id=event['cpu_id'])
+ self._check_prio_changed(event.timestamp, tid, prio)
def _process_sched_wakeup(self, event):
target_cpu = event['target_cpu']