improve behaviour under VPC, fixes from nicolas tittley.
[minix.git] / commands / simple / top.c
blob38f83b27b818fcbbb7d9587cbb3bc4a8711149d3
2 /* Author: Ben Gras <beng@few.vu.nl> 17 march 2006 */
4 #define _MINIX 1
5 #define _POSIX_SOURCE 1
7 #include <stdio.h>
8 #include <pwd.h>
9 #include <curses.h>
10 #include <timers.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <limits.h>
14 #include <termcap.h>
15 #include <termios.h>
16 #include <time.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <fcntl.h>
20 #include <errno.h>
22 #include <sys/ioc_tty.h>
23 #include <sys/times.h>
24 #include <sys/types.h>
25 #include <sys/time.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 "../../kernel/arch/i386/include/archtypes.h"
36 #include "../../servers/pm/mproc.h"
37 #include "../../kernel/const.h"
38 #include "../../kernel/proc.h"
40 u32_t system_hz;
42 #define TC_BUFFER 1024 /* Size of termcap(3) buffer */
43 #define TC_STRINGS 200 /* Enough room for cm,cl,so,se */
45 char *Tclr_all;
47 #if 0
48 int print_memory(struct pm_mem_info *pmi)
50 int h;
51 int largest_bytes = 0, total_bytes = 0;
52 for(h = 0; h < _NR_HOLES; h++) {
53 if(pmi->pmi_holes[h].h_base && pmi->pmi_holes[h].h_len) {
54 int bytes;
55 bytes = pmi->pmi_holes[h].h_len << CLICK_SHIFT;
56 if(bytes > largest_bytes) largest_bytes = bytes;
57 total_bytes += bytes;
61 printf("Mem: %dK Free, %dK Contiguous Free\n",
62 total_bytes/1024, largest_bytes/1024);
64 return 1;
66 #endif
68 int print_load(double *loads, int nloads)
70 int i;
71 printf("load averages: ");
72 for(i = 0; i < nloads; i++)
73 printf("%s %.2f", (i > 0) ? "," : "", loads[i]);
74 printf("\n");
75 return 1;
78 #define PROCS (NR_PROCS+NR_TASKS)
80 int print_proc_summary(struct proc *proc)
82 int p, alive, running, sleeping;
84 alive = running = sleeping = 0;
86 for(p = 0; p < PROCS; p++) {
87 if(p - NR_TASKS == IDLE)
88 continue;
89 if(isemptyp(&proc[p]))
90 continue;
91 alive++;
92 if(!proc_is_runnable(&proc[p]))
93 sleeping++;
94 else
95 running++;
97 printf("%d processes: %d running, %d sleeping\n",
98 alive, running, sleeping);
99 return 1;
102 static struct tp {
103 struct proc *p;
104 int ticks;
105 } tick_procs[PROCS];
107 int cmp_ticks(const void *v1, const void *v2)
109 struct tp *p1 = (struct tp *) v1, *p2 = (struct tp *) v2;
110 if(p1->ticks < p2->ticks)
111 return 1;
112 if(p1->ticks > p2->ticks)
113 return -1;
114 if(p1->p->p_nr < p2->p->p_nr)
115 return -1;
116 if(p1->p->p_nr > p2->p->p_nr)
117 return 1;
118 return 0;
121 void print_procs(int maxlines,
122 struct proc *proc1, struct proc *proc2, int dt,
123 struct mproc *mproc)
125 int p, nprocs, tot=0;
126 int idleticks = 0, kernelticks = 0, systemticks = 0;
128 if(dt < 1) return;
130 for(p = nprocs = 0; p < PROCS; p++) {
131 if(isemptyp(&proc2[p]))
132 continue;
133 tick_procs[nprocs].p = proc2 + p;
134 if(proc1[p].p_endpoint == proc2[p].p_endpoint) {
135 tick_procs[nprocs].ticks =
136 proc2[p].p_user_time-proc1[p].p_user_time;
137 } else {
138 tick_procs[nprocs].ticks =
139 proc2[p].p_user_time;
141 if(p-NR_TASKS == IDLE) {
142 idleticks = tick_procs[nprocs].ticks;
143 continue;
146 /* Kernel task time, not counting IDLE */
147 if(proc2[p].p_nr < 0)
148 kernelticks += tick_procs[nprocs].ticks;
149 else if(mproc[proc2[p].p_nr].mp_procgrp == 0)
150 systemticks += tick_procs[nprocs].ticks;
151 nprocs++;
154 qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_ticks);
156 printf("CPU states: %6.2f%% user, %6.2f%% system, %6.2f%% kernel, %6.2f%% idle",
157 100.0*(dt-systemticks-kernelticks-idleticks)/dt,
158 100.0*systemticks/dt,
159 100.0*kernelticks/dt,
160 100.0*idleticks/dt);
161 printf("\n\n");
162 maxlines -= 2;
164 printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND\n");
165 maxlines--;
166 for(p = 0; p < nprocs; p++) {
167 int euid = 0;
168 struct proc *pr;
169 int pnr, ticks;
170 char *name = "";
171 static struct passwd *who = NULL;
172 static int last_who = -1;
174 if(maxlines-- <= 0) break;
176 pnr = tick_procs[p].p->p_nr;
177 pr = tick_procs[p].p;
178 ticks = pr->p_user_time;
179 if(pnr >= 0) {
180 printf("%5d ", mproc[pnr].mp_pid);
181 euid = mproc[pnr].mp_effuid;
182 name = mproc[pnr].mp_name;
183 } else {
184 printf("[%3d] ", pnr);
185 name = pr->p_name;
187 if(last_who != euid || !who) {
188 who = getpwuid(euid);
189 last_who = euid;
192 if(who && who->pw_name) printf("%-8s ", who->pw_name);
193 else if(pnr >= 0) printf("%8d ", mproc[pnr].mp_effuid);
194 else printf(" ");
196 printf(" %2d ", pr->p_priority);
197 if(pnr >= 0) {
198 printf(" %3d ", mproc[pnr].mp_nice);
199 } else printf(" ");
200 printf("%5dK",
201 ((pr->p_memmap[T].mem_len +
202 pr->p_memmap[D].mem_len) << CLICK_SHIFT)/1024);
203 printf("%6s", pr->p_rts_flags ? "" : "RUN");
204 printf(" %3d:%02d ", (ticks/system_hz/60), (ticks/system_hz)%60);
206 printf("%6.2f%% %s\n",
207 100.0*tick_procs[p].ticks/dt, name);
211 void showtop(int r)
213 #define NLOADS 3
214 double loads[NLOADS];
215 int nloads, i, p, lines = 0;
216 static struct proc prev_proc[PROCS], proc[PROCS];
217 struct winsize winsize;
219 static struct pm_mem_info pmi;
221 static int prev_uptime, uptime;
222 static struct mproc mproc[NR_PROCS];
223 struct tms tms;
224 int mem = 0;
226 uptime = times(&tms);
228 if(ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize) != 0) {
229 perror("TIOCGWINSZ");
230 fprintf(stderr, "TIOCGWINSZ failed\n");
231 exit(1);
234 #if 0
235 if(getsysinfo(PM_PROC_NR, SI_MEM_ALLOC, &pmi) < 0) {
236 fprintf(stderr, "getsysinfo() for SI_MEM_ALLOC failed.\n");
237 mem = 0;
238 exit(1);;
239 } else mem = 1;
240 #endif
242 if(getsysinfo(PM_PROC_NR, SI_KPROC_TAB, proc) < 0) {
243 fprintf(stderr, "getsysinfo() for SI_KPROC_TAB failed.\n");
244 exit(1);
247 if(getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc) < 0) {
248 fprintf(stderr, "getsysinfo() for SI_PROC_TAB failed.\n");
249 exit(1);
252 if((nloads = getloadavg(loads, NLOADS)) != NLOADS) {
253 fprintf(stderr, "getloadavg() failed - %d loads\n", nloads);
254 exit(1);
258 printf("%s", Tclr_all);
260 lines += print_load(loads, NLOADS);
261 lines += print_proc_summary(proc);
262 #if 0
263 if(mem) { lines += print_memory(&pmi); }
264 #endif
266 if(winsize.ws_row > 0) r = winsize.ws_row;
268 print_procs(r - lines - 2, prev_proc,
269 proc, uptime-prev_uptime, mproc);
271 memcpy(prev_proc, proc, sizeof(prev_proc));
272 prev_uptime = uptime;
275 void init(int *rows)
277 char *term;
278 static char buffer[TC_BUFFER], strings[TC_STRINGS];
279 char *s = strings, *v;
281 *rows = 0;
283 if(!(term = getenv("TERM"))) {
284 fprintf(stderr, "No TERM set\n");
285 exit(1);
288 if ( tgetent( buffer, term ) != 1 ) {
289 fprintf(stderr, "tgetent failed for term %s\n", term);
290 exit(1);
293 if ( (Tclr_all = tgetstr( "cl", &s )) == NULL )
294 Tclr_all = "\f";
296 if((v = tgetstr ("li", &s)) != NULL)
297 sscanf(v, "%d", rows);
298 if(*rows < 1) *rows = 24;
299 if(!initscr()) {
300 fprintf(stderr, "initscr() failed\n");
301 exit(1);
303 cbreak();
304 nl();
307 void sigwinch(int sig) { }
309 int main(int argc, char *argv[])
311 int r, c, s = 0, orig;
313 getsysinfo_up(PM_PROC_NR, SIU_SYSTEMHZ, sizeof(system_hz), &system_hz);
315 init(&r);
317 while((c=getopt(argc, argv, "s:")) != EOF) {
318 switch(c) {
319 case 's':
320 s = atoi(optarg);
321 break;
322 default:
323 fprintf(stderr,
324 "Usage: %s [-s<secdelay>]\n", argv[0]);
325 return 1;
329 if(s < 1)
330 s = 2;
332 /* Catch window size changes so display is updated properly right away. */
333 signal(SIGWINCH, sigwinch);
335 while(1) {
336 fd_set fds;
337 int ns;
338 struct timeval tv;
339 showtop(r);
340 tv.tv_sec = s;
341 tv.tv_usec = 0;
343 FD_ZERO(&fds);
344 FD_SET(STDIN_FILENO, &fds);
345 if((ns=select(STDIN_FILENO+1, &fds, NULL, NULL, &tv)) < 0
346 && errno != EINTR) {
347 perror("select");
348 sleep(1);
351 if(ns > 0 && FD_ISSET(STDIN_FILENO, &fds)) {
352 char c;
353 if(read(STDIN_FILENO, &c, 1) == 1) {
354 switch(c) {
355 case 'q':
356 return 0;
357 break;
363 return 0;