2 /* Author: Ben Gras <beng@few.vu.nl> 17 march 2006 */
3 /* Modified for ProcFS by Alen Stojanov and David van Moolenbroek */
7 #define _POSIX_SOURCE 1
27 #include <sys/ioc_tty.h>
28 #include <sys/times.h>
29 #include <sys/types.h>
31 #include <sys/select.h>
33 #include <minix/com.h>
34 #include <minix/config.h>
35 #include <minix/type.h>
36 #include <minix/endpoint.h>
37 #include <minix/const.h>
38 #include <minix/u64.h>
40 #include <minix/procfs.h>
42 #define TIMECYCLEKEY 't'
46 #define ORDER_MEMORY 1
47 #define ORDER_HIGHEST ORDER_MEMORY
48 int order
= ORDER_CPU
;
52 /* name of cpu cycle types, in the order they appear in /psinfo. */
53 char *cputimenames
[] = { "user", "ipc", "kernelcall" };
55 #define CPUTIMENAMES (sizeof(cputimenames)/sizeof(cputimenames[0]))
57 #define CPUTIME(m, i) (m & (1L << (i)))
59 unsigned int nr_procs
, nr_tasks
;
62 #define SLOT_NR(e) (_ENDPOINT_P(e) + nr_tasks)
64 #define TC_BUFFER 1024 /* Size of termcap(3) buffer */
65 #define TC_STRINGS 200 /* Enough room for cm,cl,so,se */
69 int blockedverbose
= 0;
78 endpoint_t p_endpoint
;
80 u64_t p_cpucycles
[CPUTIMENAMES
];
87 char p_name
[PROC_NAME_LEN
+1];
90 struct proc
*proc
= NULL
, *prev_proc
= NULL
;
92 void parse_file(pid_t pid
)
94 char path
[PATH_MAX
], name
[256], type
, state
;
95 int version
, endpt
, effuid
;
96 unsigned long cycles_hi
, cycles_lo
;
102 sprintf(path
, "%d/psinfo", pid
);
104 if ((fp
= fopen(path
, "r")) == NULL
)
107 if (fscanf(fp
, "%d", &version
) != 1) {
112 if (version
!= PSINFO_VERSION
) {
113 fputs("procfs version mismatch!\n", stderr
);
117 if (fscanf(fp
, " %c %d", &type
, &endpt
) != 2) {
122 slot
= SLOT_NR(endpt
);
124 if(slot
< 0 || slot
>= nr_total
) {
125 fprintf(stderr
, "top: unreasonable endpoint number %d\n", endpt
);
132 if (type
== TYPE_TASK
)
133 p
->p_flags
|= IS_TASK
;
134 else if (type
== TYPE_SYSTEM
)
135 p
->p_flags
|= IS_SYSTEM
;
137 p
->p_endpoint
= endpt
;
140 if (fscanf(fp
, " %255s %c %d %d %lu %*u %lu %lu",
141 name
, &state
, &p
->p_blocked
, &p
->p_priority
,
142 &p
->p_user_time
, &cycles_hi
, &cycles_lo
) != 7) {
148 strncpy(p
->p_name
, name
, sizeof(p
->p_name
)-1);
149 p
->p_name
[sizeof(p
->p_name
)-1] = 0;
151 if (state
!= STATE_RUN
)
152 p
->p_flags
|= BLOCKED
;
153 p
->p_cpucycles
[0] = make64(cycles_lo
, cycles_hi
);
156 if (!(p
->p_flags
& IS_TASK
)) {
158 if ((i
=fscanf(fp
, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u",
159 &p
->p_memory
, &effuid
, &p
->p_nice
)) != 3) {
165 p
->p_effuid
= effuid
;
166 } else p
->p_effuid
= 0;
168 for(i
= 1; i
< CPUTIMENAMES
; i
++) {
169 if(fscanf(fp
, " %lu %lu",
170 &cycles_hi
, &cycles_lo
) == 2) {
171 p
->p_cpucycles
[i
] = make64(cycles_lo
, cycles_hi
);
173 p
->p_cpucycles
[i
] = 0;
177 if ((p
->p_flags
& IS_TASK
)) {
178 if(fscanf(fp
, " %lu", &p
->p_memory
) != 1) {
191 struct dirent
*p_ent
;
195 if ((p_dir
= opendir(".")) == NULL
) {
196 perror("opendir on " _PATH_PROC
);
200 for (p_ent
= readdir(p_dir
); p_ent
!= NULL
; p_ent
= readdir(p_dir
)) {
201 pid
= strtol(p_ent
->d_name
, &end
, 10);
203 if (!end
[0] && pid
!= 0)
220 proc
= malloc(nr_total
* sizeof(proc
[0]));
223 fprintf(stderr
, "Out of memory!\n");
228 for (i
= 0; i
< nr_total
; i
++)
234 int print_memory(void)
237 unsigned int pagesize
;
238 unsigned long total
, free
, largest
, cached
;
240 if ((fp
= fopen("meminfo", "r")) == NULL
)
243 if (fscanf(fp
, "%u %lu %lu %lu %lu", &pagesize
, &total
, &free
,
244 &largest
, &cached
) != 5) {
251 printf("main memory: %ldK total, %ldK free, %ldK contig free, "
253 (pagesize
* total
)/1024, (pagesize
* free
)/1024,
254 (pagesize
* largest
)/1024, (pagesize
* cached
)/1024);
259 int print_load(double *loads
, int nloads
)
262 printf("load averages: ");
263 for(i
= 0; i
< nloads
; i
++)
264 printf("%s %.2f", (i
> 0) ? "," : "", loads
[i
]);
269 int print_proc_summary(struct proc
*proc
)
271 int p
, alive
, running
, sleeping
;
273 alive
= running
= sleeping
= 0;
275 for(p
= 0; p
< nr_total
; p
++) {
276 if (proc
[p
].p_endpoint
== IDLE
)
278 if(!(proc
[p
].p_flags
& USED
))
281 if(proc
[p
].p_flags
& BLOCKED
)
286 printf("%d processes: %d running, %d sleeping\n",
287 alive
, running
, sleeping
);
296 int cmp_procs(const void *v1
, const void *v2
)
298 struct tp
*p1
= (struct tp
*) v1
, *p2
= (struct tp
*) v2
;
299 int p1blocked
, p2blocked
;
301 if(order
== ORDER_MEMORY
) {
302 if(p1
->p
->p_memory
< p2
->p
->p_memory
) return 1;
303 if(p1
->p
->p_memory
> p2
->p
->p_memory
) return -1;
307 p1blocked
= !!(p1
->p
->p_flags
& BLOCKED
);
308 p2blocked
= !!(p2
->p
->p_flags
& BLOCKED
);
310 /* Primarily order by used number of cpu cycles.
312 * Exception: if in blockedverbose mode, a blocked
313 * process is always printed after an unblocked
314 * process, and used cpu cycles don't matter.
316 * In both cases, process slot number is a tie breaker.
319 if(blockedverbose
&& (p1blocked
|| p2blocked
)) {
320 if(!p1blocked
&& p2blocked
)
322 if(!p2blocked
&& p1blocked
)
324 } else if(p1
->ticks
!= p2
->ticks
) {
325 return (p2
->ticks
- p1
->ticks
);
328 /* Process slot number is a tie breaker. */
329 return (int) (p1
->p
- p2
->p
);
332 struct tp
*lookup(endpoint_t who
, struct tp
*tptab
, int np
)
336 for(t
= 0; t
< np
; t
++)
337 if(who
== tptab
[t
].p
->p_endpoint
)
340 fprintf(stderr
, "lookup: tp %d (0x%x) not found.\n", who
, who
);
348 void print_proc(struct tp
*tp
, u64_t total_ticks
)
351 static struct passwd
*who
= NULL
;
352 static int last_who
= -1;
355 struct proc
*pr
= tp
->p
;
357 printf("%5d ", pr
->p_pid
);
361 if(last_who
!= euid
|| !who
) {
362 who
= getpwuid(euid
);
366 if(who
&& who
->pw_name
) printf("%-8s ", who
->pw_name
);
367 else if(!(pr
->p_flags
& IS_TASK
)) printf("%8d ", pr
->p_effuid
);
370 printf(" %2d ", pr
->p_priority
);
371 if(!(pr
->p_flags
& IS_TASK
)) {
372 printf(" %3d ", pr
->p_nice
);
374 printf("%6ldK", (pr
->p_memory
+ 512) / 1024);
375 printf("%6s", (pr
->p_flags
& BLOCKED
) ? "" : "RUN");
376 ticks
= pr
->p_user_time
;
377 printf(" %3u:%02u ", (ticks
/system_hz
/60), (ticks
/system_hz
)%60);
379 printf("%6.2f%% %s", 100.0 * tp
->ticks
/ total_ticks
, name
);
382 char *cputimemodename(int cputimemode
)
384 static char name
[100];
389 for(i
= 0; i
< CPUTIMENAMES
; i
++) {
390 if(CPUTIME(cputimemode
, i
)) {
391 assert(strlen(name
) +
392 strlen(cputimenames
[i
]) < sizeof(name
));
393 strcat(name
, cputimenames
[i
]);
401 u64_t
cputicks(struct proc
*p1
, struct proc
*p2
, int timemode
)
405 for(i
= 0; i
< CPUTIMENAMES
; i
++) {
406 if(!CPUTIME(timemode
, i
))
408 if(p1
->p_endpoint
== p2
->p_endpoint
) {
409 t
= t
+ p2
->p_cpucycles
[i
] - p1
->p_cpucycles
[i
];
411 t
= t
+ p2
->p_cpucycles
[i
];
418 char *ordername(int orderno
)
421 case ORDER_CPU
: return "cpu";
422 case ORDER_MEMORY
: return "memory";
424 return "invalid order";
427 void print_procs(int maxlines
,
428 struct proc
*proc1
, struct proc
*proc2
, int cputimemode
)
432 u64_t kernelticks
= 0;
433 u64_t systemticks
= 0;
435 u64_t total_ticks
= 0;
437 static struct tp
*tick_procs
= NULL
;
439 if (tick_procs
== NULL
) {
440 tick_procs
= malloc(nr_total
* sizeof(tick_procs
[0]));
442 if (tick_procs
== NULL
) {
443 fprintf(stderr
, "Out of memory!\n");
448 for(p
= nprocs
= 0; p
< nr_total
; p
++) {
450 if(!(proc2
[p
].p_flags
& USED
))
452 tick_procs
[nprocs
].p
= proc2
+ p
;
453 tick_procs
[nprocs
].ticks
= cputicks(&proc1
[p
], &proc2
[p
], cputimemode
);
454 uticks
= cputicks(&proc1
[p
], &proc2
[p
], 1);
455 total_ticks
= total_ticks
+ uticks
;
456 if(p
-NR_TASKS
== IDLE
) {
460 if(p
-NR_TASKS
== KERNEL
) {
461 kernelticks
= uticks
;
463 if(!(proc2
[p
].p_flags
& IS_TASK
)) {
464 if(proc2
[p
].p_flags
& IS_SYSTEM
)
465 systemticks
= systemticks
+ tick_procs
[nprocs
].ticks
;
467 userticks
= userticks
+ tick_procs
[nprocs
].ticks
;
473 if (total_ticks
== 0)
476 qsort(tick_procs
, nprocs
, sizeof(tick_procs
[0]), cmp_procs
);
478 printf("CPU states: %6.2f%% user, ", 100.0 * userticks
/ total_ticks
);
479 printf("%6.2f%% system, ", 100.0 * systemticks
/ total_ticks
);
480 printf("%6.2f%% kernel, ", 100.0 * kernelticks
/ total_ticks
);
481 printf("%6.2f%% idle", 100.0 * idleticks
/ total_ticks
);
483 #define NEWLINE do { printf("\n"); if(--maxlines <= 0) { return; } } while(0)
486 printf("CPU time displayed ('%c' to cycle): %s; ",
487 TIMECYCLEKEY
, cputimemodename(cputimemode
));
488 printf(" sort order ('%c' to cycle): %s", ORDERKEY
, ordername(order
));
493 printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND");
495 for(p
= 0; p
< nprocs
; p
++) {
499 pr
= tick_procs
[p
].p
;
501 if((pr
->p_flags
& IS_TASK
) && pr
->p_pid
!= KERNEL
) {
502 /* skip old kernel tasks as they don't run anymore */
506 /* If we're in blocked verbose mode, indicate start of
509 if(blockedverbose
&& (pr
->p_flags
& BLOCKED
) && !blockedseen
) {
511 printf("Blocked processes:");
516 print_proc(&tick_procs
[p
], total_ticks
);
522 /* Traverse dependency chain if blocked. */
523 while(pr
->p_flags
& BLOCKED
) {
524 endpoint_t dep
= NONE
;
528 if((dep
= pr
->p_blocked
) == NONE
) {
529 printf("not blocked on a process");
537 tpdep
= lookup(dep
, tick_procs
, nprocs
);
539 printf("%*s> ", level
, "");
540 print_proc(tpdep
, total_ticks
);
546 void showtop(int cputimemode
, int r
)
549 double loads
[NLOADS
];
550 int nloads
, lines
= 0;
551 struct winsize winsize
;
553 if(ioctl(STDIN_FILENO
, TIOCGWINSZ
, &winsize
) != 0) {
554 perror("TIOCGWINSZ");
555 fprintf(stderr
, "TIOCGWINSZ failed\n");
560 if (prev_proc
== NULL
)
563 if((nloads
= getloadavg(loads
, NLOADS
)) != NLOADS
) {
564 fprintf(stderr
, "getloadavg() failed - %d loads\n", nloads
);
569 printf("%s", Tclr_all
);
571 lines
+= print_load(loads
, NLOADS
);
572 lines
+= print_proc_summary(proc
);
573 lines
+= print_memory();
575 if(winsize
.ws_row
> 0) r
= winsize
.ws_row
;
577 print_procs(r
- lines
- 2, prev_proc
, proc
, cputimemode
);
584 static char buffer
[TC_BUFFER
], strings
[TC_STRINGS
];
585 char *s
= strings
, *v
;
589 if(!(term
= getenv("TERM"))) {
590 fprintf(stderr
, "No TERM set\n");
594 if ( tgetent( buffer
, term
) != 1 ) {
595 fprintf(stderr
, "tgetent failed for term %s\n", term
);
602 if ( (Tclr_all
= tgetstr( "cl", &s
)) == NULL
)
605 if((v
= tgetstr ("li", &s
)) != NULL
)
606 sscanf(v
, "%d", rows
);
607 if(*rows
< 1) *rows
= 24;
610 void sigwinch(int sig
) { }
616 if ((fp
= fopen("kinfo", "r")) == NULL
) {
617 fprintf(stderr
, "opening " _PATH_PROC
"kinfo failed\n");
621 if (fscanf(fp
, "%u %u", &nr_procs
, &nr_tasks
) != 2) {
622 fprintf(stderr
, "reading from " _PATH_PROC
"kinfo failed\n");
628 nr_total
= (int) (nr_procs
+ nr_tasks
);
631 int main(int argc
, char *argv
[])
634 int cputimemode
= 1; /* bitmap. */
636 if (chdir(_PATH_PROC
) != 0) {
637 perror("chdir to " _PATH_PROC
);
641 system_hz
= (u32_t
) sysconf(_SC_CLK_TCK
);
647 while((c
=getopt(argc
, argv
, "s:B")) != EOF
) {
657 "Usage: %s [-s<secdelay>] [-B]\n",
666 /* Catch window size changes so display is updated properly
669 signal(SIGWINCH
, sigwinch
);
675 showtop(cputimemode
, r
);
680 FD_SET(STDIN_FILENO
, &fds
);
682 if((ns
=select(STDIN_FILENO
+1, &fds
, NULL
, NULL
, &tv
)) < 0
688 if(ns
> 0 && FD_ISSET(STDIN_FILENO
, &fds
)) {
690 if(read(STDIN_FILENO
, &c
, 1) == 1) {
698 if(order
> ORDER_HIGHEST
)
703 if(cputimemode
>= (1L << CPUTIMENAMES
))