2 * Copyright (C) 1996 Be, Inc.
5 * This source code was published by Be, Inc. in the file gnu_x86.tar.gz for R3,
6 * a mirror is at http://linux.inf.elte.hu/ftp/beos/development/gnu/r3.0/
7 * needs to link to termcap.
8 * The GPL should apply here, since AFAIK termcap is GPLed.
12 * Top -- a program for finding the top cpu-eating threads
25 static const char IDLE_NAME
[] = "idle thread ";
26 static bigtime_t lastMeasure
= 0;
29 * Keeps track of a single thread's times
34 bigtime_t kernel_time
;
36 bigtime_t
total_time() const {
37 return user_time
+ kernel_time
;
40 bool operator< (const ThreadTime
& other
) const {
41 return total_time() > other
.total_time();
46 * Keeps track of all the threads' times
48 typedef std::list
<ThreadTime
> ThreadTimeList
;
51 static char *clear_string
; /*output string for clearing the screen */
52 static char *enter_ca_mode
; /* output string for switching screen buffer */
53 static char *exit_ca_mode
; /* output string for releasing screen buffer */
54 static char *cursor_home
; /* Places cursor back to (1,1) */
55 static char *restore_cursor
;
56 static char *save_cursor
;
57 static int columns
; /* Columns on screen */
58 static int rows
; /* how many rows on the screen */
59 static int screen_size_changed
= 0; /* tells to refresh the screen size */
60 static int cpus
; /* how many cpus we are runing on */
62 /* SIGWINCH handler */
64 winch_handler(int notused
)
67 screen_size_changed
= 1;
76 printf(restore_cursor
);
84 static char buf
[2048];
85 char *entries
= &buf
[0];
87 tgetent(buf
, getenv("TERM"));
88 exit_ca_mode
= tgetstr("te", &entries
);
89 enter_ca_mode
= tgetstr("ti", &entries
);
90 cursor_home
= tgetstr("ho", &entries
);
91 clear_string
= tgetstr("cl", &entries
);
92 restore_cursor
= tgetstr("rc", &entries
);
93 save_cursor
= tgetstr("sc", &entries
);
96 printf(enter_ca_mode
);
102 * Calculate the cpu percentage used by a given thread
103 * Remember: for multiple CPUs, multiply the interval by # cpus
107 cpu_perc(bigtime_t spent
, bigtime_t interval
)
109 return ((100.0 * spent
) / (cpus
* interval
));
114 * Compare an old snapshot with the new one
119 ThreadTimeList
*newList
,
126 ThreadTimeList times
;
141 * First, merge both old and new lists, computing the differences in time
142 * Threads in only one list are dropped.
143 * Threads with no elapsed time are dropped too.
148 ThreadTimeList::iterator it
;
149 ThreadTimeList::iterator itOld
;
152 for (it
= newList
->begin(); it
!= newList
->end(); it
++) {
155 for (itOld
= old
->begin(); itOld
!= old
->end(); itOld
++) {
156 if (itOld
->thid
!= it
->thid
) {
160 oldtime
= itOld
->total_time();
161 newtime
= it
->total_time();
162 if (oldtime
== newtime
) {
166 entry
.thid
= it
->thid
;
167 entry
.user_time
= (it
->user_time
- itOld
->user_time
);
168 entry
.kernel_time
= (it
->kernel_time
- itOld
->kernel_time
);
171 entry
.thid
= it
->thid
;
172 entry
.user_time
= it
->user_time
;
173 entry
.kernel_time
= it
->kernel_time
;
176 times
.push_back(entry
);
178 total
= entry
.total_time();
180 utotal
+= entry
.user_time
;
181 ktotal
+= entry
.kernel_time
;
186 * Sort what we found and print
190 printf("%6s %7s %7s %7s %4s %16s %-16s \n", "THID", "TOTAL", "USER", "KERNEL",
191 "%CPU", "TEAM NAME", "THREAD NAME");
197 for (it
= times
.begin(); it
!= times
.end(); it
++) {
199 if (get_thread_info(it
->thid
, &t
) < B_NO_ERROR
) {
200 strcpy(t
.name
, "(unknown)");
201 strcpy(tm
.args
, "(unknown)");
203 if (strncmp(t
.name
, IDLE_NAME
, strlen(IDLE_NAME
)) == 0) {
206 if (get_team_info(t
.team
, &tm
) < B_NO_ERROR
) {
207 strcpy(tm
.args
, "(unknown)");
209 if ((p
= strrchr(tm
.args
, '/'))) {
210 strcpy(tm
.args
, p
+ 1);
219 else if (columns
- 64 < sizeof(t
.name
))
220 t
.name
[columns
- 64] = 0;
222 total
= it
->total_time();
227 ktotal
+= it
->kernel_time
;
228 utotal
+= it
->user_time
;
230 if (!ignore
&& (!refresh
|| (linecount
< (rows
- 1)))) {
232 printf("%6ld %7.2f %7.2f %7.2f %4.1f %16s %s \n",
235 (double)(it
->user_time
/ 1000),
236 (double)(it
->kernel_time
/ 1000),
237 cpu_perc(total
, uinterval
),
244 printf("------ %7.2f %7.2f %7.2f %4.1f%% TOTAL (%4.1f%% idle time, %4.1f%% unknown)",
245 (double) (gtotal
/ 1000),
246 (double) (utotal
/ 1000),
247 (double) (ktotal
/ 1000),
248 cpu_perc(gtotal
, uinterval
),
249 cpu_perc(idletime
, uinterval
),
250 cpu_perc(cpus
* uinterval
- (gtotal
+ idletime
), uinterval
));
252 printf(clear_string
);
258 adjust_term(bool onlyRows
)
262 if (ioctl(1, TIOCGWINSZ
, &ws
) < 0) {
265 if (ws
.ws_row
<= 0) {
278 * Gather up thread data since previous run
280 static ThreadTimeList
281 gather(ThreadTimeList
*old
, int refresh
)
287 ThreadTimeList times
;
288 bigtime_t oldLastMeasure
;
291 oldLastMeasure
= lastMeasure
;
292 lastMeasure
= system_time();
294 while (get_next_team_info(&tmcookie
, &tm
) == B_NO_ERROR
) {
296 while (get_next_thread_info(tm
.team
, &thcookie
, &t
) == B_NO_ERROR
) {
298 entry
.thid
= t
.thread
;
299 entry
.user_time
= t
.user_time
;
300 entry
.kernel_time
= t
.kernel_time
;
301 times
.push_back(entry
);
305 if (screen_size_changed
) {
307 screen_size_changed
= 0;
309 compare(old
, ×
, system_time() - oldLastMeasure
, refresh
);
317 * print usage message and exit
320 usage(const char *myname
)
322 fprintf(stderr
, "usage: %s [-d] [-i interval] [-n ntimes]\n", myname
);
324 " -d, do not clear the screen between displays\n");
326 " -i interval, wait `interval' seconds before displaying\n");
328 " -n ntimes, display `ntimes' times before exiting\n");
329 fprintf(stderr
, "Default is clear screen, interval=5, ntimes=infinite\n");
335 main(int argc
, char **argv
)
337 ThreadTimeList baseline
;
347 get_system_info (&sysinfo
);
348 cpus
= sysinfo
.cpu_count
;
351 for (argc
--, argv
++; argc
> 0 && **argv
== '-'; argc
--, argv
++) {
352 if (strcmp(argv
[0], "-i") == 0) {
357 interval
= atoi(argv
[0]);
358 } else if (strcmp(argv
[0], "-n") == 0) {
363 iters
= atoi(argv
[0]);
364 } else if (strcmp(argv
[0], "-d") == 0) {
377 if (!adjust_term(false)) {
382 printf("Starting: %d interval%s of %d second%s each\n", iters
,
383 (iters
== 1) ? "" : "s", interval
,
384 (interval
== 1) ? "" : "s");
387 signal(SIGWINCH
, winch_handler
);
388 signal(SIGINT
, sigint_handler
);
390 lastMeasure
= system_time();
392 // You will only have to wait half a second for the first iteration.
393 uinterval
= 1 * 1000000 / 2;
394 baseline
= gather(NULL
, refresh
);
395 elapsed
= system_time() - lastMeasure
;
396 if (elapsed
< uinterval
)
397 snooze(uinterval
- elapsed
);
398 // then = system_time();
399 baseline
= gather(&baseline
, refresh
);
402 baseline
= gather(NULL
, refresh
);
404 uinterval
= interval
* 1000000;
405 for (i
= 0; iters
< 0 || i
< iters
; i
++) {
406 elapsed
= system_time() - lastMeasure
;
407 if (elapsed
< uinterval
)
408 snooze(uinterval
- elapsed
);
409 baseline
= gather(&baseline
, refresh
);
412 printf(exit_ca_mode
);
413 printf(restore_cursor
);