[Crash-utility] [PATCH 1/1] Speed up list/tree '-s' output.

Alexandr Terekhov Alexandr_Terekhov at epam.com
Tue Jul 26 12:01:36 UTC 2016


Hi Dave,

here is the patch which introduces new key of `list` and `tree` commands.
If new key is used, crash reads fields by means of 'readmem' function
instead of parsing the gdb output. Therefore works much faster:

% echo "tree -t radix -r address_space.page_tree -s page.flags,index,private ffff880456375220 | wc -l" | time ./crash -s ../crash_images/504.23.4.el6_x86-64-vm*
crash: invalid task address: ffffffff81a01ea8
scroll: off (/usr/bin/less)
extend: r.so: No such device or address
16652
./crash -s ../crash_images/504.23.4.el6_x86-64-vm*  226.63s user 2.90s system 99% cpu 3:51.42 total

% echo "tree -t radix -r address_space.page_tree -S page.flags,index,private ffff880456375220 | wc -l" | time ./crash -s ../crash_images/504.23.4.el6_x86-64-vm*
crash: invalid task address: ffffffff81a01ea8
scroll: off (/usr/bin/less)
extend: r.so: No such device or address
16652
./crash -s ../crash_images/504.23.4.el6_x86-64-vm*  5.30s user 0.14s system 99% cpu 5.460 total

11,000,000 records might be dealt with within several minutes.

Looking forward to your comments.

Best,
Alexandr


--- crash-7.1.5.orig/tools.c	2016-04-27 21:46:50.000000000 +0300
+++ crash-7.1.5/tools.c	2016-07-26 13:56:27.192042851 +0300
@@ -23,10 +23,11 @@
 struct hq_entry;
 static void dealloc_hq_entry(struct hq_entry *);
 static void show_options(void);
-static void dump_struct_members(struct list_data *, int, ulong);
+static void dump_struct_members(struct struct_req_entry *, int, ulong);
 static void rbtree_iteration(ulong, struct tree_data *, char *);
 static void rdtree_iteration(ulong, struct tree_data *, char *, ulong, uint);
-static void dump_struct_members_for_tree(struct tree_data *, int, ulong);
+static struct struct_req_entry *fill_member_offsets(char *);
+static void print_value(char *, ulong, short, unsigned int);
 
 /*
  *  General purpose error reporting routine.  Type INFO prints the message
@@ -3229,7 +3230,7 @@
 	BZERO(ld, sizeof(struct list_data));
 	struct_list_offset = 0;
 
-	while ((c = getopt(argcnt, args, "Hhrs:e:o:xdl:")) != EOF) {
+	while ((c = getopt(argcnt, args, "Hhrs:S:e:o:xdl:")) != EOF) {
		 switch(c)
 		{
 		case 'H':
@@ -3246,10 +3247,15 @@
 			break;
 
 		case 's':
-			if (ld->structname_args++ == 0) 
-				hq_open();
-			hq_enter((ulong)optarg);
-			break;
+		case 'S':
+			if (ld->entries == 8)
+				error(WARNING, "Too many `-S` arguments."
+				      " Ignoring argument: '%s'\n", optarg);
+			else {
+				ld->e[ld->entries] = fill_member_offsets(optarg);
+				ld->e[ld->entries++]->ff = (c == 's' ? FANCY : FAST);
+			}
+			break;
 
 		case 'l':
			 if (IS_A_NUMBER(optarg))
@@ -3313,13 +3319,10 @@
 		cmd_usage(pc->curcmd, SYNOPSIS);
 	}
 
-	if (ld->structname_args) {
-		ld->structname = (char **)GETBUF(sizeof(char *) * ld->structname_args);
-		retrieve_list((ulong *)ld->structname, ld->structname_args); 
-		hq_close(); 
+	if (ld->entries) {
 		ld->struct_list_offset = struct_list_offset;
 	} else if (struct_list_offset) {
-		error(INFO, "-l option can only be used with -s option\n");
+		error(INFO, "-l option can only be used with -s or -S option\n");
 		cmd_usage(pc->curcmd, SYNOPSIS);
 	}
 
@@ -3478,9 +3481,6 @@
 	hq_open();
 	c = do_list(ld);
 	hq_close();
-
-	if (ld->structname_args)
-		FREEBUF(ld->structname);
 }
 
 
@@ -3493,8 +3493,9 @@
 {
 	ulong next, last, first;
 	ulong searchfor, readflag;
-	int i, count, others, close_hq_on_return;
+	int i, j, count, others, close_hq_on_return;
 	unsigned int radix;
+	char b[BUFSIZE];
 
 	if (CRASHDEBUG(1)) {
 		others = 0;
@@ -3531,11 +3532,16 @@
 		console("  list_head_offset: %ld\n", ld->list_head_offset);
 		console("	       end: %lx\n", ld->end);
 		console("	 searchfor: %lx\n", ld->searchfor);
-		console("   structname_args: %lx\n", ld->structname_args);
-		if (!ld->structname_args)
-			console("	structname: (unused)\n");
-		for (i = 0; i < ld->structname_args; i++)	
-			console("     structname[%d]: %s\n", i, ld->structname[i]);
+		console("	   entries: %lx\n", ld->entries);
+		for (i = 0; i < ld->entries; i++) {
+			console("	  entry[%d]: ", i);
+			for (j = 0; j < ld->e[i]->count; j++) {
+				snprintf(b, BUFSIZE, "{ member: %s, width: %d, offset: %d }",
+					 ld->e[i]->member[j], ld->e[i]->width[j], ld->e[i]->offset[j]);
+				console("%s", b);
+				console(j == ld->e[i]->count - 1 ? "\n" : ", ");
+			}
+		}
 		console("	    header: %s\n", ld->header);
 		console("	  list_ptr: %lx\n", (ulong)ld->list_ptr);
 		console("     callback_func: %lx\n", (ulong)ld->callback_func);
@@ -3584,21 +3590,16 @@
 		if (ld->flags & VERBOSE) {
 			fprintf(fp, "%lx\n", next - ld->list_head_offset);
 
-			if (ld->structname) {
-				for (i = 0; i < ld->structname_args; i++) {
-					switch (count_chars(ld->structname[i], '.'))
-					{
-					case 0:
-						dump_struct(ld->structname[i], 
-							next - ld->list_head_offset - ld->struct_list_offset,
-							radix);
-						break;
-					default:
-						dump_struct_members(ld, i, next);
-						break;
-					}
-				}
-			}
+			for (i = 0; i < ld->entries; i++) {
+				struct struct_req_entry *e = ld->e[i];
+				if (e->count == 0)
+					dump_struct(e->name, 
+						next - ld->list_head_offset - ld->struct_list_offset,
+						radix);
+				else
+					dump_struct_members(e, radix,
+						next - ld->list_head_offset - ld->struct_list_offset);
+			}
 		}
 
		 if (next && !hq_enter(next - ld->list_head_offset)) {
@@ -3689,41 +3690,22 @@
  *	    struct.member1,member2,member3
  */
 void
-dump_struct_members(struct list_data *ld, int idx, ulong next)
+dump_struct_members(struct struct_req_entry *e, int radix, ulong p)
 {
-	int i, argc;
-	char *p1, *p2;
-	char *structname, *members;
-	char *arglist[MAXARGS];
-	unsigned int radix;
+	unsigned int i;
+	char b[BUFSIZE];
 
-	if (ld->flags & LIST_STRUCT_RADIX_10)
-		radix = 10;
-	else if (ld->flags & LIST_STRUCT_RADIX_16)
-		radix = 16;
-	else
-		radix = 0;
-
-	structname = GETBUF(strlen(ld->structname[idx])+1);
-	members = GETBUF(strlen(ld->structname[idx])+1);
-
-	strcpy(structname, ld->structname[idx]);
-	p1 = strstr(structname, ".") + 1;
-
-	p2 = strstr(ld->structname[idx], ".") + 1;
-	strcpy(members, p2);
-	replace_string(members, ",", ' ');
-	argc = parse_line(members, arglist);
+	if (!IS_KVADDR(p))
+		return;
 
-	for (i = 0; i < argc; i++) {
-		*p1 = NULLCHAR;
-		strcat(structname, arglist[i]);
- 		dump_struct_member(structname, 
-			next - ld->list_head_offset - ld->struct_list_offset, radix);
+	for (i = 0; i < e->count; i++) {
+		if (e->ff == FANCY || e->width[i] == 0 || e->width[i] > 8) {
+			snprintf(b, BUFSIZE, "%s.%s", e->name, e->member[i]);
+			dump_struct_member(b, p, radix);
+		} else {
+			print_value(e->member[i], p + e->offset[i], e->width[i], radix);
+		}
 	}
-
-	FREEBUF(structname);
-	FREEBUF(members);
 }
 
 #define RADIXTREE_REQUEST (0x1)
@@ -3745,7 +3727,7 @@
 	td = &tree_data;
 	BZERO(td, sizeof(struct tree_data));
 
-	while ((c = getopt(argcnt, args, "xdt:r:o:s:pN")) != EOF) {
+	while ((c = getopt(argcnt, args, "xdt:r:o:s:S:pN")) != EOF) {
 		switch (c)
 		{
 		case 't':
@@ -3799,11 +3781,15 @@
 			break;
 
 		case 's':
-			if (td->structname_args++ == 0) 
-				hq_open();
-			hq_enter((ulong)optarg);
-			break;
-
+		case 'S':
+			if (td->entries == 8)
+				error(WARNING, "Too many `-S` arguments."
+				      " Ignoring argument: '%s'\n", optarg);
+			else {
+				td->e[td->entries] = fill_member_offsets(optarg);
+				td->e[td->entries++]->ff = (c == 's' ? FANCY : FAST);
+			}
+			break;
 		case 'p':
 			td->flags |= TREE_POSITION_DISPLAY;
 			break;
@@ -3878,13 +3864,6 @@
 		cmd_usage(pc->curcmd, SYNOPSIS);
 	}
 
-	if (td->structname_args) {
-		td->structname = (char **)GETBUF(sizeof(char *) *
-				td->structname_args);
-		retrieve_list((ulong *)td->structname, td->structname_args); 
-		hq_close();
-	}
-
 	if (!(td->flags & TREE_NODE_POINTER))
 		td->start = td->start + root_offset;
 
@@ -3916,7 +3895,7 @@
 			td->flags & TREE_NODE_POINTER ? "yes" : "no");
 		fprintf(fp, "	     start: %lx\n", td->start);
 		fprintf(fp, "node_member_offset: %ld\n", td->node_member_offset);
-		fprintf(fp, "   structname_args: %d\n", td->structname_args);
+		fprintf(fp, "	   entries: %d\n", td->entries);
 		fprintf(fp, "	     count: %d\n", td->count);
 	}
 
@@ -3924,20 +3903,68 @@
 	td->flags |= VERBOSE;
 
 	hq_open();
+
 	if (type_flag & RADIXTREE_REQUEST)
 		do_rdtree(td);
 	else
 		do_rbtree(td);
 	hq_close();
-
-	if (td->structname_args)
-		FREEBUF(td->structname);
 }
 
 static ulong RADIX_TREE_MAP_SHIFT = UNINITIALIZED;
 static ulong RADIX_TREE_MAP_SIZE = UNINITIALIZED;
 static ulong RADIX_TREE_MAP_MASK = UNINITIALIZED;
 
+static struct struct_req_entry *
+fill_member_offsets(char *arg)
+{
+	int j;
+	char *p, m;
+	struct struct_req_entry *e;
+	char b[BUFSIZE];
+
+	if (!(arg && *arg))
+		return NULL;
+
+	j = count_chars(arg, ',') + 1;
+	e = (struct struct_req_entry *)GETBUF(sizeof(*e));
+
+	e->arg = GETBUF(strlen(arg + 1));
+	strcpy(e->arg, arg);
+
+	m = ((p = strchr(e->arg, '.')) != NULL);
+	if (!p++) 
+		p = e->arg + strlen(e->arg) + 1;
+
+	e->name = GETBUF(p - e->arg);
+	strncpy(e->name, e->arg, p - e->arg - 1);
+
+	if (!m)
+		return e;
+
+	e->count  = count_chars(p, ',') + 1;
+	e->width  = GETBUF(e->count);
+	e->member = (char **)GETBUF(e->count * sizeof(char *));
+	e->offset = (short *)GETBUF(e->count * sizeof(short));
+
+	replace_string(p, ",", ' ');
+	parse_line(p, e->member);
+
+	for (j = 0; j < e->count; j++) {
+		e->offset[j] = MEMBER_OFFSET(e->name, e->member[j]);
+		if (e->offset[j] == -1)
+			e->offset[j] = ANON_MEMBER_OFFSET(e->name, e->member[j]);
+		if (e->offset[j] == -1)
+			break;
+
+		// Dirty hack for obtaining size of particular field
+		snprintf(b, BUFSIZE, "%s + 1", e->member[j]);
+		e->width[j] = ANON_MEMBER_OFFSET(e->name, b) - e->offset[j];
+	}
+
+	return e;
+}
+
 int
 do_rdtree(struct tree_data *td)
 {
@@ -4049,28 +4076,20 @@
 			if (td->flags & TREE_POSITION_DISPLAY)
 				fprintf(fp, "  position: %s/%d\n", pos, index);
 
-			if (td->structname) {
-				if (td->flags & TREE_STRUCT_RADIX_10)
-					print_radix = 10;
-				else if (td->flags & TREE_STRUCT_RADIX_16)
-					print_radix = 16;
-				else
-					print_radix = 0;
+			if (td->flags & TREE_STRUCT_RADIX_10)
+				print_radix = 10;
+			else if (td->flags & TREE_STRUCT_RADIX_16)
+				print_radix = 16;
+			else
+				print_radix = 0;
 
-				for (i = 0; i < td->structname_args; i++) {
-					switch(count_chars(td->structname[i], '.'))
-					{
-					case 0:
-						dump_struct(td->structname[i],
-							slot, print_radix);
-						break;
-					default:
-						dump_struct_members_for_tree(td, i,
-							slot);
-						break;
-					}
-				}
-			}
+			for (i = 0; i < td->entries; i++) {
+				struct struct_req_entry *e = td->e[i];
+				if (e->count == 0)
+					dump_struct(e->name, slot, print_radix);
+				else
+					dump_struct_members(td->e[i], print_radix, slot);
+			}
 		} else 
 			rdtree_iteration(slot, td, pos, index, height-1);
 	}
@@ -4124,26 +4143,20 @@
 	if (td->flags & TREE_POSITION_DISPLAY)
 		fprintf(fp, "  position: %s\n", pos);
 
-	if (td->structname) {
-		if (td->flags & TREE_STRUCT_RADIX_10)
-			print_radix = 10;
-		else if (td->flags & TREE_STRUCT_RADIX_16)
-			print_radix = 16;
-		else
-			print_radix = 0;
+	if (td->flags & TREE_STRUCT_RADIX_10)
+		print_radix = 10;
+	else if (td->flags & TREE_STRUCT_RADIX_16)
+		print_radix = 16;
+	else
+		print_radix = 0;
 
-		for (i = 0; i < td->structname_args; i++) {
-			switch(count_chars(td->structname[i], '.'))
-			{
-			case 0:
-				dump_struct(td->structname[i], struct_p, print_radix);
-				break;
-			default:
-				dump_struct_members_for_tree(td, i, struct_p);
-				break;
-			}
-		}
-	}
+	for (i = 0; i < td->entries; i++) {
+		struct struct_req_entry *e = td->e[i];
+		if (e->count == 0)
+			dump_struct(e->name, struct_p, print_radix);
+		else
+			dump_struct_members(td->e[i], print_radix, struct_p);
+	}
 
 	readmem(node_p+OFFSET(rb_node_rb_left), KVADDR, &left_p,
 		sizeof(void *), "rb_node rb_left", FAULT_ON_ERROR);
@@ -4157,40 +4170,32 @@
 	rbtree_iteration(right_p, td, right_pos);		
 }
 
-void
-dump_struct_members_for_tree(struct tree_data *td, int idx, ulong struct_p)
+static void
+print_value(char *name, ulong addr, short width, unsigned int radix)
 {
-	int i, argc;
-	uint print_radix;
-	char *p1;
-	char *structname, *members;
-	char *arglist[MAXARGS];
-
-	if (td->flags & TREE_STRUCT_RADIX_10)
-		print_radix = 10;
-	else if (td->flags & TREE_STRUCT_RADIX_16)
-		print_radix = 16;
-	else
-		print_radix = 0;
-
-	structname = GETBUF(strlen(td->structname[idx])+1);
-	members = GETBUF(strlen(td->structname[idx])+1);
-
-	strcpy(structname, td->structname[idx]);
-	p1 = strstr(structname, ".") + 1;
+	union { uint64_t v64; uint32_t v32;
+		uint16_t v16; uint8_t v8;
+	} v;
+	char fmt[BUFSIZE];
+
+	if (!readmem(addr, KVADDR, &v, width,
+	    "structure value", RETURN_ON_ERROR | QUIET)) {
+		error(INFO, "cannot access field: %s at %lx\n", name, addr);
+		return;
+	}
+	snprintf(fmt, BUFSIZE, "  %%s = %s%%%s%s\n",
+		 (radix == 16 ? "0x" : ""),
+		 (width == 8 ? "l" : ""),
+		 (radix == 16 ? "x" : "u" )
+		);
 
-	strcpy(members, p1);
-	replace_string(members, ",", ' ');
-	argc = parse_line(members, arglist);
 
-	for (i = 0; i <argc; i++) {
-		*p1 = NULLCHAR;
-		strcat(structname, arglist[i]);
-		dump_struct_member(structname, struct_p, print_radix);
+	switch (width) {
+		case 1: fprintf(fp, fmt, name, v.v8); break;
+		case 2: fprintf(fp, fmt, name, v.v16); break;
+		case 4: fprintf(fp, fmt, name, v.v32); break;
+		case 8: fprintf(fp, fmt, name, v.v64); break;
 	}
-
-	FREEBUF(structname);
-	FREEBUF(members);
 }
 
 /*
--- crash-7.1.5.orig/defs.h	2016-04-27 21:46:50.000000000 +0300
+++ crash-7.1.5/defs.h	2016-07-25 14:43:32.224688448 +0300
@@ -2376,6 +2376,15 @@
 
 #define union_name struct_name
 
+enum fast_or_fancy { FAST, FANCY };
+struct struct_req_entry {
+	char *arg, *name;
+	char **member, *width;
+	short *offset;
+	unsigned char count;
+	enum fast_or_fancy ff;
+};
+
 struct list_data {	     /* generic structure used by do_list() to walk */
	 ulong flags;	   /* through linked lists in the kernel */
	 ulong start;
@@ -2383,13 +2392,14 @@
 	long list_head_offset;
	 ulong end;
 	ulong searchfor;
-	char **structname;
-	int structname_args;
 	char *header;
 	ulong *list_ptr;
 	int (*callback_func)(void *, void *); 
 	void *callback_data;
 	long struct_list_offset;
+	int count;
+	int entries;
+	struct struct_req_entry *e[8];
 };
 #define LIST_OFFSET_ENTERED  (VERBOSE << 1)
 #define LIST_START_ENTERED   (VERBOSE << 2)
@@ -2408,9 +2418,9 @@
 	ulong flags;
 	ulong start;
 	long node_member_offset;
-	char **structname;
-	int structname_args;
 	int count;
+	int entries;
+	struct struct_req_entry *e[8];
 };
 
 #define TREE_ROOT_OFFSET_ENTERED  (VERBOSE << 1)
--- crash-7.1.5.orig/help.c	2016-04-27 21:46:50.000000000 +0300
+++ crash-7.1.5/help.c	2016-07-26 14:02:42.192044349 +0300
@@ -5583,6 +5583,9 @@
 "	     or \"struct.member[index]\"; embedded member specifications may",
 "	     extend beyond one level deep by expressing the struct argument as", 
 "	     \"struct.member.member.member...\".",
+"  -S struct  Do exactly the same thing as `-s`, but instead of parsing gdb output",
+"	     it reads value from memory, therefore it works much faster for"
+"	     1-, 2-, 4-, and 8-bytes fields."
 "	 -x  Override default output format with hexadecimal format.",
 "	 -d  Override default output format with decimal format.",
 "	 -p  Display the node's position information, showing the relationship",




More information about the Crash-utility mailing list