*/
/*
-cc -I. -DKERNEL_PRIVATE -O -o sc_usage sc_usage.c
+cc -I. -DKERNEL_PRIVATE -O -o sc_usage sc_usage.c -lncurses
*/
#define Default_DELAY 1 /* default delay interval */
#include <libc.h>
#include <termios.h>
-#include <bsd/curses.h>
+#include <curses.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <errno.h>
-#import <mach/clock_types.h>
+#include <mach/mach_time.h>
#include <err.h>
#define MAX_NESTED 8
#define MAX_FAULTS 5
+/* If NUMPARMS from kernel changes, it will be reflected in PATHLENGTH as well */
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(long))
char *state_name[] = {
"Dont Know",
#define WAITING 3
#define PREEMPTED 4
-typedef struct {
- natural_t hi;
- natural_t lo;
-} AbsoluteTime;
-
-
struct entry {
int sc_state;
int type;
int depth;
int vfslookup;
int curpri;
- char pathname[32];
+ long *pathptr;
+ char pathname[PATHLENGTH + 1];
struct entry th_entry[MAX_NESTED];
};
#define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
double divisor = DIVISOR;
-struct termios tmode, omode;
int mib[6];
size_t needed;
move(LINES - 1, 0);
refresh();
endwin();
-
- tcsetattr(0, TCSANOW, &omode);
}
set_enable(0);
set_pidcheck(pid, 0);
move(LINES - 1, 0);
refresh();
endwin();
-
- tcsetattr(0, TCSANOW, &omode);
}
printf("sc_usage: ");
newLINES = 1;
}
-
-/* raw read of the timebase register */
-void clock_get_uptime(
- AbsoluteTime *result)
-{
-#ifdef __ppc__
-
- natural_t hi, lo, hic;
-
- do {
- asm volatile(" mftbu %0" : "=r" (hi));
- asm volatile(" mftb %0" : "=r" (lo));
- asm volatile(" mftbu %0" : "=r" (hic));
- } while (hic != hi);
-
- result->lo = lo;
- result->hi = hi;
-#else
- result->lo = 0;
- result->hi = 0;
-#endif /* __ppc__ */
-}
-
int
exit_usage(myname) {
if (no_screen_refresh == 0) {
- if (tcgetattr(0, &tmode) < 0) {
- printf("can't get terminal attributes\n");
- exit(1);
- }
- omode = tmode;
-
- tmode.c_lflag &= ~ICANON;
- tmode.c_cc[VMIN] = 0;
- tmode.c_cc[VTIME] = 1;
- if (tcsetattr(0, TCSANOW, &tmode) < 0) {
- printf("can't set terminal attributes\n");
- exit(1);
- }
/* initializes curses and screen (last) */
- initscr();
+ if (initscr() == (WINDOW *) 0)
+ {
+ printf("Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+ cbreak();
+ timeout(100);
+ noecho();
+
clear();
refresh();
}
/* set up signal handlers */
signal(SIGINT, leave);
signal(SIGQUIT, leave);
+ signal(SIGHUP, leave);
+ signal(SIGTERM, leave);
signal(SIGWINCH, sigwinch);
if (no_screen_refresh == 0)
while (1) {
int i;
int cnt;
- char ibuf[128];
+ char c;
void sample_sc();
for (i = 0; i < (10 * delay) && newLINES == 0; i++) {
if (no_screen_refresh == 0) {
- if ((cnt = read(0, &ibuf, 128)) > 0) {
- int n;
-
- for (n = 0; n < cnt; n++)
- if (ibuf[n] == 'q')
- leave();
- reset_counters();
- break;
- }
+ if ((c = getch()) != ERR && (char)c == 'q')
+ leave();
+ if (c != ERR)
+ reset_counters();
} else
usleep(100000);
sample_sc();
(void)sort_scalls();
if (newLINES) {
- initscr();
+ /*
+ No need to check for initscr error return.
+ We won't get here if it fails on the first call.
+ */
+ endwin();
clear();
refresh();
char *p1, *p2, *p3;
char tbuf[256];
int clen;
+ int plen;
int n, i, rows;
long curr_time;
long elapsed_secs;
printf("\n");
if (num_of_threads) {
- sprintf(tbuf, "\nCURRENT_TYPE LAST_PATHNAME_WAITED_FOR CUR_WAIT_TIME THRD# PRI\n");
+ sprintf(tbuf, "\nCURRENT_TYPE LAST_PATHNAME_WAITED_FOR CUR_WAIT_TIME THRD# PRI\n");
if (tbuf[COLS-2] != '\n') {
tbuf[COLS-1] = '\n';
for (i = 0; i < num_of_threads; i++, ti++) {
struct entry *te;
- unsigned long long now;
- AbsoluteTime timestamp;
+ uint64_t now;
int secs, time_secs, time_usecs;
- clock_get_uptime(×tamp);
-
- now = (((unsigned long long)timestamp.hi) << 32) |
- (unsigned long long)((unsigned int)(timestamp.lo));
+ now = mach_absolute_time();
while (ti->thread == 0 && ti < &th_state[MAX_THREADS])
ti++;
}
clen = strlen(tbuf);
- sprintf(&tbuf[clen], " %-28.28s ", ti->pathname);
+ /* print the tail end of the pathname */
+ plen = strlen(ti->pathname);
+ if (plen > 34)
+ plen -= 34;
+ else
+ plen = 0;
+ sprintf(&tbuf[clen], " %-34.34s ", &ti->pathname[plen]);
clen += strlen(&tbuf[clen]);
print_time(&tbuf[clen], time_usecs, time_secs);
clen += strlen(&tbuf[clen]);
- sprintf(&tbuf[clen], " %2d %3d\n", i, ti->curpri);
+ sprintf(&tbuf[clen], " %2d %3d\n", i, ti->curpri);
if (tbuf[COLS-2] != '\n') {
tbuf[COLS-1] = '\n';
struct th_info *ti;
struct sc_entry *se;
struct entry *te;
- unsigned long long now;
- AbsoluteTime timestamp;
+ uint64_t now;
- clock_get_uptime(×tamp);
-
- now = (((unsigned long long)timestamp.hi) << 32) |
- (unsigned long long)((unsigned int)(timestamp.lo));
+ now = mach_absolute_time();
for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
if (ti->thread == 0)
if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) {
ti->thread = 0;
ti->vfslookup = 0;
+ ti->pathptr = (long *)0;
ti->pathname[0] = 0;
num_of_threads--;
}
th_state[i].depth = 0;
th_state[i].thread = 0;
th_state[i].vfslookup = 0;
+ th_state[i].pathptr = (long *)0;
th_state[i].pathname[0] = 0;
}
num_of_threads = 0;
for (i = 0; i < count; i++) {
int debugid, baseid, thread;
int type, code;
- unsigned long long now;
+ uint64_t now;
struct th_info *ti, *switched_out, *switched_in;
struct sc_entry *se;
struct entry *te;
switched_out = (struct th_info *)0;
switched_in = (struct th_info *)0;
- now = (((unsigned long long)kd[i].timestamp.tv_sec) << 32) |
- (unsigned long long)((unsigned int)(kd[i].timestamp.tv_nsec));
+ now = (((uint64_t)kd[i].timestamp.tv_sec) << 32) |
+ (uint64_t)((unsigned int)(kd[i].timestamp.tv_nsec));
baseid = debugid & 0xffff0000;
- if (debugid == vfs_lookup) {
+ if (type == vfs_lookup) {
long *sargptr;
if ((ti = find_thread(thread)) == (struct th_info *)0)
continue;
+
if (ti->vfslookup == 1) {
- ti->vfslookup = 2;
- memset(&ti->pathname[0], 0, 32);
- sargptr = (long *)&ti->pathname[0];
-
+ ti->vfslookup++;
+ memset(&ti->pathname[0], 0, (PATHLENGTH + 1));
+ sargptr = (long *)&ti->pathname[0];
+
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
*sargptr++ = kd[i].arg4;
+ ti->pathptr = sargptr;
+
+ } else if (ti->vfslookup > 1) {
+ ti->vfslookup++;
+ sargptr = ti->pathptr;
+
+ /*
+ We don't want to overrun our pathname buffer if the
+ kernel sends us more VFS_LOOKUP entries than we can
+ handle.
+ */
+
+ if ((long *)sargptr >= (long *)&ti->pathname[PATHLENGTH])
+ continue;
+
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (debugid & DBG_FUNC_START)
+ {
+ (long *)ti->pathptr = (long *)&ti->pathname[PATHLENGTH];
+ continue;
+ }
- } else if (ti->vfslookup == 2) {
- ti->vfslookup = 3;
-
- sargptr = (long *)&ti->pathname[12];
*sargptr++ = kd[i].arg1;
*sargptr++ = kd[i].arg2;
*sargptr++ = kd[i].arg3;
*sargptr++ = kd[i].arg4;
+ ti->pathptr = sargptr;
}
continue;
se->delta_count++;
se->total_count++;
- if (ti->depth) {
+ while (ti->depth) {
te = &ti->th_entry[ti->depth-1];
if (te->type == type) {
te->stime = (double)now;
te->otime = (double)now;
+
+ break;
+ }
+ ti->depth--;
+
+ if (ti->depth == 0) {
+ /*
+ * headed back to user mode
+ * start the time accumulation
+ */
+ te = &ti->th_entry[0];
+ te->sc_state = USER_MODE;
+ te->stime = (double)now;
+ te->otime = (double)now;
}
}
}
exit(1);
}
-
void getdivisor()
{
+ mach_timebase_info_data_t info;
- unsigned int delta;
- unsigned int abs_to_ns_num;
- unsigned int abs_to_ns_denom;
- unsigned int proc_to_abs_num;
- unsigned int proc_to_abs_denom;
+ (void) mach_timebase_info (&info);
- MKGetTimeBaseInfo (&delta, &abs_to_ns_num, &abs_to_ns_denom,
- &proc_to_abs_num, &proc_to_abs_denom);
+ divisor = ( (double)info.denom / (double)info.numer) * 1000;
- divisor = ((double)abs_to_ns_denom / (double)abs_to_ns_num) * 1000;
}