Hi Dave,
Please share your thoughts on adding a -m option to kmem to display
the free pages per migrate type.
This is similar to /proc/pagetypeinfo.
Sample output (without formatting). Patch attached.
crash>
Free pages count per migrate type at order [0-10]:
Node 0, zone Normal, type Unmovable 155 172 92
39 20 8 10 15 7 3 1
Node 0, zone HighMem, type Unmovable 1 2 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Unmovable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Reclaimable 9 3 0
0 1 1 0 0 0 0 0
Node 0, zone HighMem, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Movable 7 68 35
253 137 38 16 4 0 0 66
Node 0, zone HighMem, type Movable 0 1 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Movable 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Reserve 0 0 0
0 0 0 0 0 0 0 1
Node 0, zone HighMem, type Reserve 11 7 5
1 0 0 0 0 0 0 0
Node 0, zone Movable, type Reserve 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone HighMem, type Isolate 0 0 0
0 0 0 0 0 0 0 0
Node 0, zone Movable, type Isolate 0 0 0
0 0 0 0 0 0 0 0
diff --git a/crash-6.0.8/help.c b/crash-6.0.8/help.c
index 6d6ac5e..9ad6c00 100755
--- a/crash-6.0.8/help.c
+++ b/crash-6.0.8/help.c
@@ -5147,7 +5147,7 @@ NULL
char *help_kmem[] = {
"kmem",
"kernel memory",
-"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z-o] [slab] [[-P] address]\n"
+"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-m|-z-o] [slab] [[-P] address]\n"
" [-g [flags]]",
" This command displays information about the use of kernel memory.\n",
" -f displays the contents of the system free memory headers.",
@@ -5174,6 +5174,8 @@ char *help_kmem[] = {
" values to translate them into kernel virtual addresses.",
" -g displays the enumerator value of all bits in the page
structure's",
" \"flags\" field.",
+" -m displays the number of pages per migrate type for all
orders, for all",
+" nodes.",
" flags when used with -g, translates all bits in this hexadecimal page",
" structure flags value into its enumerator values.",
" slab when used with -s or -S, limits the command to only the
slab cache",
@@ -5605,6 +5607,24 @@ char *help_kmem[] = {
" PG_slab 7 0000080",
" PG_head 14 0004000",
" %s>",
+"\n Display pages per migrate type for all orders, for all nodes:\n",
+" %s> kmem -m",
+" Free pages count per migrate type at order [0-10]:",
+" Node 0, zone Normal, type Unmovable 155 172 92
39 20 8 10 15 7 3 1",
+" Node 0, zone HighMem, type Unmovable 1 2 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Unmovable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Reclaimable 9 3 0
0 1 1 0 0 0 0 0",
+" Node 0, zone HighMem, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Reclaimable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Movable 7 68 35
253 137 38 16 4 0 0 66",
+" Node 0, zone HighMem, type Movable 0 1 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Movable 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Reserve 0 0 0
0 0 0 0 0 0 0 1",
+" Node 0, zone HighMem, type Reserve 11 7 5
1 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Reserve 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Normal, type Isolate 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone HighMem, type Isolate 0 0 0
0 0 0 0 0 0 0 0",
+" Node 0, zone Movable, type Isolate 0 0 0
0 0 0 0 0 0 0 0",
NULL
};
diff --git a/crash-6.0.8/memory.c b/crash-6.0.8/memory.c
index 02a6de1..e03db84 100755
--- a/crash-6.0.8/memory.c
+++ b/crash-6.0.8/memory.c
@@ -264,6 +264,7 @@ static int verify_pfn(ulong);
static void dump_per_cpu_offsets(void);
static void dump_page_flags(ulonglong);
static ulong kmem_cache_nodelists(ulong);
+static void dump_pgtype_info(void);
/*
* Memory display modes specific to this file.
@@ -4044,6 +4045,8 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm)
* -c displays the number of pages in the page_hash_table.
* -C displays all entries in the page_hash_table.
* -i displays informational data shown by /proc/meminfo.
+ * -m displays information on the number of pages per migrate type
+ * for all orders, for all nodes.
*
* -P forces address to be defined as a physical address
* address when used with -f, the address can be either a page pointer
@@ -4090,7 +4093,7 @@ cmd_kmem(void)
int i;
int c;
int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag, oflag, gflag;
- int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag;
+ int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag, mflag;
struct meminfo meminfo;
ulonglong value[MAXARGS];
char buf[BUFSIZE];
@@ -4100,12 +4103,12 @@ cmd_kmem(void)
spec_addr = 0;
sflag = Sflag = pflag = fflag = Fflag = Pflag = zflag = oflag = 0;
vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0;
- gflag = 0;
+ gflag = mflag = 0;
escape = FALSE;
BZERO(&meminfo, sizeof(struct meminfo));
BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
- while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVo")) != EOF) {
+ while ((c = getopt(argcnt, args, "gI:sSFfpvczCinml:L:PVo")) != EOF) {
switch(c)
{
case 'V':
@@ -4206,6 +4209,10 @@ cmd_kmem(void)
gflag = 1;
break;
+ case 'm':
+ mflag = 1;
+ break;
+
default:
argerrs++;
break;
@@ -4215,8 +4222,8 @@ cmd_kmem(void)
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
- if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag +
- vflag + Cflag + cflag + iflag + lflag + Lflag + gflag) > 1) {
+ if ((sflag + Sflag + pflag + fflag + Fflag + Vflag + oflag + vflag +
+ Cflag + cflag + iflag + lflag + Lflag + gflag + mflag) > 1) {
error(INFO, "only one flag allowed!\n");
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -4444,9 +4451,12 @@ cmd_kmem(void)
if (gflag == 1)
dump_page_flags(0);
+ if (mflag == 1)
+ dump_pgtype_info();
+
if (!(sflag + Sflag + pflag + fflag + Fflag + vflag +
Vflag + zflag + oflag + cflag + Cflag + iflag +
- nflag + lflag + Lflag + gflag + meminfo.calls))
+ nflag + lflag + Lflag + gflag + mflag + meminfo.calls))
cmd_usage(pc->curcmd, SYNOPSIS);
}
@@ -7051,6 +7061,163 @@ bailout:
return total_free;
}
+static void dump_pgtype_info(void)
+{
+ int n, m, z, o;
+ int list_count = 0;
+ int free_cnt = 0;
+ int mtype_sym = 0;
+ int mtype_len = 0;
+ ulong *mtypes;
+ ulong node_zones;
+ ulong temp;
+ ulong freelist;
+ ulong *free_ptr;
+ char *free_list_buf;
+ char name_buf[BUFSIZE];
+ char buf[BUFSIZE];
+ struct node_table *nt;
+ struct list_data list_data;
+
+ if (!(vt->flags & (NODES|ZONES)))
+ error(FATAL,
+ "dump_pgtype_info called without (NODES|ZONES)\n");
+
+ if (!VALID_STRUCT(zone))
+ error(FATAL,
+ "zone struct not available in this kernel\n");
+
+ if (VALID_STRUCT(free_area)) {
+ if (SIZE(free_area) == (3 * sizeof(ulong)))
+ error(FATAL,
+ "free_area type not supported by command\n");
+ else
+ list_count = MEMBER_SIZE("free_area",
+ "free_list")/SIZE(list_head);
+ } else
+ error(FATAL,
+ "free_area structure not found\n");
+
+ free_list_buf = GETBUF(SIZE(list_head));
+
+ do {
+ if (symbol_exists("migratetype_names") &&
+ (get_symbol_type("migratetype_names",
+ NULL, NULL) == TYPE_CODE_ARRAY)) {
+
+ open_tmpfile();
+ sprintf(buf, "whatis migratetype_names");
+ if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) {
+ close_tmpfile();
+ break;
+ }
+
+ rewind(pc->tmpfile);
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
+ if (STRNEQ(buf, "type = "))
+ break;
+ }
+ close_tmpfile();
+
+ if (!strstr(buf, "char *") ||
+ (count_chars(buf, '[') != 1) ||
+ (count_chars(buf, ']') != 1))
+ break;
+
+ mtype_len = get_array_length("migratetype_names",
+ NULL, 0);
+
+ mtypes = (ulong *)GETBUF(mtype_len * sizeof(ulong));
+
+ readmem(symbol_value("migratetype_names"),
+ KVADDR, mtypes,
+ (mtype_len * sizeof(ulong)),
+ NULL, FAULT_ON_ERROR);
+
+ mtype_sym = 1;
+ }
+ } while (0);
+
+ fprintf(fp, "%-43s [%d-%d]:",
+ "Free pages count per migrate type at order",
+ 0, vt->nr_free_areas - 1);
+
+ fprintf(fp, "\n");
+
+ for (n = 0; n < vt->numnodes; n++) {
+ nt = &vt->node_table[n];
+ node_zones = nt->pgdat + OFFSET(pglist_data_node_zones);
+
+ for (m = 0; m < list_count; m++) {
+
+ for (z = 0; z < vt->nr_zones; z++) {
+ readmem((node_zones + (z * SIZE(zone)))
+ + OFFSET(zone_name), KVADDR, &temp,
+ sizeof(void *), "node_zones name",
+ FAULT_ON_ERROR);
+ read_string(temp, name_buf, BUFSIZE-1);
+
+ fprintf(fp, "Node %4d, ", nt->node_id);
+ fprintf(fp, "zone %8s, ", name_buf);
+
+ if (mtype_sym) {
+ read_string(mtypes[m],
+ name_buf, BUFSIZE-1);
+ fprintf(fp, "type %12s ", name_buf);
+ } else
+ fprintf(fp, "type %12d ", m);
+
+ for (o = 0; o < vt->nr_free_areas; o++) {
+ freelist =
+ (node_zones + (z * SIZE(zone)))
+ + (OFFSET(zone_free_area) +
+ (o * SIZE(free_area))) +
+ (m * SIZE(list_head));
+
+ readmem(freelist, KVADDR, free_list_buf,
+ SIZE(list_head),
+ "free_area free_list",
+ FAULT_ON_ERROR);
+
+ free_ptr = (ulong *)free_list_buf;
+
+ if (!(*free_ptr) ||
+ (*free_ptr == freelist)) {
+ fprintf(fp, "%6lu ", 0);
+ continue;
+ }
+
+ BZERO(&list_data,
+ sizeof(struct list_data));
+ list_data.flags = RETURN_ON_DUPLICATE;
+ list_data.start = *free_ptr;
+ list_data.end = freelist;
+ list_data.list_head_offset =
+ OFFSET(page_lru) +
+ OFFSET(list_head_next);
+
+ free_cnt = do_list(&list_data);
+ if (free_cnt < 0) {
+ error(pc->curcmd_flags &
+ IGNORE_ERRORS ? INFO : FATAL,
+ "corrupted free list\n");
+ free_cnt = 0;
+ }
+
+ fprintf(fp, "%6lu ", free_cnt);
+ }
+ fprintf(fp, "\n");
+ }
+ }
+ node_zones + OFFSET(zone_free_area);
+ }
+
+ FREEBUF(free_list_buf);
+
+ if (mtype_sym)
+ FREEBUF(mtypes);
+}
+
/*
* dump_kmeminfo displays basic memory use information typically shown
* by /proc/meminfo, and then some...
--
1.7.6