[Crash-utility] [PATCH v3] ps: Add support to "ps -l|-m" to properly display process

Austin Kim austindh.kim at gmail.com
Wed Mar 2 21:37:45 UTC 2022


Sometimes kernel image is generated without CONFIG_SCHEDSTATS or CONFIG_SCHED_INFO.
Where relevant commit id is f6db83479932 ("sched/stat: Simplify the sched_info accounting")

  - CONFIG_SCHED_INFO: KERNEL_VERSION >= LINUX(4,2,0)
  - CONFIG_SCHEDSTATS: KERNEL_VERSION < LINUX(4,2,0)

Running crash-utility with above kernel image,
"ps -l" option cannot display all processes sorted with most recently-run process.
Also "ps -m" option cannot display all processes with timestamp.

crash> ps -l or crash> ps -m
ps: last-run timestamps do not exist in this kernel
Usage: ps [-k|-u|-G] [-s]
  [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S]
     [pid | task | command] ...
Enter "help ps" for details.

This is because output of "ps -l|-m" depends on task_struct.sched_info.last_arrival.

Without CONFIG_SCHEDSTATS or CONFIG_SCHED_INFO, 'sched_info' field is not included
in task_struct.  In this case we make "ps -l|-m" option to access 'exec_start' 
field of sched_entity where 'exec_start' is task_struct.se.exec_start.

The 'task_struct.se.exec_start' contains the most recently-executed timestamp 
when process is running in the below cases;

 - enqueued to runqueue
 - dequeued from runqueue
 - scheduler tick is invoked
 - etc

'task_struct.se.exec_start' could be one of statistics which indicates the most 
recently-run timestamp of process activity.

With this patch, "ps -l|-m" option works well without CONFIG_SCHEDSTATS or
CONFIG_SCHED_INFO.

Signed-off-by: Austin Kim <austindh.kim at gmail.com>
---
 defs.h    |  1 +
 help.c    |  5 +++--
 symbols.c |  2 ++
 task.c    | 20 ++++++++++++++++----
 4 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/defs.h b/defs.h
index bf2c59b..841bd0b 100644
--- a/defs.h
+++ b/defs.h
@@ -2168,6 +2168,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long sbitmap_queue_min_shallow_depth;
 	long sbq_wait_state_wait_cnt;
 	long sbq_wait_state_wait;
+	long sched_entity_exec_start;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
diff --git a/help.c b/help.c
index 8347668..6ca7c92 100644
--- a/help.c
+++ b/help.c
@@ -1442,7 +1442,8 @@ char *help_ps[] = {
 "           and system times.",
 "       -l  display the task's last-run timestamp value, using either the",
 "           task_struct's last_run value, the task_struct's timestamp value",
-"           or the task_struct's sched_entity last_arrival value, whichever",
+"           the task_struct's sched_info last_arrival value",
+"           or the task_struct's sched_entity exec_start value, whichever",
 "           applies, of selected, or all, tasks; the list is sorted with the",
 "           most recently-run task (with the largest timestamp) shown first,",
 "           followed by the task's current state.",
@@ -1621,7 +1622,7 @@ char *help_ps[] = {
 "     >  9497      1   0  ffff880549ec2ab0  RU   0.0 42314692 138664  oracle",
 " ",
 "  Show all tasks sorted by their task_struct's last_run, timestamp, or", 
-"  sched_entity last_arrival timestamp value, whichever applies:\n",
+"  sched_info last_arrival or sched_entity exec_start timestamp value, whichever applies:\n",
 "    %s> ps -l",
 "    [20811245123] [IN] PID: 37    TASK: f7153030  CPU: 2  COMMAND: \"events/2\"",
 "    [20811229959] [IN] PID: 1756  TASK: f2a5a570  CPU: 2  COMMAND: \"ntpd\"",
diff --git a/symbols.c b/symbols.c
index ba5e274..1c40586 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10290,6 +10290,8 @@ dump_offset_table(char *spec, ulong makestruct)
 		OFFSET(sched_entity_my_q));
 	fprintf(fp, "            sched_entity_on_rq: %ld\n",
 		OFFSET(sched_entity_on_rq));
+	fprintf(fp, "            sched_entity_exec_start: %ld\n",
+		OFFSET(sched_entity_exec_start));
 	fprintf(fp, "             cfs_rq_nr_running: %ld\n",
 		OFFSET(cfs_rq_nr_running));
 	fprintf(fp, "            cfs_rq_rb_leftmost: %ld\n",
diff --git a/task.c b/task.c
index 864c838..2c12196 100644
--- a/task.c
+++ b/task.c
@@ -334,9 +334,15 @@ task_init(void)
 	if (VALID_MEMBER(task_struct_sched_info))
 		MEMBER_OFFSET_INIT(sched_info_last_arrival, 
 			"sched_info", "last_arrival");
+	MEMBER_OFFSET_INIT(task_struct_se, "task_struct", "se");
+	if (VALID_MEMBER(task_struct_se)) {
+		STRUCT_SIZE_INIT(sched_entity, "sched_entity");
+		MEMBER_OFFSET_INIT(sched_entity_exec_start, "sched_entity", "exec_start");
+	}
 	if (VALID_MEMBER(task_struct_last_run) || 
 	    VALID_MEMBER(task_struct_timestamp) ||
-	    VALID_MEMBER(sched_info_last_arrival)) {
+	    VALID_MEMBER(sched_info_last_arrival) ||
+	    VALID_MEMBER(sched_entity_exec_start)) {
 		char buf[BUFSIZE];
 	        strcpy(buf, "alias last ps -l");
         	alias_init(buf);
@@ -3559,7 +3565,8 @@ cmd_ps(void)
 		case 'm':
 			if (INVALID_MEMBER(task_struct_last_run) &&
 			    INVALID_MEMBER(task_struct_timestamp) &&
-			    INVALID_MEMBER(sched_info_last_arrival)) {
+			    INVALID_MEMBER(sched_info_last_arrival) &&
+			    INVALID_MEMBER(sched_entity_exec_start)) {
 				error(INFO, 
                             "last-run timestamps do not exist in this kernel\n");
 				argerrs++;
@@ -3574,7 +3581,8 @@ cmd_ps(void)
 		case 'l':
 			if (INVALID_MEMBER(task_struct_last_run) &&
 			    INVALID_MEMBER(task_struct_timestamp) &&
-			    INVALID_MEMBER(sched_info_last_arrival)) {
+			    INVALID_MEMBER(sched_info_last_arrival) &&
+			    INVALID_MEMBER(sched_entity_exec_start)) {
 				error(INFO, 
                             "last-run timestamps do not exist in this kernel\n");
 				argerrs++;
@@ -6020,7 +6028,11 @@ task_last_run(ulong task)
         	timestamp = tt->last_task_read ?  ULONGLONG(tt->task_struct + 
 			OFFSET(task_struct_sched_info) + 
 			OFFSET(sched_info_last_arrival)) : 0;
-	
+	else if (VALID_MEMBER(sched_entity_exec_start))
+			timestamp = tt->last_task_read ?  ULONGLONG(tt->task_struct +
+			OFFSET(task_struct_se) +
+			OFFSET(sched_entity_exec_start)) : 0;
+
         return timestamp;
 }
 
-- 
2.20.1




More information about the Crash-utility mailing list