2 /* Author: Ben Gras <beng@few.vu.nl> 17 march 2006 */
5 #define _POSIX_SOURCE 1
22 #include <sys/ioc_tty.h>
23 #include <sys/times.h>
24 #include <sys/types.h>
26 #include <sys/select.h>
28 #include <minix/ipc.h>
29 #include <minix/com.h>
30 #include <minix/sysinfo.h>
31 #include <minix/config.h>
32 #include <minix/type.h>
33 #include <minix/const.h>
35 #include <minix/u64.h>
37 #include <machine/archtypes.h>
38 #include "../../servers/pm/mproc.h"
39 #include "../../kernel/const.h"
40 #include "../../kernel/proc.h"
44 #define TC_BUFFER 1024 /* Size of termcap(3) buffer */
45 #define TC_STRINGS 200 /* Enough room for cm,cl,so,se */
49 int blockedverbose
= 0;
52 int print_memory(struct pm_mem_info
*pmi
)
55 int largest_bytes
= 0, total_bytes
= 0;
56 for(h
= 0; h
< _NR_HOLES
; h
++) {
57 if(pmi
->pmi_holes
[h
].h_base
&& pmi
->pmi_holes
[h
].h_len
) {
59 bytes
= pmi
->pmi_holes
[h
].h_len
<< CLICK_SHIFT
;
60 if(bytes
> largest_bytes
) largest_bytes
= bytes
;
65 printf("Mem: %dK Free, %dK Contiguous Free\n",
66 total_bytes
/1024, largest_bytes
/1024);
72 int print_load(double *loads
, int nloads
)
75 printf("load averages: ");
76 for(i
= 0; i
< nloads
; i
++)
77 printf("%s %.2f", (i
> 0) ? "," : "", loads
[i
]);
82 #define PROCS (NR_PROCS+NR_TASKS)
84 int print_proc_summary(struct proc
*proc
)
86 int p
, alive
, running
, sleeping
;
88 alive
= running
= sleeping
= 0;
90 for(p
= 0; p
< PROCS
; p
++) {
91 if(p
- NR_TASKS
== IDLE
)
93 if(isemptyp(&proc
[p
]))
96 if(!proc_is_runnable(&proc
[p
]))
101 printf("%d processes: %d running, %d sleeping\n",
102 alive
, running
, sleeping
);
111 int cmp_ticks(const void *v1
, const void *v2
)
114 struct tp
*p1
= (struct tp
*) v1
, *p2
= (struct tp
*) v2
;
115 int p1blocked
, p2blocked
;
117 p1blocked
= !!p1
->p
->p_rts_flags
;
118 p2blocked
= !!p2
->p
->p_rts_flags
;
120 /* Primarily order by used number of cpu cycles.
122 * Exception: if in blockedverbose mode, a blocked
123 * process is always printed after an unblocked
124 * process, and used cpu cycles don't matter.
126 * In both cases, process slot number is a tie breaker.
129 if(blockedverbose
&& (p1blocked
|| p2blocked
)) {
130 if(!p1blocked
&& p2blocked
)
132 if( p2blocked
&& !p1blocked
)
134 } else if((c
=cmp64(p1
->ticks
, p2
->ticks
)) != 0)
137 /* Process slot number is a tie breaker. */
139 if(p1
->p
->p_nr
< p2
->p
->p_nr
)
141 if(p1
->p
->p_nr
> p2
->p
->p_nr
)
144 fprintf(stderr
, "unreachable.\n");
148 struct tp
*lookup(endpoint_t who
, struct tp
*tptab
, int np
)
152 for(t
= 0; t
< np
; t
++)
153 if(who
== tptab
[t
].p
->p_endpoint
)
156 fprintf(stderr
, "lookup: tp %d (0x%x) not found.\n", who
, who
);
163 * since we don't have true div64(u64_t, u64_t) we scale the 64 bit counters to
164 * 32. Since the samplig happens every ~1s and the counters count CPU cycles
165 * during this period, unless we have extremely fast CPU, shifting the counters
166 * by 12 make them 32bit counters which we can use for normal integer
169 #define SCALE (1 << 12)
171 void print_proc(struct tp
*tp
, struct mproc
*mpr
, u32_t tcyc
)
174 static struct passwd
*who
= NULL
;
175 static int last_who
= -1;
179 struct proc
*pr
= tp
->p
;
181 printf("%5d ", mpr
->mp_pid
);
182 euid
= mpr
->mp_effuid
;
185 if(last_who
!= euid
|| !who
) {
186 who
= getpwuid(euid
);
190 if(who
&& who
->pw_name
) printf("%-8s ", who
->pw_name
);
191 else if(pr
->p_nr
>= 0) printf("%8d ", mpr
->mp_effuid
);
194 printf(" %2d ", pr
->p_priority
);
196 printf(" %3d ", mpr
->mp_nice
);
199 ((pr
->p_memmap
[T
].mem_len
+
200 pr
->p_memmap
[D
].mem_len
) << CLICK_SHIFT
)/1024);
201 printf("%6s", pr
->p_rts_flags
? "" : "RUN");
202 ticks
= pr
->p_user_time
;
203 printf(" %3d:%02d ", (ticks
/system_hz
/60), (ticks
/system_hz
)%60);
205 pcyc
= div64u(tp
->ticks
, SCALE
);
207 printf("%6.2f%% %s", 100.0*pcyc
/tcyc
, name
);
210 void print_procs(int maxlines
,
211 struct proc
*proc1
, struct proc
*proc2
,
214 int p
, nprocs
, tot
=0;
215 u64_t idleticks
= cvu64(0);
216 u64_t kernelticks
= cvu64(0);
217 u64_t systemticks
= cvu64(0);
218 u64_t userticks
= cvu64(0);
219 u64_t total_ticks
= cvu64(0);
223 struct tp tick_procs
[PROCS
];
225 for(p
= nprocs
= 0; p
< PROCS
; p
++) {
226 if(isemptyp(&proc2
[p
]))
228 tick_procs
[nprocs
].p
= proc2
+ p
;
229 if(proc1
[p
].p_endpoint
== proc2
[p
].p_endpoint
) {
230 tick_procs
[nprocs
].ticks
=
231 sub64(proc2
[p
].p_cycles
, proc1
[p
].p_cycles
);
233 tick_procs
[nprocs
].ticks
=
236 total_ticks
= add64(total_ticks
, tick_procs
[nprocs
].ticks
);
237 if(p
-NR_TASKS
== IDLE
) {
238 idleticks
= tick_procs
[nprocs
].ticks
;
241 if(p
-NR_TASKS
== KERNEL
) {
242 kernelticks
= tick_procs
[nprocs
].ticks
;
245 if(mproc
[proc2
[p
].p_nr
].mp_procgrp
== 0)
246 systemticks
= add64(systemticks
, tick_procs
[nprocs
].ticks
);
247 else if (p
> NR_TASKS
)
248 userticks
= add64(userticks
, tick_procs
[nprocs
].ticks
);
253 if (!cmp64u(total_ticks
, 0))
256 qsort(tick_procs
, nprocs
, sizeof(tick_procs
[0]), cmp_ticks
);
258 tcyc
= div64u(total_ticks
, SCALE
);
260 tmp
= div64u(userticks
, SCALE
);
261 printf("CPU states: %6.2f%% user, ", 100.0*(tmp
)/tcyc
);
263 tmp
= div64u(systemticks
, SCALE
);
264 printf("%6.2f%% system, ", 100.0*tmp
/tcyc
);
266 tmp
= div64u(kernelticks
, SCALE
);
267 printf("%6.2f%% kernel, ", 100.0*tmp
/tcyc
);
269 tmp
= div64u(idleticks
, SCALE
);
270 printf("%6.2f%% idle", 100.0*tmp
/tcyc
);
272 #define NEWLINE do { printf("\n"); if(--maxlines <= 0) { return; } } while(0)
276 printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND");
278 for(p
= 0; p
< nprocs
; p
++) {
283 pnr
= tick_procs
[p
].p
->p_nr
;
286 /* skip old kernel tasks as they don't run anymore */
290 pr
= tick_procs
[p
].p
;
292 /* If we're in blocked verbose mode, indicate start of
295 if(blockedverbose
&& pr
->p_rts_flags
&& !blockedseen
) {
297 printf("Blocked processes:");
302 print_proc(&tick_procs
[p
], &mproc
[pnr
], tcyc
);
308 /* Traverse dependency chain if blocked. */
309 while(pr
->p_rts_flags
) {
310 endpoint_t dep
= NONE
;
314 if((dep
= P_BLOCKEDON(pr
)) == NONE
) {
315 printf("not blocked on a process");
323 tpdep
= lookup(dep
, tick_procs
, nprocs
);
325 printf("%*s> ", level
, "");
326 print_proc(tpdep
, &mproc
[pr
->p_nr
], tcyc
);
335 double loads
[NLOADS
];
336 int nloads
, i
, p
, lines
= 0;
337 static struct proc prev_proc
[PROCS
], proc
[PROCS
];
338 static int preheated
= 0;
339 struct winsize winsize
;
341 static struct pm_mem_info pmi;
343 static struct mproc mproc
[NR_PROCS
];
346 if(ioctl(STDIN_FILENO
, TIOCGWINSZ
, &winsize
) != 0) {
347 perror("TIOCGWINSZ");
348 fprintf(stderr
, "TIOCGWINSZ failed\n");
353 if(getsysinfo(PM_PROC_NR
, SI_MEM_ALLOC
, &pmi
) < 0) {
354 fprintf(stderr
, "getsysinfo() for SI_MEM_ALLOC failed.\n");
361 if(getsysinfo(PM_PROC_NR
, SI_KPROC_TAB
, proc
) < 0) {
362 fprintf(stderr
, "getsysinfo() for SI_KPROC_TAB failed.\n");
367 memcpy(prev_proc
, proc
, sizeof(prev_proc
));
371 if(getsysinfo(PM_PROC_NR
, SI_PROC_TAB
, mproc
) < 0) {
372 fprintf(stderr
, "getsysinfo() for SI_PROC_TAB failed.\n");
376 if((nloads
= getloadavg(loads
, NLOADS
)) != NLOADS
) {
377 fprintf(stderr
, "getloadavg() failed - %d loads\n", nloads
);
382 printf("%s", Tclr_all
);
384 lines
+= print_load(loads
, NLOADS
);
385 lines
+= print_proc_summary(proc
);
387 if(mem
) { lines
+= print_memory(&pmi
); }
390 if(winsize
.ws_row
> 0) r
= winsize
.ws_row
;
392 print_procs(r
- lines
- 2, prev_proc
,
395 memcpy(prev_proc
, proc
, sizeof(prev_proc
));
401 static char buffer
[TC_BUFFER
], strings
[TC_STRINGS
];
402 char *s
= strings
, *v
;
406 if(!(term
= getenv("TERM"))) {
407 fprintf(stderr
, "No TERM set\n");
411 if ( tgetent( buffer
, term
) != 1 ) {
412 fprintf(stderr
, "tgetent failed for term %s\n", term
);
416 if ( (Tclr_all
= tgetstr( "cl", &s
)) == NULL
)
419 if((v
= tgetstr ("li", &s
)) != NULL
)
420 sscanf(v
, "%d", rows
);
421 if(*rows
< 1) *rows
= 24;
423 fprintf(stderr
, "initscr() failed\n");
430 void sigwinch(int sig
) { }
432 int main(int argc
, char *argv
[])
434 int r
, c
, s
= 0, orig
;
436 getsysinfo_up(PM_PROC_NR
, SIU_SYSTEMHZ
, sizeof(system_hz
), &system_hz
);
440 while((c
=getopt(argc
, argv
, "s:B")) != EOF
) {
450 "Usage: %s [-s<secdelay>] [-B]\n",
459 /* Catch window size changes so display is updated properly
462 signal(SIGWINCH
, sigwinch
);
473 FD_SET(STDIN_FILENO
, &fds
);
474 if((ns
=select(STDIN_FILENO
+1, &fds
, NULL
, NULL
, &tv
)) < 0
480 if(ns
> 0 && FD_ISSET(STDIN_FILENO
, &fds
)) {
482 if(read(STDIN_FILENO
, &c
, 1) == 1) {