source: trunk/minix/commands/simple/top.c@ 11

Last change on this file since 11 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 7.3 KB
RevLine 
[9]1
2/* Author: Ben Gras <beng@few.vu.nl> 17 march 2006 */
3
4#define _MINIX 1
5#define _POSIX_SOURCE 1
6
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>
21
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>
27
28#include <minix/ipc.h>
29#include <minix/config.h>
30#include <minix/type.h>
31#include <minix/const.h>
32
33#include "../../servers/pm/mproc.h"
34#include "../../kernel/const.h"
35#include "../../kernel/proc.h"
36
37#define TC_BUFFER 1024 /* Size of termcap(3) buffer */
38#define TC_STRINGS 200 /* Enough room for cm,cl,so,se */
39
40char *Tclr_all;
41
42int print_memory(struct pm_mem_info *pmi)
43{
44 int h;
45 int largest_bytes = 0, total_bytes = 0;
46 for(h = 0; h < _NR_HOLES; h++) {
47 if(pmi->pmi_holes[h].h_base && pmi->pmi_holes[h].h_len) {
48 int bytes;
49 bytes = pmi->pmi_holes[h].h_len << CLICK_SHIFT;
50 if(bytes > largest_bytes) largest_bytes = bytes;
51 total_bytes += bytes;
52 }
53 }
54
55 printf("Mem: %dK Free, %dK Contiguous Free\n",
56 total_bytes/1024, largest_bytes/1024);
57
58 return 1;
59}
60
61int print_load(double *loads, int nloads)
62{
63 int i;
64 printf("load averages: ");
65 for(i = 0; i < nloads; i++)
66 printf("%s %.2f", (i > 0) ? "," : "", loads[i]);
67 printf("\n");
68 return 1;
69}
70
71#define PROCS (NR_PROCS+NR_TASKS)
72
73int print_proc_summary(struct proc *proc)
74{
75 int p, alive, running, sleeping;
76
77 alive = running = sleeping = 0;
78
79 for(p = 0; p < PROCS; p++) {
80 if(p - NR_TASKS == IDLE)
81 continue;
82 if(proc[p].p_rts_flags & SLOT_FREE)
83 continue;
84 alive++;
85 if(proc[p].p_rts_flags & ~SLOT_FREE)
86 sleeping++;
87 else
88 running++;
89 }
90 printf("%d processes: %d running, %d sleeping\n",
91 alive, running, sleeping);
92 return 1;
93}
94
95static struct tp {
96 struct proc *p;
97 int ticks;
98} tick_procs[PROCS];
99
100int cmp_ticks(const void *v1, const void *v2)
101{
102 struct tp *p1 = (struct tp *) v1, *p2 = (struct tp *) v2;
103 if(p1->ticks < p2->ticks)
104 return 1;
105 if(p1->ticks > p2->ticks)
106 return -1;
107 if(p1->p->p_nr < p2->p->p_nr)
108 return -1;
109 if(p1->p->p_nr > p2->p->p_nr)
110 return 1;
111 return 0;
112}
113
114void print_procs(int maxlines,
115 struct proc *proc1, struct proc *proc2, int dt,
116 struct mproc *mproc)
117{
118 int p, nprocs, tot=0;
119 int idleticks = 0, kernelticks = 0, systemticks = 0;
120
121 if(dt < 1) return;
122
123 for(p = nprocs = 0; p < PROCS; p++) {
124 if(proc2[p].p_rts_flags & SLOT_FREE)
125 continue;
126 tick_procs[nprocs].p = proc2 + p;
127 if(proc1[p].p_endpoint == proc2[p].p_endpoint) {
128 tick_procs[nprocs].ticks =
129 proc2[p].p_user_time-proc1[p].p_user_time;
130 } else {
131 tick_procs[nprocs].ticks =
132 proc2[p].p_user_time;
133 }
134 if(p-NR_TASKS == IDLE) {
135 idleticks = tick_procs[nprocs].ticks;
136 continue;
137 }
138
139 /* Kernel task time, not counting IDLE */
140 if(proc2[p].p_nr < 0)
141 kernelticks += tick_procs[nprocs].ticks;
142 else if(mproc[proc2[p].p_nr].mp_procgrp == 0)
143 systemticks += tick_procs[nprocs].ticks;
144 nprocs++;
145 }
146
147 qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_ticks);
148
149 printf("CPU states: %6.2f%% user, %6.2f%% system, %6.2f%% kernel, %6.2f%% idle",
150 100.0*(dt-systemticks-kernelticks-idleticks)/dt,
151 100.0*systemticks/dt,
152 100.0*kernelticks/dt,
153 100.0*idleticks/dt);
154 printf("\n\n");
155 maxlines -= 2;
156
157 printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND\n");
158 maxlines--;
159 for(p = 0; p < nprocs; p++) {
160 int euid = 0;
161 struct proc *pr;
162 int pnr, ticks;
163 char *name = "";
164 static struct passwd *who = NULL;
165 static int last_who = -1;
166
167 if(maxlines-- <= 0) break;
168
169 pnr = tick_procs[p].p->p_nr;
170 pr = tick_procs[p].p;
171 ticks = pr->p_user_time;
172 if(pnr >= 0) {
173 printf("%5d ", mproc[pnr].mp_pid);
174 euid = mproc[pnr].mp_effuid;
175 name = mproc[pnr].mp_name;
176 } else {
177 printf("[%3d] ", pnr);
178 name = pr->p_name;
179 }
180 if(last_who != euid || !who) {
181 who = getpwuid(euid);
182 last_who = euid;
183 }
184
185 if(who && who->pw_name) printf("%-8s ", who->pw_name);
186 else if(pnr >= 0) printf("%8d ", mproc[pnr].mp_effuid);
187 else printf(" ");
188
189 printf(" %2d ", pr->p_priority);
190 if(pnr >= 0) {
191 printf(" %3d ", mproc[pnr].mp_nice);
192 } else printf(" ");
193 printf("%5dK",
194 ((pr->p_memmap[T].mem_len +
195 pr->p_memmap[D].mem_len) << CLICK_SHIFT)/1024);
196 printf("%6s", pr->p_rts_flags ? "" : "RUN");
197 printf(" %3d:%02d ", (ticks/HZ/60), (ticks/HZ)%60);
198
199 printf("%6.2f%% %s\n",
200 100.0*tick_procs[p].ticks/dt, name);
201 }
202}
203
204void showtop(int r)
205{
206#define NLOADS 3
207 double loads[NLOADS];
208 int nloads, i, p, lines = 0;
209 static struct proc prev_proc[PROCS], proc[PROCS];
210 struct winsize winsize;
211 static struct pm_mem_info pmi;
212 static int prev_uptime, uptime;
213 static struct mproc mproc[NR_PROCS];
214 struct tms tms;
215
216 uptime = times(&tms);
217
218 if(ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize) != 0) {
219 perror("TIOCGWINSZ");
220 fprintf(stderr, "TIOCGWINSZ failed\n");
221 exit(1);
222 }
223
224 if(getsysinfo(PM_PROC_NR, SI_MEM_ALLOC, &pmi) < 0) {
225 fprintf(stderr, "getsysinfo() for SI_MEM_ALLOC failed.\n");
226 exit(1);;
227 }
228
229 if(getsysinfo(PM_PROC_NR, SI_KPROC_TAB, proc) < 0) {
230 fprintf(stderr, "getsysinfo() for SI_KPROC_TAB failed.\n");
231 exit(1);
232 }
233
234 if(getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc) < 0) {
235 fprintf(stderr, "getsysinfo() for SI_PROC_TAB failed.\n");
236 exit(1);
237 }
238
239 if((nloads = getloadavg(loads, NLOADS)) != NLOADS) {
240 fprintf(stderr, "getloadavg() failed - %d loads\n", nloads);
241 exit(1);
242 }
243
244
245 printf("%s", Tclr_all);
246
247 lines += print_load(loads, NLOADS);
248 lines += print_proc_summary(proc);
249 lines += print_memory(&pmi);
250
251 if(winsize.ws_row > 0) r = winsize.ws_row;
252
253 print_procs(r - lines - 2, prev_proc,
254 proc, uptime-prev_uptime, mproc);
255
256 memcpy(prev_proc, proc, sizeof(prev_proc));
257 prev_uptime = uptime;
258}
259
260void init(int *rows)
261{
262 char *term;
263 static char buffer[TC_BUFFER], strings[TC_STRINGS];
264 char *s = strings, *v;
265
266 *rows = 0;
267
268 if(!(term = getenv("TERM"))) {
269 fprintf(stderr, "No TERM set\n");
270 exit(1);
271 }
272
273 if ( tgetent( buffer, term ) != 1 ) {
274 fprintf(stderr, "tgetent failed for term %s\n", term);
275 exit(1);
276 }
277
278 if ( (Tclr_all = tgetstr( "cl", &s )) == NULL )
279 Tclr_all = "\f";
280
281 if((v = tgetstr ("li", &s)) != NULL)
282 sscanf(v, "%d", rows);
283 if(*rows < 1) *rows = 24;
284 if(!initscr()) {
285 fprintf(stderr, "initscr() failed\n");
286 exit(1);
287 }
288 cbreak();
289 nl();
290}
291
292void sigwinch(int sig) { }
293
294int main(int argc, char *argv[])
295{
296 int r, c, s = 0, orig;
297
298 init(&r);
299
300 while((c=getopt(argc, argv, "s:")) != EOF) {
301 switch(c) {
302 case 's':
303 s = atoi(optarg);
304 break;
305 default:
306 fprintf(stderr,
307 "Usage: %s [-s<secdelay>]\n", argv[0]);
308 return 1;
309 }
310 }
311
312 if(s < 1)
313 s = 2;
314
315 /* Catch window size changes so display is updated properly right away. */
316 signal(SIGWINCH, sigwinch);
317
318 while(1) {
319 fd_set fds;
320 int ns;
321 struct timeval tv;
322 showtop(r);
323 tv.tv_sec = s;
324 tv.tv_usec = 0;
325
326 FD_ZERO(&fds);
327 FD_SET(STDIN_FILENO, &fds);
328 if((ns=select(STDIN_FILENO+1, &fds, NULL, NULL, &tv)) < 0
329 && errno != EINTR) {
330 perror("select");
331 sleep(1);
332 }
333
334 if(ns > 0 && FD_ISSET(STDIN_FILENO, &fds)) {
335 char c;
336 if(read(STDIN_FILENO, &c, 1) == 1) {
337 switch(c) {
338 case 'q':
339 return 0;
340 break;
341 }
342 }
343 }
344 }
345
346 return 0;
347}
348
Note: See TracBrowser for help on using the repository browser.