This patch changes dump_kmeminfo() to report overcommit information similar
to that displayed under the proc/meminfo file. It may be useful to indicate
memory over commitment abuse, for example with forced vmcores from system
hangs due to shortage of memory. The intended output is as follows:
crash> kmem -i
PAGES TOTAL PERCENTAGE
TOTAL MEM 1965332 7.5 GB ----
FREE 78080 305 MB 3% of TOTAL MEM
USED 1887252 7.2 GB 96% of TOTAL MEM
SHARED 789954 3 GB 40% of TOTAL MEM
BUFFERS 110606 432.1 MB 5% of TOTAL MEM
CACHED 1212645 4.6 GB 61% of TOTAL MEM
SLAB 146563 572.5 MB 7% of TOTAL MEM
TOTAL SWAP 1970175 7.5 GB ----
SWAP USED 5 20 KB 0% of TOTAL SWAP
SWAP FREE 1970170 7.5 GB 99% of TOTAL SWAP
COMMIT LIMIT 2952841 11.3 GB ----
COMMITTED 1150595 4.4 GB 38% of TOTAL LIMIT
Tested under 3.16.4-200.fc20.x86_64 only.
Though this should work under RHEL5 (2.6.18) and above.
Signed-off-by: Aaron Tomlin <atomlin(a)redhat.com>
Suggested-by: Alexis Solanas <alexis(a)redhat.com>
---
help.c | 33 +++++++-------
memory.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 155 insertions(+), 31 deletions(-)
diff --git a/help.c b/help.c
index 6aa3e20..bedd7c3 100644
--- a/help.c
+++ b/help.c
@@ -5587,23 +5587,26 @@ char *help_kmem[] = {
"\nEXAMPLES",
" Display memory usage information:\n",
" %s> kmem -i",
-" PAGES TOTAL PERCENTAGE",
-" TOTAL MEM 63602 248.4 MB ----",
-" FREE 993 3.9 MB 1% of TOTAL MEM",
-" USED 62609 244.6 MB 98% of TOTAL MEM",
-" SHARED 34035 132.9 MB 53% of TOTAL MEM",
-" BUFFERS 10928 42.7 MB 17% of TOTAL MEM",
-" CACHED 35249 137.7 MB 55% of TOTAL MEM",
-" SLAB 2823 11 MB 4% of TOTAL MEM",
+" PAGES TOTAL PERCENTAGE",
+" TOTAL MEM 63602 248.4 MB ----",
+" FREE 993 3.9 MB 1% of TOTAL MEM",
+" USED 62609 244.6 MB 98% of TOTAL MEM",
+" SHARED 34035 132.9 MB 53% of TOTAL MEM",
+" BUFFERS 10928 42.7 MB 17% of TOTAL MEM",
+" CACHED 35249 137.7 MB 55% of TOTAL MEM",
+" SLAB 2823 11 MB 4% of TOTAL MEM",
" ",
-" TOTAL HIGH 0 0 0% of TOTAL MEM",
-" FREE HIGH 0 0 0% of TOTAL HIGH",
-" TOTAL LOW 63602 248.4 MB 100% of TOTAL MEM",
-" FREE LOW 993 3.9 MB 1% of TOTAL LOW",
+" TOTAL HIGH 0 0 0% of TOTAL MEM",
+" FREE HIGH 0 0 0% of TOTAL HIGH",
+" TOTAL LOW 63602 248.4 MB 100% of TOTAL MEM",
+" FREE LOW 993 3.9 MB 1% of TOTAL LOW",
" ",
-" TOTAL SWAP 129792 507 MB ----",
-" SWAP USED 14727 57.5 MB 11% of TOTAL SWAP",
-" SWAP FREE 115065 449.5 MB 88% of TOTAL SWAP",
+" TOTAL SWAP 129792 507 MB ----",
+" SWAP USED 14727 57.5 MB 11% of TOTAL SWAP",
+" SWAP FREE 115065 449.5 MB 88% of TOTAL SWAP",
+" ",
+" COMMIT LIMIT 2952841 11.3 GB ----",
+" COMMITTED 1158600 4.4 GB 39% of TOTAL LIMIT",
" ",
" ZONE NAME FREE ACTIVE INACTIVE_DIRTY INACTIVE_CLEAN
MIN/LOW/HIGH",
" 0 DMA 240 1166 7 161 128/256/384
",
diff --git a/memory.c b/memory.c
index 3ac928d..ce3acb9 100644
--- a/memory.c
+++ b/memory.c
@@ -227,6 +227,7 @@ 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 int get_hugetlb_total_pages(ulong *);
static void swap_info_init(void);
static char *get_swapdev(ulong, char *);
static void fill_swap_info(ulong);
@@ -4627,7 +4628,7 @@ cmd_kmem(void)
}
- if (iflag == 1)
+ if (iflag)
dump_kmeminfo();
if (pflag == 1)
@@ -7653,7 +7654,7 @@ bailout:
* by /proc/meminfo, and then some...
*/
-char *kmeminfo_hdr = " PAGES TOTAL PERCENTAGE\n";
+char *kmeminfo_hdr = " PAGES TOTAL PERCENTAGE\n";
static void
dump_kmeminfo(void)
@@ -7670,6 +7671,11 @@ dump_kmeminfo(void)
ulong freehighmem_pages;
ulong totallowmem_pages;
ulong freelowmem_pages;
+ ulong allowed;
+ long committed;
+ ulong overcommit_kbytes = 0;
+ int overcommit_ratio;
+ ulong hugetlb_total_pages;
long nr_file_pages, nr_slab;
ulong swapper_space_nrpages;
ulong pct;
@@ -7720,7 +7726,7 @@ dump_kmeminfo(void)
} else
totalram_pages = get_totalram;
- fprintf(fp, "%10s %7ld %11s ----\n", "TOTAL MEM",
+ fprintf(fp, "%13s %7ld %11s ----\n", "TOTAL MEM",
totalram_pages, pages_to_size(totalram_pages, buf));
/*
@@ -7731,12 +7737,12 @@ dump_kmeminfo(void)
vt->dump_free_pages(&meminfo);
freeram_pages = meminfo.retval;
pct = (freeram_pages * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"FREE", freeram_pages, pages_to_size(freeram_pages, buf), pct);
used_pages = totalram_pages - freeram_pages;
pct = (used_pages * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"USED", used_pages, pages_to_size(used_pages, buf), pct);
/*
@@ -7745,7 +7751,7 @@ dump_kmeminfo(void)
* pages that have a count of greater than 1.
*/
pct = (shared_pages * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"SHARED", shared_pages, pages_to_size(shared_pages, buf), pct);
subtract_buffer_pages = 0;
@@ -7762,7 +7768,7 @@ dump_kmeminfo(void)
buffer_pages = 0;
pct = (buffer_pages * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"BUFFERS", buffer_pages, pages_to_size(buffer_pages, buf), pct);
if (CRASHDEBUG(1))
@@ -7816,7 +7822,7 @@ dump_kmeminfo(void)
pct = (page_cache_size * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"CACHED", page_cache_size,
pages_to_size(page_cache_size, buf), pct);
@@ -7826,7 +7832,7 @@ dump_kmeminfo(void)
*/
pct = (get_slabs * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"SLAB", get_slabs, pages_to_size(get_slabs, buf), pct);
if (symbol_exists("totalhigh_pages")) {
@@ -7851,7 +7857,7 @@ dump_kmeminfo(void)
pct = totalhigh_pages ?
(totalhigh_pages * 100)/totalram_pages : 0;
- fprintf(fp, "\n%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "\n%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"TOTAL HIGH", totalhigh_pages,
pages_to_size(totalhigh_pages, buf), pct);
@@ -7860,19 +7866,19 @@ dump_kmeminfo(void)
freehighmem_pages = meminfo.retval;
pct = freehighmem_pages ?
(freehighmem_pages * 100)/totalhigh_pages : 0;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL HIGH\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL HIGH\n",
"FREE HIGH", freehighmem_pages,
pages_to_size(freehighmem_pages, buf), pct);
totallowmem_pages = totalram_pages - totalhigh_pages;
pct = (totallowmem_pages * 100)/totalram_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL MEM\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL MEM\n",
"TOTAL LOW", totallowmem_pages,
pages_to_size(totallowmem_pages, buf), pct);
freelowmem_pages = freeram_pages - freehighmem_pages;
pct = (freelowmem_pages * 100)/totallowmem_pages;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL LOW\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL LOW\n",
"FREE LOW", freelowmem_pages,
pages_to_size(freelowmem_pages, buf), pct);
}
@@ -7884,18 +7890,18 @@ dump_kmeminfo(void)
if (symbol_exists("swapper_space") ||
symbol_exists("swapper_spaces")) {
if (dump_swap_info(RETURN_ON_ERROR, &totalswap_pages,
&totalused_pages)) {
- fprintf(fp, "%10s %7ld %11s ----\n",
+ fprintf(fp, "%13s %7ld %11s ----\n",
"TOTAL SWAP", totalswap_pages,
pages_to_size(totalswap_pages, buf));
pct = totalswap_pages ? (totalused_pages * 100) /
totalswap_pages : 100;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL SWAP\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL SWAP\n",
"SWAP USED", totalused_pages,
pages_to_size(totalused_pages, buf), pct);
pct = totalswap_pages ?
((totalswap_pages - totalused_pages) *
100) / totalswap_pages : 0;
- fprintf(fp, "%10s %7ld %11s %3ld%% of TOTAL SWAP\n",
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL SWAP\n",
"SWAP FREE",
totalswap_pages - totalused_pages,
pages_to_size(totalswap_pages - totalused_pages,
@@ -7905,6 +7911,68 @@ dump_kmeminfo(void)
"swap_info[%ld].swap_map at %lx is inaccessible\n",
totalused_pages, totalswap_pages);
}
+ /*
+ * Show committed memory
+ */
+ if (kernel_symbol_exists("sysctl_overcommit_memory")) {
+
+ fprintf(fp, "\n");
+ if (kernel_symbol_exists("sysctl_overcommit_kbytes"))
+ get_symbol_data("sysctl_overcommit_kbytes",
+ sizeof(ulong), &overcommit_kbytes);
+
+ if (overcommit_kbytes)
+ allowed = overcommit_kbytes >>
+ (machdep->pageshift - 10);
+ else {
+ get_symbol_data("sysctl_overcommit_ratio",
+ sizeof(int),
+ &overcommit_ratio);
+
+ if (!get_hugetlb_total_pages(&hugetlb_total_pages))
+ goto bailout;
+
+ allowed = ((totalram_pages - hugetlb_total_pages)
+ * overcommit_ratio / 100);
+ }
+ if (symbol_exists("vm_committed_as")) {
+ if (!MEMBER_EXISTS("percpu_counter", "count"))
+ goto bailout;
+
+ readmem(symbol_value("vm_committed_as") +
+ MEMBER_OFFSET("percpu_counter",
+ "count"), KVADDR,
+ &committed,
+ sizeof(long),
+ "percpu_counter count",
+ FAULT_ON_ERROR);
+
+ /* Ensure always positive */
+ if (committed < 0)
+ committed = 0;
+ } else {
+ if (!MEMBER_EXISTS("atomic_t", "counter"))
+ goto bailout;
+
+ readmem(symbol_value("vm_committed_space") +
+ MEMBER_OFFSET("atomic_t",
+ "counter"), KVADDR,
+ &committed, sizeof(int),
+ "atomic_t counter",
+ FAULT_ON_ERROR);
+ }
+ allowed += totalswap_pages;
+ fprintf(fp, "%13s %7ld %11s ----\n",
+ "COMMIT LIMIT", allowed,
+ pages_to_size(allowed, buf));
+
+ pct = committed ? ((committed * 100)
+ / allowed) : 0;
+ fprintf(fp, "%13s %7ld %11s %3ld%% of TOTAL LIMIT\n",
+ "COMMITTED", committed,
+ pages_to_size(committed, buf), pct);
+ }
+bailout:
dump_zone_page_usage();
}
@@ -14734,6 +14802,59 @@ next_physpage(ulonglong paddr, ulonglong *nextpaddr)
return FALSE;
}
+static int
+get_hugetlb_total_pages(ulong *nr_total_pages)
+{
+ ulong hstate_p;
+ int i, len;
+ ulong nr_huge_pages;
+ uint horder;
+
+ *nr_total_pages = 0;
+ if (kernel_symbol_exists("hstates")) {
+ STRUCT_SIZE_INIT(hstate, "hstate");
+ MEMBER_OFFSET_INIT(hstate_order, "hstate", "order");
+ MEMBER_OFFSET_INIT(hstate_nr_huge_pages, "hstate",
"nr_huge_pages");
+
+ if (INVALID_SIZE(hstate) ||
+ INVALID_MEMBER(hstate_order) ||
+ INVALID_MEMBER(hstate_nr_huge_pages))
+ return FALSE;
+
+ len = get_array_length("hstates", NULL, 0);
+ hstate_p = symbol_value("hstates");
+
+ for (i = 0; i < len; i++) {
+ hstate_p = hstate_p +
+ (SIZE(hstate) * i);
+
+ readmem(hstate_p + OFFSET(hstate_order),
+ KVADDR,
+ &horder, sizeof(uint),
+ "hstate_order",
+ FAULT_ON_ERROR);
+
+ readmem(hstate_p + OFFSET(hstate_nr_huge_pages),
+ KVADDR,
+ &nr_huge_pages, sizeof(ulong),
+ "hstate_nr_huge_pages",
+ FAULT_ON_ERROR);
+
+ *nr_total_pages += nr_huge_pages * (1 << horder);
+ }
+ } else if (kernel_symbol_exists("nr_huge_pages")) {
+ unsigned long hpage_shift = 21;
+
+ if ((machine_type("X86") && !(machdep->flags & PAE)))
+ hpage_shift = 22;
+ get_symbol_data("nr_huge_pages",
+ sizeof(ulong), &nr_huge_pages);
+ *nr_total_pages = nr_huge_pages * ((1 << hpage_shift) /
+ machdep->pagesize);
+ }
+ return TRUE;
+}
+
/*
* Display swap statistics.
*/
--
1.9.3