From cf3b4aa11701502fc00905ca9b5925017ec2dfbc Mon Sep 17 00:00:00 2001
From: Gopi Krishna Nedanuri <gnedanur@codeaurora.org>
Date: Tue, 4 Aug 2015 11:33:49 +0530
Subject: [PATCH] linux-ramdump-parser-v2: Add support to dump task schedule
 stats

Add support to print all schedule stats like last_arrival, last_queued,
pcount, run_delay to a file per core. Files are sorted based on the
last_arrival.

Change-Id: If247ad393d861532872c4a31b206e8c1499de571
---
 linux-ramdump-parser-v2/parsers/taskdump.py | 107 ++++++++++++++++++++
 1 file changed, 107 insertions(+)
 mode change 100644 => 100755 linux-ramdump-parser-v2/parsers/taskdump.py

diff --git a/linux-ramdump-parser-v2/parsers/taskdump.py b/linux-ramdump-parser-v2/parsers/taskdump.py
old mode 100644
new mode 100755
index 14db15d..2944c04
--- a/linux-ramdump-parser-v2/parsers/taskdump.py
+++ b/linux-ramdump-parser-v2/parsers/taskdump.py
@@ -169,6 +169,108 @@ def do_dump_stacks(ramdump, check_for_panic=0):
         task_out.close()
         print_out_str('---wrote tasks to tasks.txt')
 
+def do_dump_task_timestamps(ramdump):
+    offset_tasks = ramdump.field_offset('struct task_struct', 'tasks')
+    offset_comm = ramdump.field_offset('struct task_struct', 'comm')
+    offset_thread_group = ramdump.field_offset(
+        'struct task_struct', 'thread_group')
+    offset_pid = ramdump.field_offset('struct task_struct', 'pid')
+    init_addr = ramdump.addr_lookup('init_task')
+    init_next_task = init_addr + offset_tasks
+    orig_init_next_task = init_next_task
+    init_thread_group = init_addr + offset_thread_group
+    seen_tasks = []
+    task_out = []
+    no_of_cpus = ramdump.get_num_cpus()
+    t = [[] for j in range(no_of_cpus)]
+    for i in range(0, no_of_cpus):
+        task_file = ramdump.open_file('tasks_sched_stats{0}.txt'.format(i))
+        task_out.append(task_file)
+    while True:
+        ret = dump_thread_group_timestamps(ramdump, init_thread_group,t)
+        if ret == False:
+            break
+        next_task = ramdump.read_word(init_next_task)
+        if next_task is None:
+            break
+
+        if (next_task == init_next_task) and (next_task != orig_init_next_task):
+            break
+
+        if (next_task in seen_tasks):
+            break
+
+        seen_tasks.append(next_task)
+
+        init_next_task = next_task
+        init_thread_group = init_next_task - offset_tasks + offset_thread_group
+        if init_next_task == orig_init_next_task:
+            break
+    for i in range(0, no_of_cpus):
+        t[i] = sorted(t[i],key=lambda l:l[2], reverse=True)
+        str = '{0:<17s}{1:>8s}{2:>17s}{3:>17s}{4:>17s}{5:>17s}\n'.format('Task name','PID','Exec_Started_at','Last_Queued_at','Total_wait_time','No_of_times_exec')
+        task_out[i].write(str)
+        for item in t[i]:
+            str = '{0:<17s}{1:8d}{2:17d}{3:17d}{4:17d}{5:17d}\n'.format(item[0],item[1],item[2],item[3],item[4],item[5])
+            task_out[i].write(str)
+        task_out[i].close()
+        print_out_str('---wrote tasks to tasks_sched_stats{0}.txt'.format(i))
+
+def dump_thread_group_timestamps(ramdump, thread_group, t):
+    offset_thread_group = ramdump.field_offset(
+        'struct task_struct', 'thread_group')
+    offset_comm = ramdump.field_offset('struct task_struct', 'comm')
+    offset_pid = ramdump.field_offset('struct task_struct', 'pid')
+    offset_cpu = ramdump.field_offset('struct thread_info', 'cpu')
+    offset_task = ramdump.field_offset('struct thread_info', 'task')
+    offset_stack = ramdump.field_offset('struct task_struct', 'stack')
+    offset_schedinfo = ramdump.field_offset('struct task_struct', 'sched_info')
+    offset_last_arrival = offset_schedinfo + ramdump.field_offset('struct sched_info', 'last_arrival')
+    offset_last_queued = offset_schedinfo + ramdump.field_offset('struct sched_info', 'last_queued')
+    offset_last_pcount = offset_schedinfo + ramdump.field_offset('struct sched_info', 'pcount')
+    offset_last_rundelay = offset_schedinfo + ramdump.field_offset('struct sched_info', 'run_delay')
+    orig_thread_group = thread_group
+    first = 0
+    seen_threads = []
+
+    while True:
+        next_thread_start = thread_group - offset_thread_group
+        next_thread_comm = next_thread_start + offset_comm
+        next_thread_pid = next_thread_start + offset_pid
+        next_thread_last_arrival = next_thread_start + offset_last_arrival
+        next_thread_last_queued = next_thread_start + offset_last_queued
+        next_thread_pcount = next_thread_start + offset_last_pcount
+        next_thread_run_delay = next_thread_start + offset_last_rundelay
+        next_thread_stack = next_thread_start + offset_stack
+        addr_stack = ramdump.read_word(next_thread_stack)
+        if addr_stack is None:
+            print_out_str('!!!! Task list corruption\n')
+            return False
+        threadinfo = addr_stack
+        thread_task_name = cleanupString(
+            ramdump.read_cstring(next_thread_comm, 16))
+        thread_task_pid = ramdump.read_int(next_thread_pid)
+        cpu_no = ramdump.read_int(threadinfo + offset_cpu)
+        thread_info_task = ramdump.read_word(threadinfo + offset_task)
+        if next_thread_start != thread_info_task:
+            print_out_str('!!!! Task list or Thread info corruption\n{0}  {1}'.format(next_thread_start,thread_info_task))
+            return False
+        t[cpu_no].append([thread_task_name, thread_task_pid, ramdump.read_word(next_thread_last_arrival),
+            ramdump.read_int(next_thread_last_queued),
+            ramdump.read_int(next_thread_run_delay),ramdump.read_int(next_thread_pcount)])
+        next_thr = ramdump.read_word(thread_group)
+        if (next_thr == thread_group) and (next_thr != orig_thread_group):
+            print_out_str('!!!! Cycle in thread group! The list is corrupt!\n')
+            return False
+        if (next_thr in seen_threads):
+            break
+
+        seen_threads.append(next_thr)
+        thread_group = next_thr
+        if thread_group == orig_thread_group:
+            break
+    return True
+
 
 @register_parser('--print-tasks', 'Print all the task information', shortopt='-t')
 class DumpTasks(RamParser):
@@ -176,6 +278,11 @@ class DumpTasks(RamParser):
     def parse(self):
         do_dump_stacks(self.ramdump, 0)
 
+@register_parser('--print-tasks-timestamps', 'Print all the task sched stats per core sorted on arrival time', shortopt='-T')
+class DumpTasksTimeStamps(RamParser):
+
+    def parse(self):
+        do_dump_task_timestamps(self.ramdump)
 
 @register_parser('--check-for-panic', 'Check if a kernel panic occured', shortopt='-p')
 class CheckForPanic(RamParser):
-- 
GitLab