Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/procstat/procstat_kstack.c
/*- | /*- | ||||
* Copyright (c) 2007 Robert N. M. Watson | * Copyright (c) 2007 Robert N. M. Watson | ||||
* Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) { | ||||
if (ts == TS_FUNC || (kflag > 1 && ts == TS_OFF)) { | if (ts == TS_FUNC || (kflag > 1 && ts == TS_OFF)) { | ||||
*cp_new = *cp_old; | *cp_new = *cp_old; | ||||
cp_new++; | cp_new++; | ||||
} | } | ||||
} | } | ||||
*cp_new = '\0'; | *cp_new = '\0'; | ||||
} | } | ||||
static void | |||||
kstack_cleanup_encoded(const char *old, char *new, int kflag) | |||||
{ | |||||
enum trace_state old_ts, ts; | |||||
const char *cp_old; | |||||
char *cp_new, *cp_loop, *cp_tofree, *cp_line; | |||||
ts = TS_FRAMENUM; | |||||
if (kflag == 1) { | |||||
for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) { | |||||
switch (*cp_old) { | |||||
case '\n': | |||||
*cp_new = *cp_old; | |||||
cp_new++; | |||||
case ' ': | |||||
case '+': | |||||
old_ts = ts; | |||||
ts = kstack_nextstate(old_ts); | |||||
continue; | |||||
} | |||||
if (ts == TS_FUNC) { | |||||
*cp_new = *cp_old; | |||||
cp_new++; | |||||
} | |||||
} | |||||
cp_tofree = cp_loop = strdup(new); | |||||
} else | |||||
cp_tofree = cp_loop = strdup(old); | |||||
while ((cp_line = strsep(&cp_loop, "\n")) != NULL) { | |||||
if (strlen(cp_line) != 0 && *cp_line != 127) | |||||
xo_emit("{le:token/%s}", cp_line); | |||||
} | |||||
*cp_new = '\0'; | |||||
free(cp_tofree); | |||||
} | |||||
/* | /* | ||||
* Sort threads by tid. | * Sort threads by tid. | ||||
*/ | */ | ||||
static int | static int | ||||
kinfo_kstack_compare(const void *a, const void *b) | kinfo_kstack_compare(const void *a, const void *b) | ||||
{ | { | ||||
return ((const struct kinfo_kstack *)a)->kkst_tid - | return ((const struct kinfo_kstack *)a)->kkst_tid - | ||||
((const struct kinfo_kstack *)b)->kkst_tid; | ((const struct kinfo_kstack *)b)->kkst_tid; | ||||
} | } | ||||
static void | static void | ||||
kinfo_kstack_sort(struct kinfo_kstack *kkstp, int count) | kinfo_kstack_sort(struct kinfo_kstack *kkstp, int count) | ||||
{ | { | ||||
qsort(kkstp, count, sizeof(*kkstp), kinfo_kstack_compare); | qsort(kkstp, count, sizeof(*kkstp), kinfo_kstack_compare); | ||||
} | } | ||||
void | void | ||||
procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) | procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) | ||||
{ | { | ||||
struct kinfo_kstack *kkstp, *kkstp_free; | struct kinfo_kstack *kkstp, *kkstp_free; | ||||
struct kinfo_proc *kip, *kip_free; | struct kinfo_proc *kip, *kip_free; | ||||
char trace[KKST_MAXLEN]; | char trace[KKST_MAXLEN], encoded_trace[KKST_MAXLEN]; | ||||
unsigned int i, j; | unsigned int i, j; | ||||
unsigned int kip_count, kstk_count; | unsigned int kip_count, kstk_count; | ||||
if (!hflag) | if (!hflag) | ||||
printf("%5s %6s %-16s %-16s %-29s\n", "PID", "TID", "COMM", | xo_emit("{T:/%5s %6s %-16s %-16s %-29s}\n", "PID", "TID", "COMM", | ||||
"TDNAME", "KSTACK"); | "TDNAME", "KSTACK"); | ||||
kkstp = kkstp_free = procstat_getkstack(procstat, kipp, &kstk_count); | kkstp = kkstp_free = procstat_getkstack(procstat, kipp, &kstk_count); | ||||
if (kkstp == NULL) | if (kkstp == NULL) | ||||
return; | return; | ||||
/* | /* | ||||
* We need to re-query for thread information, so don't use *kipp. | * We need to re-query for thread information, so don't use *kipp. | ||||
Show All 18 Lines | for (i = 0; i < kstk_count; i++) { | ||||
for (j = 0; j < kip_count; j++) { | for (j = 0; j < kip_count; j++) { | ||||
kipp = &kip_free[j]; | kipp = &kip_free[j]; | ||||
if (kkstp->kkst_tid == kipp->ki_tid) | if (kkstp->kkst_tid == kipp->ki_tid) | ||||
break; | break; | ||||
} | } | ||||
if (kipp == NULL) | if (kipp == NULL) | ||||
continue; | continue; | ||||
printf("%5d ", kipp->ki_pid); | xo_emit("{k:process_id/%5d/%d} ", kipp->ki_pid); | ||||
printf("%6d ", kkstp->kkst_tid); | xo_emit("{:thread_id/%6d/%d} ", kkstp->kkst_tid); | ||||
printf("%-16s ", kipp->ki_comm); | xo_emit("{:command/%-16s/%s} ", kipp->ki_comm); | ||||
printf("%-16s ", (strlen(kipp->ki_tdname) && | xo_emit("{:thread_name/%-16s/%s} ", (strlen(kipp->ki_tdname) && | ||||
(strcmp(kipp->ki_comm, kipp->ki_tdname) != 0)) ? | (strcmp(kipp->ki_comm, kipp->ki_tdname) != 0)) ? | ||||
kipp->ki_tdname : "-"); | kipp->ki_tdname : "-"); | ||||
switch (kkstp->kkst_state) { | switch (kkstp->kkst_state) { | ||||
case KKST_STATE_RUNNING: | case KKST_STATE_RUNNING: | ||||
printf("%-29s\n", "<running>"); | xo_emit("{:state/%-29s/%s}\n", "<running>"); | ||||
continue; | continue; | ||||
case KKST_STATE_SWAPPED: | case KKST_STATE_SWAPPED: | ||||
printf("%-29s\n", "<swapped>"); | xo_emit("{:state/%-29s/%s}\n", "<swapped>"); | ||||
continue; | continue; | ||||
case KKST_STATE_STACKOK: | case KKST_STATE_STACKOK: | ||||
break; | break; | ||||
default: | default: | ||||
printf("%-29s\n", "<unknown>"); | xo_emit("{:state/%-29s/%s}\n", "<unknown>"); | ||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
* The kernel generates a trace with carriage returns between | * The kernel generates a trace with carriage returns between | ||||
* entries, but for a more compact view, we convert carriage | * entries, but for a more compact view, we convert carriage | ||||
* returns to spaces. | * returns to spaces. | ||||
*/ | */ | ||||
kstack_cleanup(kkstp->kkst_trace, trace, kflag); | kstack_cleanup(kkstp->kkst_trace, trace, kflag); | ||||
printf("%-29s\n", trace); | xo_open_list("trace"); | ||||
kstack_cleanup_encoded(kkstp->kkst_trace, encoded_trace, kflag); | |||||
xo_close_list("trace"); | |||||
xo_emit("{d:trace/%-29s}\n", trace); | |||||
} | } | ||||
procstat_freekstack(procstat, kkstp_free); | procstat_freekstack(procstat, kkstp_free); | ||||
procstat_freeprocs(procstat, kip_free); | procstat_freeprocs(procstat, kip_free); | ||||
} | } |