[patch] make ktrdump loop reading the ktr buffers

Aggelos Economopoulos aoiko at cc.ece.ntua.gr
Fri Jun 8 07:32:44 PDT 2007


This patch adds a new flag to ktrdump(8) as discussed on kernel. -s 
functionality has not been tested (no smp here). Cleans up the code a bit, 
not as much as I would like, but still... Written during the week when I was 
too sleepy to study so, please, *test* before commiting.

Aggelos
Index: ktrdump.c
===================================================================
RCS file: /home/aggelos/imports/vcs/dcvs/src/usr.bin/ktrdump/ktrdump.c,v
retrieving revision 1.6
diff -u -u -r1.6 ktrdump.c
--- ktrdump.c	19 Dec 2005 17:09:58 -0000	1.6
+++ ktrdump.c	8 Jun 2007 14:19:31 -0000
@@ -60,6 +60,10 @@
 static const char *trunc_path(const char *str, int maxlen);
 static void read_symbols(const char *execfile);
 static const char *address_to_symbol(void *kptr);
+static struct ktr_buffer *ktr_bufs_init(int);
+static void load_bufs(struct ktr_buffer *, struct ktr_entry **);
+static void print_buf(FILE *, struct ktr_buffer *, int );
+static void print_bufs_timesorted(FILE *, struct ktr_buffer *);
 
 static struct nlist nl[] = {
 	{ "_ktr_version" },
@@ -74,6 +78,7 @@
 static int cflag;
 static int fflag;
 static int iflag;
+static int lflag;
 static int nflag;
 static int qflag;
 static int rflag;
@@ -90,10 +95,20 @@
 static char corefile[PATH_MAX];
 static char execfile[PATH_MAX];
 
-static char desc[SBUFLEN];
 static char errbuf[_POSIX2_LINE_MAX];
-static char fbuf[PATH_MAX];
-static char obuf[PATH_MAX];
+static int ncpus;
+static kvm_t *kd;
+static int entries_per_buf;
+
+struct ktr_buffer {
+	struct ktr_entry *ents;
+	int modified;
+	int last_idx;
+	int kern_idx;
+	int curr_idx;	/* aux */
+	int times_bit_tail;	/* TBD: print on signal */
+};
+
 
 /*
  * Reads the ktr trace buffer from kernel memory and prints the trace entries.
@@ -101,34 +116,20 @@
 int
 main(int ac, char **av)
 {
-	struct ktr_entry **ktr_buf;
-	struct ktr_entry *entry;
-	struct ktr_entry *entryx;
-	uintmax_t tlast, tnow;
-	struct stat sb;
-	kvm_t *kd;
+	struct ktr_buffer *ktr_bufs;
+	struct ktr_entry **ktr_kbuf;
 	FILE *fo;
-	char *p;
-	int64_t first_timestamp;
 	int64_t tts;
 	int *ktr_start_index;
 	int version;
-	int entries;
-	int *ktr_idx;
-	int ncpus;
-	int did_display_flag = 0;
-	int in;
 	int c;
-	int i;
 	int n;
-	int bestn;
-	int row;
 
 	/*
 	 * Parse commandline arguments.
 	 */
 	fo = stdout;
-	while ((c = getopt(ac, av, "acfinqrtxpsA:N:M:o:")) != -1) {
+	while ((c = getopt(ac, av, "acfinqrtxpslA:N:M:o:")) != -1) {
 		switch (c) {
 		case 'a':
 			cflag = 1;
@@ -150,6 +151,9 @@
 		case 'f':
 			fflag = 1;
 			break;
+		case 'l':
+			lflag = 1;
+			break;
 		case 'i':
 			iflag = 1;
 			break;
@@ -228,97 +232,32 @@
 	}
 	if (version > KTR_VERSION)
 		errx(1, "ktr version too high for us to handle");
-	if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) == -1)
+	if (kvm_read(kd, nl[1].n_value, &entries_per_buf,
+				sizeof(entries_per_buf)) == -1)
 		errx(1, "%s", kvm_geterr(kd));
-	ktr_buf = malloc(sizeof(*ktr_buf) * ncpus);
-	ktr_idx = malloc(sizeof(*ktr_idx) * ncpus);
+
+	printf("TSC frequency is %6.3f MHz\n", tsc_frequency / 1000000.0);
+
+	ktr_kbuf = malloc(sizeof(*ktr_kbuf) * ncpus);
 
 	if (nflag == 0)
 		read_symbols(Nflag ? execfile : NULL);
 
-	if (kvm_read(kd, nl[2].n_value, ktr_idx, sizeof(*ktr_idx) * ncpus) == -1)
-		errx(1, "%s", kvm_geterr(kd));
-	if (kvm_read(kd, nl[3].n_value, ktr_buf, sizeof(*ktr_buf) * ncpus) == -1)
+	if (kvm_read(kd, nl[3].n_value, ktr_kbuf, sizeof(*ktr_kbuf) * ncpus) == -1)
 		errx(1, "%s", kvm_geterr(kd));
-	for (n = 0; n < ncpus; ++n) {
-		void *kptr = ktr_buf[n];
-		ktr_buf[n] = malloc(sizeof(**ktr_buf) * entries);
-		if (kvm_read(kd, (uintptr_t)kptr, ktr_buf[n], sizeof(**ktr_buf) * entries) == -1)
-			errx(1, "%s", kvm_geterr(kd));
-	}
 
-	/*
-	 * Figure out the lowest numbered timestamp.
-	 */
-	first_timestamp = 0;
-	printf("TSC frequency is %6.3f MHz\n", tsc_frequency / 1000000.0);
-	for (n = 0; n < ncpus; ++n) {
-		for (i = 0; i < entries; ++i) {
-			entry = &ktr_buf[n][i];
-			if (entry->ktr_timestamp && (first_timestamp == 0 ||
-			    first_timestamp < entry->ktr_timestamp)) {
-				first_timestamp = entry->ktr_timestamp;
-			}
-		}
-	}
+	ktr_bufs = ktr_bufs_init(ncpus);
 
-	/*
-	 * Figure out the starting entry for each cpu
-	 */
-	for (n = 0; n < ncpus; ++n) {
-		ktr_start_index[n] = 0;
-		tts = 0;
-		for (i = 0; i < entries; ++i) {
-			entry = &ktr_buf[n][i];
-			if (entry->ktr_timestamp == 0)
-				continue;
-			if (tts == 0 || tts > entry->ktr_timestamp) {
-				tts = entry->ktr_timestamp;
-				ktr_start_index[n] = i;
-			}
-		}
-	}
-
-	/*
-	 * Now tear through the trace buffer.
-	 */
 	if (sflag) {
-		row = 0;
-		for (;;) {
-			bestn = -1;
-			tts = 0;
+		load_bufs(ktr_bufs, ktr_kbuf);
+		print_bufs_timesorted(fo, ktr_bufs);
+	} else {
+		do {
+			load_bufs(ktr_bufs, ktr_kbuf);
 			for (n = 0; n < ncpus; ++n) {
-				i = ktr_start_index[n];
-				entry = &ktr_buf[n][i];
-				if (entry->ktr_timestamp == 0)
-					continue;
-				if (tts == 0 || tts >= entry->ktr_timestamp) {
-					tts = entry->ktr_timestamp;
-					bestn = n;
-				}
+				print_buf(fo, ktr_bufs, n);
 			}
-			if (bestn < 0 || tts < last_timestamp)
-				break;
-			print_header(fo, row);
-			print_entry(fo, kd, bestn, ktr_start_index[bestn],
-				    &ktr_buf[bestn][ktr_start_index[bestn]]);
-			if (++ktr_start_index[bestn] == entries)
-				ktr_start_index[bestn] = 0;
-			last_timestamp = tts;
-			++row;
-		}
-	} else {
-		for (n = 0; n < ncpus; ++n) {
-			last_timestamp = first_timestamp;
-			i = ktr_start_index[n];
-			do {
-				entry = &ktr_buf[n][i];
-				print_header(fo, i);
-				print_entry(fo, kd, n, i, &ktr_buf[n][i]);
-				if (++i == entries)
-					i = 0;
-			} while (i != ktr_start_index[n]);
-		}
+		} while (lflag);
 	}
 	return (0);
 }
@@ -552,6 +491,154 @@
 	return(buf);
 }
 
+static
+struct ktr_buffer *
+ktr_bufs_init(int ncpus)
+{
+	struct ktr_buffer *ktr_bufs, *it;
+	int i;
+
+	ktr_bufs = malloc(sizeof(*ktr_bufs) * ncpus);
+	if (!ktr_bufs)
+		err(1, "can't allocate data structures\n");
+	for (i = 0; i < ncpus; ++i) {
+		it = ktr_bufs + i;
+		if (!(it->ents = malloc(sizeof(struct ktr_entry) *
+							entries_per_buf)))
+			err(1, "can't allocate data structures\n");
+		it->last_idx = -1;
+		it->times_bit_tail = 0;
+	}
+	return ktr_bufs;
+}
+
+static
+void
+get_indices(kvm_t *kd, int *idx)
+{
+	if (kvm_read(kd, nl[2].n_value, idx, sizeof(*idx) * ncpus) == -1)
+		errx(1, "%s", kvm_geterr(kd));
+}
+
+static
+void
+load_bufs(struct ktr_buffer *ktr_bufs, struct ktr_entry **kbufs)
+{
+	static int *kern_idx;
+	struct ktr_buffer *ktr_buf;
+	int i;
+
+	if (!kern_idx) {
+		kern_idx = malloc(sizeof(*kern_idx) * ncpus);
+		if (!kern_idx) {
+			err(1, "can't allocate data structures\n");
+		}
+	}
+
+	get_indices(kd, kern_idx);
+	for (i = 0; i < ncpus; ++i) {
+		ktr_buf = &ktr_bufs[i];
+		if (kern_idx[i] == ktr_buf->last_idx)
+			continue;
+		ktr_buf->kern_idx = kern_idx[i];
+		if (ktr_buf->last_idx < 0)
+			ktr_buf->last_idx = ktr_buf->kern_idx;
+		if (kvm_read(kd, (uintptr_t)kbufs[i], ktr_bufs[i].ents,
+				sizeof(struct ktr_entry) * entries_per_buf)
+									== -1)
+			errx(1, "%s", kvm_geterr(kd));
+		ktr_buf->modified = !0;
+	}
+
+}
+
+static
+int
+earliest_ts(struct ktr_buffer *buf)
+{
+	struct ktr_entry *e;
+	int i, low;
+
+	low = 0;
+	for (i = 0, e = &buf->ents[0]; i < entries_per_buf; ++i, ++e) {
+		if (e->ktr_timestamp < buf->ents[low].ktr_timestamp) {
+			low = i;
+		}
+	}
+	return low;
+}
+
+static
+void
+print_buf(FILE *fo, struct ktr_buffer *ktr_bufs, int cpu)
+{
+	int i, first, last, iearliest;
+	struct ktr_buffer *buf = ktr_bufs + cpu;
+
+	iearliest = earliest_ts(buf);
+	last_timestamp = buf->ents[iearliest].ktr_timestamp;
+	if (!buf->modified)
+		return;
+	last = buf->kern_idx & (entries_per_buf - 1);
+	if (buf->kern_idx > buf->last_idx + entries_per_buf) {
+		++buf->times_bit_tail;
+		first = iearliest & (entries_per_buf - 1);
+	} else {
+		first = buf->last_idx & (entries_per_buf - 1);
+	}
+	i = first;
+	do {
+		print_header(fo, i);
+		print_entry(fo, kd, cpu, i, &buf->ents[i]);
+		if (++i == entries_per_buf)
+			i = 0;
+	} while (i != last);
+	if (i)
+		--i;
+	else
+		i = entries_per_buf - 1;
+	buf->last_idx = buf->kern_idx;
+	buf->modified = 0;
+}
+
+static
+void
+print_bufs_timesorted(FILE *fo, struct ktr_buffer *ktr_bufs)
+{
+	struct ktr_entry *ent;
+	struct ktr_buffer *buf;
+	int row, n, bestn;
+	u_int64_t ts;
+
+	last_timestamp = 0;
+	row = 0;
+	for (n = 0; n < ncpus; ++n) {
+		buf = ktr_bufs + n;
+		buf->curr_idx = buf->last_idx & (entries_per_buf - 1);
+	}
+	for (;;) {
+		ts = 0;
+		bestn = -1;
+		for (n = 0; n < ncpus; ++n) {
+			buf = ktr_bufs + n;
+			ent = &buf->ents[buf->curr_idx];
+			if (!ts || (ts >= ent->ktr_timestamp)) {
+				ts = ent->ktr_timestamp;
+				bestn = n;
+			}
+		}
+		if ((bestn < 0) || (ts < last_timestamp))
+			break;
+		buf = ktr_bufs + bestn;
+		print_header(fo, row);
+		print_entry(fo, kd, bestn, buf->curr_idx, &buf->ents[buf->curr_idx]);
+		if (++buf->curr_idx == entries_per_buf)
+			buf->curr_idx = 0;
+		last_timestamp = ts;
+		++row;
+	}
+}
+
 static void
 usage(void)
 {




More information about the Submit mailing list