[Crash-utility] [PATCH] kmem option to display pages per migrate type

Dave Anderson anderson at redhat.com
Fri Mar 29 19:46:25 UTC 2013



----- Original Message -----
> 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.

OK, now there's two competing "kmem -m" patch requests out there -- neither
of which I'm particularly interested in maintaining.

Look, the crash utility could effectively mimic every file in the
/proc filesystem.  But that doesn't mean that it should -- somewhere
that has to be a line to be drawn.

Can you make it an extension module?  I'll host it on the extensions
web page, and if there becomes a consensus where people find that they
can't live without it, then it can be reconsidered for the base
crash utility.

Dave

 

> 
> 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
> 




More information about the Crash-utility mailing list