diff --git a/SOURCES/fix-ps-performance-on-live-system.patch b/SOURCES/fix-ps-performance-on-live-system.patch new file mode 100644 index 0000000..2398c88 --- /dev/null +++ b/SOURCES/fix-ps-performance-on-live-system.patch @@ -0,0 +1,139 @@ +commit a3a441aeabd6c5c3c86b4793a283927507a5cc10 +Author: Dave Anderson +Date: Mon Sep 22 16:25:16 2014 -0400 + + Fix for the "ps" command performance degradation patch the was + introduced in crash-7.0.8. Without this patch, it is possible that + the "ps" command may fail prematurely with the error message + "ps: bsearch for tgid failed: task:
tgid: " + when running on a live system or against a "live" dumpfile. + (panfy.fnst@cn.fujitsu.com) + +diff --git a/memory.c b/memory.c +index 518c917..2376e6f 100644 +--- a/memory.c ++++ b/memory.c +@@ -4187,54 +4187,52 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm) + 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(first->task + +- OFFSET(task_struct_rss_stat) + +- OFFSET(task_rss_stat_count), KVADDR, +- &sync_rss, +- sizeof(int), +- "task_struct rss_stat MM_FILEPAGES", +- RETURN_ON_ERROR)) +- continue; ++ if (tg) { ++ /* 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(first->task + ++ OFFSET(task_struct_rss_stat) + ++ OFFSET(task_rss_stat_count), KVADDR, ++ &sync_rss, ++ sizeof(int), ++ "task_struct rss_stat MM_FILEPAGES", ++ RETURN_ON_ERROR)) ++ continue; + +- rss += sync_rss; +- +- /* count 1 -> anonpages */ +- if (!readmem(first->task + +- OFFSET(task_struct_rss_stat) + +- OFFSET(task_rss_stat_count) + +- sizeof(int), +- KVADDR, &sync_rss, +- sizeof(int), +- "task_struct rss_stat MM_ANONPAGES", +- RETURN_ON_ERROR)) +- continue; ++ rss += sync_rss; ++ ++ /* count 1 -> anonpages */ ++ if (!readmem(first->task + ++ OFFSET(task_struct_rss_stat) + ++ OFFSET(task_rss_stat_count) + ++ sizeof(int), ++ KVADDR, &sync_rss, ++ sizeof(int), ++ "task_struct rss_stat MM_ANONPAGES", ++ RETURN_ON_ERROR)) ++ continue; + +- rss += sync_rss; ++ rss += sync_rss; + +- if(first == last) +- break; +- first++; +- } ++ if (first == last) ++ break; ++ first++; ++ } + +- tt->last_tgid = last; ++ tt->last_tgid = last; ++ } + } + + /* + + +commit 62b294b27ce08decb63b204aeb9c6d3d5ace96b2 +Author: Dave Anderson +Date: Fri Sep 19 14:20:57 2014 -0400 + + Fix for the one-time (dumpfile), or as-required (live system), + gathering of tasks from the kernel pid_hash[] in 2.6.24 and later + kernels. Without the patch, if an entry in a pid_hash[] chain is + not related to the "init_pid_ns" pid_namespace structure, any + remaining entries in the hlist chain are skipped. + (vvs@parallels.com) + +diff --git a/task.c b/task.c +index b33c96a..66f2e0a 100644 +--- a/task.c ++++ b/task.c +@@ -2033,7 +2033,7 @@ do_chained: + * Use init_pid_ns level 0 (PIDTYPE_PID). + */ + if (upid_ns != tt->init_pid_ns) +- continue; ++ goto chain_next; + + pid = upid - OFFSET(pid_numbers); + + diff --git a/SOURCES/ps-performance.patch b/SOURCES/ps-performance.patch new file mode 100644 index 0000000..df54183 --- /dev/null +++ b/SOURCES/ps-performance.patch @@ -0,0 +1,357 @@ +--- 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; + } + + /* diff --git a/SPECS/crash.spec b/SPECS/crash.spec index 45218c0..82c68a8 100644 --- a/SPECS/crash.spec +++ b/SPECS/crash.spec @@ -4,7 +4,7 @@ Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles Name: crash Version: 7.0.2 -Release: 6%{?dist} +Release: 7%{?dist}.1 License: GPLv3 Group: Development/Debuggers Source: http://people.redhat.com/anderson/crash-%{version}.tar.gz @@ -19,6 +19,8 @@ Patch1: rhel7.0_beta.patch Patch2: kmem-S-CONFIG_SLUB.patch Patch3: S390X_NR_CPUS.patch Patch4: backtrace_fixes.patch +Patch5: ps-performance.patch +Patch6: fix-ps-performance-on-live-system.patch %description The core analysis suite is a self-contained tool that can be used to @@ -44,6 +46,8 @@ offered by Mission Critical Linux, or the LKCD kernel patch. %patch2 -p1 -b kmem-S-CONFIG_SLUB.patch %patch3 -p1 -b S390X_NR_CPUS.patch %patch4 -p1 -b backtrace_fixes.patch +%patch5 -p1 -b ps-performance.patch +%patch6 -p1 -b fix-ps-performance-on-live-system.patch %build make RPMPKG="%{version}-%{release}" CFLAGS="%{optflags}" @@ -72,6 +76,14 @@ rm -rf %{buildroot} %{_includedir}/* %changelog +* Tue Sep 23 2014 Dave Anderson - 7.0.2-7 +- Fix ps performance patch regression on live systems. +- Resolves: rhbz#1142139 + +* Thu Sep 18 2014 Dave Anderson - 7.0.2-7 +- Z-stream fix for "ps sub-command shows massive performance degradation" +- Resolves: rhbz#1142139 + * Tue Jan 28 2014 Daniel Mach - 7.0.2-6 - Mass rebuild 2014-01-24