[PATCH] "kmem -i" extremely slow on dumps from large memory systems
by Aureau, Georges (Kernel Tools ERT)
The "kmem -i" command is extremely slow (appears to hang) on dumps from large memory systems.
For example, on 120GB crash dump from a high-end server with 32TB of RAM (ie. 8Giga Pages),
the "kmem -i" command is taking over 50 minutes to execute on a DL380 Gen10. To report basic
general memory usage figures, we should only be reading global counters, without having to walk
the full flat/sparse mem map page table. Hence, dump_kmeminfo() should first be reading globals,
and then only call dump_mem_map() if important information (ie. slabs or total ram) is missing.
Signed-off-by: Georges Aureau <georges.aureau(a)hpe.com<mailto:georges.aureau@hpe.com>>
--
diff --git a/memory.c b/memory.c
index 8c01ed0..8e2b2e9 100644
--- a/memory.c
+++ b/memory.c
@@ -8546,18 +8546,19 @@ dump_kmeminfo(void)
ulong get_buffers;
ulong get_slabs;
char buf[BUFSIZE];
+ ulong flags;
-
- BZERO(&meminfo, sizeof(struct meminfo));
- meminfo.flags = GET_ALL;
- dump_mem_map(&meminfo);
- get_totalram = meminfo.get_totalram;
- shared_pages = meminfo.get_shared;
- get_buffers = meminfo.get_buffers;
- get_slabs = meminfo.get_slabs;
+ /*
+ * By default, we will no longer call dump_mem_map() as this is too
+ * slow for large memory systems. If we have to call it (eg. missing
+ * important information such as slabs or total ram), we will also
+ * collect shared pages. Otherwise, we won't print shared pages.
+ */
+ flags = GET_SHARED_PAGES;
+ shared_pages = 0;
/*
- * If vm_stat array exists, override page search info.
+ * If vm_stat array does not exists, then set mem map flag.
*/
if (vm_stat_init()) {
if (dump_vm_stat("NR_SLAB", &nr_slab, 0))
@@ -8571,10 +8572,11 @@ dump_kmeminfo(void)
get_slabs = nr_slab;
if (dump_vm_stat("NR_SLAB_UNRECLAIMABLE_B", &nr_slab, 0))
get_slabs += nr_slab;
+ } else {
+ flags |= GET_SLAB_PAGES;
}
}
- fprintf(fp, "%s", kmeminfo_hdr);
/*
* Get total RAM based upon how the various versions of si_meminfo()
* have done it, latest to earliest:
@@ -8586,9 +8588,32 @@ dump_kmeminfo(void)
symbol_exists("_totalram_pages")) {
totalram_pages = vt->totalram_pages ?
vt->totalram_pages : get_totalram;
- } else
- totalram_pages = get_totalram;
+ } else {
+ flags |= GET_TOTALRAM_PAGES;
+ }
+ /*
+ * If we want more than just shared pages (missing slabs or total ram)
+ * then call dump_mem_map() and also collect buffers.
+ */
+ if (flags != GET_SHARED_PAGES) {
+ BZERO(&meminfo, sizeof(struct meminfo));
+ flags |= GET_BUFFERS_PAGES;
+ meminfo.flags = flags;
+ dump_mem_map(&meminfo);
+ /* Update the missing information */
+ if (flags & GET_SLAB_PAGES) {
+ get_slabs = meminfo.get_slabs;
+ }
+ if (flags & GET_TOTALRAM_PAGES) {
+ get_totalram = meminfo.get_totalram;
+ totalram_pages = get_totalram;
+ }
+ shared_pages = meminfo.get_shared;
+ get_buffers = meminfo.get_buffers;
+ }
+
+ fprintf(fp, "%s", kmeminfo_hdr);
fprintf(fp, "%13s %7ld %11s ----\n", "TOTAL MEM",
totalram_pages, pages_to_size(totalram_pages, buf));
@@ -8613,9 +8638,11 @@ dump_kmeminfo(void)
* differently than the kernel -- it just tallies the non-reserved
* pages that have a count of greater than 1.
*/
- pct = (shared_pages * 100)/totalram_pages;
- fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
- "SHARED", shared_pages, pages_to_size(shared_pages, buf), pct);
+ if (shared_pages) {
+ pct = (shared_pages * 100)/totalram_pages;
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
+ "SHARED", shared_pages, pages_to_size(shared_pages, buf), pct);
+ }
subtract_buffer_pages = 0;
if (symbol_exists("buffermem_pages")) {
@@ -8634,7 +8661,7 @@ dump_kmeminfo(void)
fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"BUFFERS", buffer_pages, pages_to_size(buffer_pages, buf), pct);
- if (CRASHDEBUG(1))
+ if (CRASHDEBUG(1)&&(flags&GET_BUFFERS_PAGES))
error(NOTE, "pages with buffers: %ld\n", get_buffers);
/*