Blob Blame History Raw
--- crash-7.0.2/task.c.orig
+++ crash-7.0.2/task.c
@@ -489,6 +489,7 @@ task_init(void)
 	}
 
 	sort_context_array();
+	sort_tgid_array();
 
 	if (pc->flags & SILENT)
 		initialize_task_state();
@@ -635,6 +636,11 @@ allocate_task_space(int cnt)
                     malloc(cnt * sizeof(struct task_context))))
                         error(FATAL, "cannot malloc context array (%d tasks)",
                                 cnt);
+		if (!(tt->tgid_array = (struct tgid_context *)
+                    malloc(cnt * sizeof(struct tgid_context))))
+                        error(FATAL, "cannot malloc tgid array (%d tasks)",
+                                cnt);
+
 	} else {
                 if (!(tt->task_local = (void *)
 		    realloc(tt->task_local, cnt * sizeof(void *)))) 
@@ -648,6 +654,13 @@ allocate_task_space(int cnt)
                         error(FATAL,
                             "%scannot realloc context array (%d tasks)",
 	                	(pc->flags & RUNTIME) ? "" : "\n", cnt);
+
+		 if (!(tt->tgid_array = (struct tgid_context *)
+                    realloc(tt->tgid_array, 
+		    cnt * sizeof(struct tgid_context)))) 
+                        error(FATAL,
+                            "%scannot realloc tgid array (%d tasks)",
+	                	(pc->flags & RUNTIME) ? "" : "\n", cnt);
 	}
 }
 
@@ -2272,13 +2285,14 @@ retry_active:
 static struct task_context *
 store_context(struct task_context *tc, ulong task, char *tp)
 {
-        pid_t *pid_addr;
+        pid_t *pid_addr, *tgid_addr;
         char *comm_addr;
         int *processor_addr;
         ulong *parent_addr;
         ulong *mm_addr;
         int has_cpu;
 	int do_verify;
+	struct tgid_context *tg;
 
 	processor_addr = NULL;
 
@@ -2301,6 +2315,7 @@ store_context(struct task_context *tc, u
 		tc = tt->context_array + tt->running_tasks;
 
         pid_addr = (pid_t *)(tp + OFFSET(task_struct_pid));
+	tgid_addr = (pid_t *)(tp + OFFSET(task_struct_tgid));
         comm_addr = (char *)(tp + OFFSET(task_struct_comm));
 	if (tt->flags & THREAD_INFO) {
 		tc->thread_info = ULONG(tp + OFFSET(task_struct_thread_info));
@@ -2326,6 +2341,14 @@ store_context(struct task_context *tc, u
         tc->task = task;
         tc->tc_next = NULL;
 
+	/*
+	 *  Fill a tgid_context structure with the data from 
+	 *  the incoming task.
+	 */
+	tg = tt->tgid_array + tt->running_tasks;
+	tg->tgid = *tgid_addr;
+	tg->task = task;
+
         if (do_verify && !verify_task(tc, do_verify)) {
 		error(INFO, "invalid task address: %lx\n", tc->task);
                 BZERO(tc, sizeof(struct task_context));
@@ -2441,6 +2464,33 @@ sort_context_array_by_last_run(void)
 }
 
 /*
+ *  Set the tgid_context array by tgid number.
+ */
+void
+sort_tgid_array(void)
+{
+	if (VALID_MEMBER(mm_struct_rss) || (!VALID_MEMBER(task_struct_rss_stat)))
+		return;
+
+	qsort((void *)tt->tgid_array, (size_t)tt->running_tasks,
+		sizeof(struct tgid_context), sort_by_tgid);
+
+	tt->last_tgid = tt->tgid_array;
+}
+
+int
+sort_by_tgid(const void *arg1, const void *arg2)
+{
+	struct tgid_context *t1, *t2;
+
+	t1 = (struct tgid_context *)arg1;
+	t2 = (struct tgid_context *)arg2;
+
+	return (t1->tgid < t2->tgid ? -1 :
+		t1->tgid == t2->tgid ? 0 : 1);
+}
+
+/*
  *  Keep a stash of the last task_struct accessed.  Chances are it will
  *  be hit several times before the next task is accessed.
  */
@@ -6320,6 +6370,7 @@ dump_task_table(int verbose)
 {
 	int i, j, more, nr_cpus;
 	struct task_context *tc;
+	struct tgid_context *tg;
 	char buf[BUFSIZE];
 	int others, wrap, flen;
 
@@ -6340,6 +6391,12 @@ dump_task_table(int verbose)
 		fprintf(fp, "          .tc_next: %lx\n", (ulong)tc->tc_next);
 	}
 	fprintf(fp, "     context_array: %lx\n",  (ulong)tt->context_array);
+	fprintf(fp, "        tgid_array: %lx\n",  (ulong)tt->tgid_array);
+	fprintf(fp, "     tgid_searches: %ld\n",  tt->tgid_searches);
+	fprintf(fp, "   tgid_cache_hits: %ld (%ld%%)\n", tt->tgid_cache_hits,
+		tt->tgid_searches ? 
+		tt->tgid_cache_hits * 100 / tt->tgid_searches : 0);
+	fprintf(fp, "         last_tgid: %lx\n",  (ulong)tt->last_tgid);
 	fprintf(fp, "refresh_task_table: ");
 	if (tt->refresh_task_table == refresh_fixed_task_table)
 		fprintf(fp, "refresh_fixed_task_table()\n");
@@ -6434,6 +6491,8 @@ dump_task_table(int verbose)
 	fprintf(fp, "       task_struct: %lx\n", (ulong)tt->task_struct);
 	fprintf(fp, "         mm_struct: %lx\n", (ulong)tt->mm_struct);
 	fprintf(fp, "       init_pid_ns: %lx\n", tt->init_pid_ns);
+	fprintf(fp, "         filepages: %ld\n", tt->filepages);
+	fprintf(fp, "         anonpages: %ld\n", tt->anonpages);
 
 
 	wrap = sizeof(void *) == SIZEOF_32BIT ? 8 : 4;
@@ -6649,6 +6708,13 @@ dump_task_table(int verbose)
 				i, tc->task, tc->pid, tc->processor, tc->ptask,
 				(ulong)tc->mm_struct, tc->comm); 
 	}
+
+        fprintf(fp, "\nINDEX       TASK       TGID  (COMM)\n");
+	for (i = 0; i < RUNNING_TASKS(); i++) {
+		tg = &tt->tgid_array[i];
+		tc = task_to_context(tg->task);
+		fprintf(fp, "[%3d] %lx %ld (%s)\n", i, tg->task, tg->tgid, tc->comm);
+	}
 }
 
 /*
--- crash-7.0.2/main.c.orig
+++ crash-7.0.2/main.c
@@ -747,6 +747,7 @@ reattempt:
 			} else if (!(pc->flags & MINIMAL_MODE)) {
 				tt->refresh_task_table();
 				sort_context_array();
+				sort_tgid_array();	
 			}
 		}
                 if (!STREQ(pc->curcmd, pc->program_name))
--- crash-7.0.2/defs.h.orig
+++ crash-7.0.2/defs.h
@@ -749,6 +749,11 @@ struct task_context {
 	struct task_context *tc_next;
 };
 
+struct tgid_context {               /* tgid and task stored for each task */
+	ulong tgid;
+	ulong task;
+};
+
 struct task_table {                      /* kernel/local task table data */
 	struct task_context *current;
 	struct task_context *context_array;
@@ -782,6 +787,12 @@ struct task_table {
 	char *thread_info;
 	char *mm_struct;
 	ulong init_pid_ns;
+	struct tgid_context *tgid_array;
+	struct tgid_context *last_tgid;
+	ulong tgid_searches;
+	ulong tgid_cache_hits;
+	long filepages;
+	long anonpages;
 };
 
 #define TASK_INIT_DONE       (0x1)
@@ -4710,6 +4721,8 @@ ulong generic_get_stackbase(ulong);
 ulong generic_get_stacktop(ulong);
 void dump_task_table(int);
 void sort_context_array(void);
+void sort_tgid_array(void);
+int sort_by_tgid(const void *, const void *);
 int in_irq_ctx(ulonglong, int, ulong);
 
 /*
--- crash-7.0.2/memory.c.orig
+++ crash-7.0.2/memory.c
@@ -215,6 +215,7 @@ static int next_module_vaddr(ulong, ulon
 static int next_identity_mapping(ulong, ulong *);
 static int vm_area_page_dump(ulong, ulong, ulong, ulong, ulong,
 	struct reference *);
+static void rss_page_types_init(void);
 static int dump_swap_info(ulong, ulong *, ulong *);
 static void swap_info_init(void);
 static char *get_swapdev(ulong, char *);
@@ -1040,6 +1041,8 @@ vm_init(void)
 
 	page_flags_init();
 
+	rss_page_types_init();
+
 	vt->flags |= VM_INIT;
 }
 
@@ -4001,6 +4004,54 @@ in_user_stack(ulong task, ulong vaddr)
 }
 
 /*
+ * Set the const value of filepages and anonpages 
+ * according to MM_FILEPAGES and MM_ANONPAGES.
+ */
+static void 
+rss_page_types_init(void)
+{
+	long anonpages, filepages;
+
+	if (VALID_MEMBER(mm_struct_rss))
+		return;
+
+	if (VALID_MEMBER(mm_struct_rss_stat)) 
+	{
+		if (!enumerator_value("MM_FILEPAGES", &filepages) ||
+		    !enumerator_value("MM_ANONPAGES", &anonpages)) 
+		{
+			filepages = 0;
+			anonpages = 1;
+		}
+		tt->filepages = filepages;
+		tt->anonpages = anonpages;
+	}
+}
+
+static struct tgid_context *
+tgid_quick_search(ulong tgid)
+{
+	struct tgid_context *last, *next;
+
+	tt->tgid_searches++;
+
+	last = tt->last_tgid;
+	if (tgid == last->tgid) {
+		tt->tgid_cache_hits++;
+		return last;
+	}
+
+	next = last + 1;
+	if ((next < (tt->tgid_array + RUNNING_TASKS())) &&
+ 	    (tgid == next->tgid)) {
+		tt->tgid_cache_hits++;
+		return next;
+	}
+
+	return NULL;
+}
+
+/*
  *  Fill in the task_mem_usage structure with the RSS, virtual memory size,
  *  percent of physical memory being used, and the mm_struct address.
  */
@@ -4037,11 +4088,8 @@ get_task_mem_usage(ulong task, struct ta
 		if (VALID_MEMBER(mm_struct_rss_stat)) {
 			long anonpages, filepages;
 
-			if (!enumerator_value("MM_FILEPAGES", &filepages) ||
-			    !enumerator_value("MM_ANONPAGES", &anonpages)) {
-				filepages = 0;
-				anonpages = 1;
-			}
+			anonpages = tt->anonpages;
+			filepages = tt->filepages;
 			rss += LONG(tt->mm_struct +
 				OFFSET(mm_struct_rss_stat) +
 				OFFSET(mm_rss_stat_count) +
@@ -4054,19 +4102,35 @@ get_task_mem_usage(ulong task, struct ta
 
 		/* Check whether SPLIT_RSS_COUNTING is enabled */
 		if (VALID_MEMBER(task_struct_rss_stat)) {
-			int i, sync_rss;
-			ulong tgid;
-			struct task_context *tc1;
-
-			tgid = task_tgid(task);
-
-			tc1 = FIRST_CONTEXT();
-			for (i = 0; i < RUNNING_TASKS(); i++, tc1++) {
-				if (task_tgid(tc1->task) != tgid)
-					continue;
+			int sync_rss;
+			struct tgid_context tgid, *tgid_array, *tg, *first, *last;
+
+			tgid_array = tt->tgid_array;
+			tgid.tgid = task_tgid(task);
 
+			if (!(tg = tgid_quick_search(tgid.tgid)))
+				tg = (struct tgid_context *)bsearch(&tgid, tgid_array, RUNNING_TASKS(), 
+					sizeof(struct tgid_context), sort_by_tgid);
+
+			if (tg == NULL)
+				error(FATAL, "bsearch for tgid failed: task: %lx tgid: %ld\n", 
+					task, tgid.tgid);
+
+			/* find the first element which has the same tgid */
+			first = tg;
+			while ((first > tgid_array) && ((first - 1)->tgid == first->tgid)) 
+				first--;
+
+			/* find the last element which have same tgid */
+			last = tg;
+			while ((last < (tgid_array + (RUNNING_TASKS() - 1))) && 
+				(last->tgid == (last + 1)->tgid))
+				last++;
+
+			while (first <= last)
+			{
 				/* count 0 -> filepages */
-				if (!readmem(tc1->task +
+				if (!readmem(first->task +
 					OFFSET(task_struct_rss_stat) +
 					OFFSET(task_rss_stat_count), KVADDR,
 					&sync_rss,
@@ -4078,7 +4142,7 @@ get_task_mem_usage(ulong task, struct ta
 				rss += sync_rss;
 
 				/* count 1 -> anonpages */
-				if (!readmem(tc1->task +
+				if (!readmem(first->task +
 					OFFSET(task_struct_rss_stat) +
 					OFFSET(task_rss_stat_count) +
 					sizeof(int),
@@ -4089,7 +4153,13 @@ get_task_mem_usage(ulong task, struct ta
 						continue;
 
 				rss += sync_rss;
+
+				if(first == last)
+					break;
+				first++;
 			}
+
+			tt->last_tgid = last;
 		}
 
 		/*