Found top.c in some public source from R3... that's the original one,
with a pointer to a mirror. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6391 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
df6c2e833f
commit
837c5110d1
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* Copyright (C) 1996 Be, Inc.
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This source code was published by Be, Inc. in the file gnu_x86.tar.gz for R3,
|
||||
* a mirror is at http://linux.inf.elte.hu/ftp/beos/development/gnu/r3.0/
|
||||
* needs to link to termcap.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Top -- a program for finding the top cpu-eating threads
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <OS.h>
|
||||
#include <termcap.h>
|
||||
#include <termios.h>
|
||||
|
||||
static const char IDLE_NAME[] = "idle thread ";
|
||||
|
||||
/*
|
||||
* Keeps track of a single thread's times
|
||||
*/
|
||||
typedef struct {
|
||||
thread_id thid;
|
||||
bigtime_t user_time;
|
||||
bigtime_t kernel_time;
|
||||
} thread_times_t;
|
||||
|
||||
/*
|
||||
* Keeps track of all the threads' times
|
||||
*/
|
||||
typedef struct {
|
||||
int nthreads;
|
||||
int maxthreads;
|
||||
thread_times_t *thread_times;
|
||||
} thread_time_list_t;
|
||||
|
||||
|
||||
#define FREELIST_SIZE 3
|
||||
static thread_time_list_t freelist[FREELIST_SIZE];
|
||||
|
||||
static char *clear_string; /* output string for clearing the screen */
|
||||
static int rows; /* how many rows on the screen */
|
||||
static int cpus; /* how many cpus we are runing on */
|
||||
|
||||
/*
|
||||
* Grow the list to add just one more entry
|
||||
*/
|
||||
void
|
||||
grow(
|
||||
thread_time_list_t *times
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (times->nthreads == times->maxthreads) {
|
||||
times->thread_times = realloc(times->thread_times,
|
||||
(sizeof(times->thread_times[0]) *
|
||||
(times->nthreads + 1)));
|
||||
times->maxthreads = times->nthreads + 1;
|
||||
}
|
||||
i = times->nthreads;
|
||||
times->thread_times[i].thid = -1;
|
||||
times->thread_times[i].user_time = 0;
|
||||
times->thread_times[i].kernel_time = 0;
|
||||
times->nthreads++;
|
||||
}
|
||||
|
||||
void
|
||||
init_times(
|
||||
thread_time_list_t *times
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FREELIST_SIZE; i++) {
|
||||
if (freelist[i].nthreads == 0) {
|
||||
*times = freelist[i];
|
||||
freelist[i].nthreads = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "This can't happen\n");
|
||||
}
|
||||
|
||||
void
|
||||
free_times(
|
||||
thread_time_list_t *times
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < FREELIST_SIZE; i++) {
|
||||
if (freelist[i].nthreads == 1) {
|
||||
freelist[i] = *times;
|
||||
freelist[i].nthreads = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "This can't happen\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two thread snapshots (for qsort)
|
||||
*/
|
||||
int
|
||||
comparetime(
|
||||
const void *a,
|
||||
const void *b
|
||||
)
|
||||
{
|
||||
thread_times_t *ta = (thread_times_t *)a;
|
||||
thread_times_t *tb = (thread_times_t *)b;
|
||||
|
||||
return ((tb->user_time + tb->kernel_time) -
|
||||
(ta->user_time + ta->kernel_time));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the cpu percentage used by a given thread
|
||||
* Remember: for multiple CPUs, multiply the interval by # cpus
|
||||
* when calculating
|
||||
*/
|
||||
float
|
||||
cpu_perc(
|
||||
bigtime_t spent,
|
||||
bigtime_t interval
|
||||
)
|
||||
{
|
||||
return ((100.0 * spent) / (cpus * interval));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the screen
|
||||
*/
|
||||
void
|
||||
clear(void)
|
||||
{
|
||||
if (clear_string) {
|
||||
printf(clear_string);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare an old snapshot with the new one
|
||||
*/
|
||||
void
|
||||
compare(
|
||||
thread_time_list_t *old,
|
||||
thread_time_list_t *new,
|
||||
bigtime_t old_busy,
|
||||
bigtime_t new_busy,
|
||||
bigtime_t uinterval,
|
||||
int refresh
|
||||
)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
bigtime_t oldtime;
|
||||
bigtime_t newtime;
|
||||
thread_time_list_t times;
|
||||
thread_info t;
|
||||
team_info tm;
|
||||
bigtime_t total;
|
||||
bigtime_t utotal;
|
||||
bigtime_t ktotal;
|
||||
bigtime_t gtotal;
|
||||
bigtime_t idletime;
|
||||
thread_times_t ttime;
|
||||
int newthread;
|
||||
int ignore;
|
||||
int linecount;
|
||||
system_info info;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* First, merge both old and new lists, computing the differences in time
|
||||
* Threads in only one list are dropped.
|
||||
* Threads with no elapsed time are dropped too.
|
||||
*/
|
||||
init_times(×);
|
||||
k = 0;
|
||||
gtotal = 0;
|
||||
utotal = 0;
|
||||
ktotal = 0;
|
||||
for (j = 0; j < new->nthreads; j++) {
|
||||
newthread = 1;
|
||||
ignore = 0;
|
||||
for (i = 0; i < old->nthreads; i++) {
|
||||
if (old->thread_times[i].thid != new->thread_times[j].thid) {
|
||||
continue;
|
||||
}
|
||||
newthread = 0;
|
||||
oldtime = (old->thread_times[i].user_time +
|
||||
old->thread_times[i].kernel_time);
|
||||
newtime = (new->thread_times[j].user_time +
|
||||
new->thread_times[j].kernel_time);
|
||||
if (oldtime == newtime) {
|
||||
ignore = 1;
|
||||
break;
|
||||
}
|
||||
grow(×);
|
||||
times.thread_times[k].thid = new->thread_times[j].thid;
|
||||
times.thread_times[k].user_time = (new->thread_times[j].user_time -
|
||||
old->thread_times[i].user_time);
|
||||
times.thread_times[k].kernel_time = (new->thread_times[j].kernel_time -
|
||||
old->thread_times[i].kernel_time);
|
||||
}
|
||||
if (newthread) {
|
||||
grow(×);
|
||||
times.thread_times[k].thid = new->thread_times[j].thid;
|
||||
times.thread_times[k].user_time = new->thread_times[j].user_time;
|
||||
times.thread_times[k].kernel_time = new->thread_times[j].kernel_time;
|
||||
}
|
||||
if (!ignore) {
|
||||
total = (times.thread_times[k].user_time +
|
||||
times.thread_times[k].kernel_time);
|
||||
gtotal += total;
|
||||
utotal += times.thread_times[k].user_time;
|
||||
ktotal += times.thread_times[k].kernel_time;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort what we found and print
|
||||
*/
|
||||
qsort(times.thread_times, times.nthreads,
|
||||
sizeof(times.thread_times[0]), comparetime);
|
||||
|
||||
if (refresh) {
|
||||
clear();
|
||||
}
|
||||
printf("%6s %7s %7s %7s %4s %16s %16s\n", "thid", "total", "user", "kernel",
|
||||
"%cpu", "team name", "thread name");
|
||||
linecount = 1;
|
||||
idletime = new_busy - old_busy;
|
||||
gtotal = 0;
|
||||
ktotal = 0;
|
||||
utotal = 0;
|
||||
for (i = 0; i < times.nthreads; i++) {
|
||||
ignore = 0;
|
||||
if (get_thread_info(times.thread_times[i].thid,
|
||||
&t) < B_NO_ERROR) {
|
||||
strcpy(t.name, "(unknown)");
|
||||
strcpy(tm.args, "(unknown)");
|
||||
} else {
|
||||
if (strncmp(t.name, IDLE_NAME, strlen(IDLE_NAME)) == 0) {
|
||||
ignore++;
|
||||
}
|
||||
if (get_team_info(t.team, &tm) < B_NO_ERROR) {
|
||||
strcpy(tm.args, "(unknown)");
|
||||
} else {
|
||||
if (p = strrchr(tm.args, '/')) {
|
||||
strcpy(tm.args, p + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tm.args[16] = 0;
|
||||
t.name[16] = 0;
|
||||
total = (times.thread_times[i].user_time +
|
||||
times.thread_times[i].kernel_time);
|
||||
if (ignore) {
|
||||
idletime += total;
|
||||
} else {
|
||||
gtotal += total;
|
||||
ktotal += times.thread_times[i].kernel_time;
|
||||
utotal += times.thread_times[i].user_time;
|
||||
}
|
||||
if (!ignore && (!refresh || (linecount < (rows - 1)))) {
|
||||
|
||||
printf("%6d %7.2f %7.2f %7.2f %4.1f %16s %16s\n",
|
||||
times.thread_times[i].thid,
|
||||
total / 1000.0,
|
||||
(double)(times.thread_times[i].user_time / 1000),
|
||||
(double)(times.thread_times[i].kernel_time / 1000),
|
||||
cpu_perc(total, uinterval),
|
||||
tm.args,
|
||||
t.name);
|
||||
linecount++;
|
||||
}
|
||||
}
|
||||
free_times(×);
|
||||
printf("------ %7.2f %7.2f %7.2f %4.1f%% TOTAL (%4.1f%% idle time, %4.1f%% unknown)",
|
||||
(double)(gtotal / 1000),
|
||||
(double) (utotal / 1000),
|
||||
(double) (ktotal / 1000),
|
||||
cpu_perc(gtotal, uinterval),
|
||||
cpu_perc(idletime, uinterval),
|
||||
cpu_perc(cpus * uinterval - (gtotal + idletime), uinterval));
|
||||
fflush(stdout);
|
||||
if (!refresh) {
|
||||
printf("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
setup_term(void)
|
||||
{
|
||||
char *term;
|
||||
char *str;
|
||||
char buf[2048];
|
||||
char *entries;
|
||||
struct winsize ws;
|
||||
|
||||
if (ioctl(1, TIOCGWINSZ, &ws) < 0) {
|
||||
return (0);
|
||||
}
|
||||
if (ws.ws_row <= 0) {
|
||||
return (0);
|
||||
}
|
||||
rows = ws.ws_row;
|
||||
term = getenv("TERM");
|
||||
if (term == NULL) {
|
||||
return (0);
|
||||
}
|
||||
if (tgetent(buf, term) <= 0) {
|
||||
return (0);
|
||||
}
|
||||
entries = &buf[0];
|
||||
str = tgetstr("cl", &entries);
|
||||
if (str == NULL) {
|
||||
return (0);
|
||||
}
|
||||
clear_string = strdup(str);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gather up thread data for uinterval microseconds
|
||||
*/
|
||||
thread_time_list_t
|
||||
gather(
|
||||
thread_time_list_t *old,
|
||||
bigtime_t *busy_wait_time,
|
||||
bigtime_t uinterval,
|
||||
int refresh
|
||||
)
|
||||
{
|
||||
int32 tmcookie;
|
||||
int32 thcookie;
|
||||
thread_info t;
|
||||
team_info tm;
|
||||
thread_time_list_t times;
|
||||
bigtime_t old_busy;
|
||||
int i;
|
||||
system_info info;
|
||||
|
||||
i = 0;
|
||||
init_times(×);
|
||||
tmcookie = 0;
|
||||
while (get_next_team_info(&tmcookie, &tm) == B_NO_ERROR) {
|
||||
thcookie = 0;
|
||||
while (get_next_thread_info(tm.team, &thcookie, &t) == B_NO_ERROR) {
|
||||
grow(×);
|
||||
times.thread_times[i].thid = t.thread;
|
||||
times.thread_times[i].user_time = t.user_time;
|
||||
times.thread_times[i].kernel_time = t.kernel_time;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
get_system_info(&info);
|
||||
old_busy = *busy_wait_time;
|
||||
*busy_wait_time = info._busy_wait_time;
|
||||
if (old != NULL) {
|
||||
compare(old, ×, old_busy, *busy_wait_time, uinterval, refresh);
|
||||
free_times(old);
|
||||
}
|
||||
return (times);
|
||||
}
|
||||
|
||||
/*
|
||||
* print usage message and exit
|
||||
*/
|
||||
void
|
||||
usage(const char *myname)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-d] [-i interval] [-n ntimes]\n", myname);
|
||||
fprintf(stderr,
|
||||
" -d, do not clear the screen between displays\n");
|
||||
fprintf(stderr,
|
||||
" -i interval, wait `interval' seconds before displaying\n");
|
||||
fprintf(stderr,
|
||||
" -n ntimes, display `ntimes' times before exiting\n");
|
||||
fprintf(stderr, "Default is clear screen, interval=5, ntimes=infinite\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
thread_time_list_t baseline;
|
||||
int i;
|
||||
int iters = -1;
|
||||
int interval = 5;
|
||||
int refresh = 1;
|
||||
system_info sysinfo;
|
||||
bigtime_t now;
|
||||
bigtime_t then;
|
||||
bigtime_t uinterval;
|
||||
bigtime_t elapsed;
|
||||
bigtime_t busy;
|
||||
char *myname;
|
||||
|
||||
get_system_info (&sysinfo);
|
||||
cpus = sysinfo.cpu_count;
|
||||
|
||||
myname = argv[0];
|
||||
for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
|
||||
if (strcmp(argv[0], "-i") == 0) {
|
||||
argc--, argv++;
|
||||
if (argc == 0) {
|
||||
usage(myname);
|
||||
}
|
||||
interval = atoi(argv[0]);
|
||||
} else if (strcmp(argv[0], "-n") == 0) {
|
||||
argc--, argv++;
|
||||
if (argc == 0) {
|
||||
usage(myname);
|
||||
}
|
||||
iters = atoi(argv[0]);
|
||||
} else if (strcmp(argv[0], "-d") == 0) {
|
||||
refresh = 0;
|
||||
} else {
|
||||
usage(myname);
|
||||
}
|
||||
}
|
||||
if (argc) {
|
||||
usage(myname);
|
||||
}
|
||||
if (refresh) {
|
||||
if (!setup_term()) {
|
||||
refresh = 0;
|
||||
}
|
||||
}
|
||||
if (iters < 0) {
|
||||
printf("Starting: infinite intervals of %d second%s each\n",
|
||||
interval,
|
||||
(interval == 1) ? "" : "s");
|
||||
} else {
|
||||
printf("Starting: %d interval%s of %d second%s each\n", iters,
|
||||
(iters == 1) ? "" : "s", interval,
|
||||
(interval == 1) ? "" : "s");
|
||||
}
|
||||
then = system_time();
|
||||
uinterval = interval * 1000000;
|
||||
baseline = gather(NULL, &busy, 0, refresh);
|
||||
for (i = 0; iters < 0 || i < iters; i++) {
|
||||
elapsed = system_time() - then;
|
||||
if (elapsed < uinterval) {
|
||||
snooze(uinterval - elapsed);
|
||||
elapsed = uinterval;
|
||||
}
|
||||
then = system_time();
|
||||
baseline = gather(&baseline, &busy, elapsed, refresh);
|
||||
}
|
||||
exit(0);
|
||||
}
|
Loading…
Reference in New Issue