[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