Use core/stats in cputop and sched, add prio_list support
authorAntoine Busque <abusque@efficios.com>
Tue, 22 Dec 2015 03:54:06 +0000 (22:54 -0500)
committerAntoine Busque <abusque@efficios.com>
Thu, 11 Feb 2016 18:58:52 +0000 (13:58 -0500)
Signed-off-by: Antoine Busque <abusque@efficios.com>
lttnganalyses/cli/cputop.py
lttnganalyses/core/cputop.py
lttnganalyses/core/sched.py
lttnganalyses/core/stats.py
lttnganalyses/linuxautomaton/sched.py

index 17d6f214e29c126111c1feab490f2954b58db29c..38e9d7ca4a1f4e710064d8b691ab3e8afd5fc1ae 100644 (file)
@@ -45,7 +45,7 @@ class Cputop(Command):
             '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),
             ]
         ),
@@ -114,10 +114,13 @@ class Cputop(Command):
         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
index e77ef75fa51a9d0ddfeec6de8e4d0eb586226f53..43355458343989f3104cfbd01dc6c1c998229de6 100644 (file)
@@ -21,6 +21,7 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
+from . import stats
 from .analysis import Analysis
 
 
@@ -29,7 +30,8 @@ class Cputop(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)
@@ -44,11 +46,15 @@ class Cputop(Analysis):
         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()
@@ -126,11 +132,12 @@ class Cputop(Analysis):
             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']
@@ -147,6 +154,16 @@ class Cputop(Analysis):
 
         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:
@@ -173,38 +190,29 @@ class CpuUsageStats():
         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
index dbab32208a311dfb6860c2e1160b425576ea9a8e..df38e94603b213aeef9783f8e96f9795402d6770 100644 (file)
 # 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 = {
@@ -85,11 +82,12 @@ class SchedAnalysis(Analysis):
 
         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(
@@ -118,19 +116,14 @@ class SchedAnalysis(Analysis):
         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):
@@ -146,17 +139,12 @@ class SchedStats():
         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():
index 8c15567a67149bb3d130b2e2caf062fc94708433..df0de09d005ca7e8926e5fdf8088408e51d975fb 100644 (file)
 # 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()
@@ -30,11 +36,20 @@ class Process(Stats):
         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):
index 4e5b076de71130a12047db997dfdac760c5cad83..659989ea1400d2f92bd16a4a82b096719f460fed 100644 (file)
@@ -131,9 +131,9 @@ class SchedStateProvider(sp.StateProvider):
         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']
This page took 0.02841 seconds and 5 git commands to generate.