--- 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; } /*