00001
00002
00003
00004 #define _MINIX 1
00005 #define _POSIX_SOURCE 1
00006
00007 #include <stdio.h>
00008 #include <pwd.h>
00009 #include <curses.h>
00010 #include <timers.h>
00011 #include <unistd.h>
00012 #include <stdlib.h>
00013 #include <limits.h>
00014 #include <termcap.h>
00015 #include <termios.h>
00016 #include <time.h>
00017 #include <string.h>
00018 #include <signal.h>
00019 #include <fcntl.h>
00020 #include <errno.h>
00021
00022 #include <sys/ioc_tty.h>
00023 #include <sys/times.h>
00024 #include <sys/types.h>
00025 #include <sys/time.h>
00026 #include <sys/select.h>
00027
00028 #include <minix/ipc.h>
00029 #include <minix/config.h>
00030 #include <minix/type.h>
00031 #include <minix/const.h>
00032
00033 #include "../../servers/pm/mproc.h"
00034 #include "../../kernel/const.h"
00035 #include "../../kernel/proc.h"
00036
00037 #define TC_BUFFER 1024
00038 #define TC_STRINGS 200
00039
00040 char *Tclr_all;
00041
00042 int print_memory(struct pm_mem_info *pmi)
00043 {
00044 int h;
00045 int largest_bytes = 0, total_bytes = 0;
00046 for(h = 0; h < _NR_HOLES; h++) {
00047 if(pmi->pmi_holes[h].h_base && pmi->pmi_holes[h].h_len) {
00048 int bytes;
00049 bytes = pmi->pmi_holes[h].h_len << CLICK_SHIFT;
00050 if(bytes > largest_bytes) largest_bytes = bytes;
00051 total_bytes += bytes;
00052 }
00053 }
00054
00055 printf("Mem: %dK Free, %dK Contiguous Free\n",
00056 total_bytes/1024, largest_bytes/1024);
00057
00058 return 1;
00059 }
00060
00061 int print_load(double *loads, int nloads)
00062 {
00063 int i;
00064 printf("load averages: ");
00065 for(i = 0; i < nloads; i++)
00066 printf("%s %.2f", (i > 0) ? "," : "", loads[i]);
00067 printf("\n");
00068 return 1;
00069 }
00070
00071 #define PROCS (NR_PROCS+NR_TASKS)
00072
00073 int print_proc_summary(struct proc *proc)
00074 {
00075 int p, alive, running, sleeping;
00076
00077 alive = running = sleeping = 0;
00078
00079 for(p = 0; p < PROCS; p++) {
00080 if(p - NR_TASKS == IDLE)
00081 continue;
00082 if(proc[p].p_rts_flags & SLOT_FREE)
00083 continue;
00084 alive++;
00085 if(proc[p].p_rts_flags & ~SLOT_FREE)
00086 sleeping++;
00087 else
00088 running++;
00089 }
00090 printf("%d processes: %d running, %d sleeping\n",
00091 alive, running, sleeping);
00092 return 1;
00093 }
00094
00095 static struct tp {
00096 struct proc *p;
00097 int ticks;
00098 } tick_procs[PROCS];
00099
00100 int cmp_ticks(const void *v1, const void *v2)
00101 {
00102 struct tp *p1 = (struct tp *) v1, *p2 = (struct tp *) v2;
00103 if(p1->ticks < p2->ticks)
00104 return 1;
00105 if(p1->ticks > p2->ticks)
00106 return -1;
00107 if(p1->p->p_nr < p2->p->p_nr)
00108 return -1;
00109 if(p1->p->p_nr > p2->p->p_nr)
00110 return 1;
00111 return 0;
00112 }
00113
00114 void print_procs(int maxlines,
00115 struct proc *proc1, struct proc *proc2, int dt,
00116 struct mproc *mproc)
00117 {
00118 int p, nprocs, tot=0;
00119 int idleticks = 0, kernelticks = 0, systemticks = 0;
00120
00121 if(dt < 1) return;
00122
00123 for(p = nprocs = 0; p < PROCS; p++) {
00124 if(proc2[p].p_rts_flags & SLOT_FREE)
00125 continue;
00126 tick_procs[nprocs].p = proc2 + p;
00127 if(proc1[p].p_endpoint == proc2[p].p_endpoint) {
00128 tick_procs[nprocs].ticks =
00129 proc2[p].p_user_time-proc1[p].p_user_time;
00130 } else {
00131 tick_procs[nprocs].ticks =
00132 proc2[p].p_user_time;
00133 }
00134 if(p-NR_TASKS == IDLE) {
00135 idleticks = tick_procs[nprocs].ticks;
00136 continue;
00137 }
00138
00139
00140 if(proc2[p].p_nr < 0)
00141 kernelticks += tick_procs[nprocs].ticks;
00142 else if(mproc[proc2[p].p_nr].mp_procgrp == 0)
00143 systemticks += tick_procs[nprocs].ticks;
00144 nprocs++;
00145 }
00146
00147 qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_ticks);
00148
00149 printf("CPU states: %6.2f%% user, %6.2f%% system, %6.2f%% kernel, %6.2f%% idle",
00150 100.0*(dt-systemticks-kernelticks-idleticks)/dt,
00151 100.0*systemticks/dt,
00152 100.0*kernelticks/dt,
00153 100.0*idleticks/dt);
00154 printf("\n\n");
00155 maxlines -= 2;
00156
00157 printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND\n");
00158 maxlines--;
00159 for(p = 0; p < nprocs; p++) {
00160 int euid = 0;
00161 struct proc *pr;
00162 int pnr, ticks;
00163 char *name = "";
00164 static struct passwd *who = NULL;
00165 static int last_who = -1;
00166
00167 if(maxlines-- <= 0) break;
00168
00169 pnr = tick_procs[p].p->p_nr;
00170 pr = tick_procs[p].p;
00171 ticks = pr->p_user_time;
00172 if(pnr >= 0) {
00173 printf("%5d ", mproc[pnr].mp_pid);
00174 euid = mproc[pnr].mp_effuid;
00175 name = mproc[pnr].mp_name;
00176 } else {
00177 printf("[%3d] ", pnr);
00178 name = pr->p_name;
00179 }
00180 if(last_who != euid || !who) {
00181 who = getpwuid(euid);
00182 last_who = euid;
00183 }
00184
00185 if(who && who->pw_name) printf("%-8s ", who->pw_name);
00186 else if(pnr >= 0) printf("%8d ", mproc[pnr].mp_effuid);
00187 else printf(" ");
00188
00189 printf(" %2d ", pr->p_priority);
00190 if(pnr >= 0) {
00191 printf(" %3d ", mproc[pnr].mp_nice);
00192 } else printf(" ");
00193 printf("%5dK",
00194 ((pr->p_memmap[T].mem_len +
00195 pr->p_memmap[D].mem_len) << CLICK_SHIFT)/1024);
00196 printf("%6s", pr->p_rts_flags ? "" : "RUN");
00197 printf(" %3d:%02d ", (ticks/HZ/60), (ticks/HZ)%60);
00198
00199 printf("%6.2f%% %s\n",
00200 100.0*tick_procs[p].ticks/dt, name);
00201 }
00202 }
00203
00204 void showtop(int r)
00205 {
00206 #define NLOADS 3
00207 double loads[NLOADS];
00208 int nloads, i, p, lines = 0;
00209 static struct proc prev_proc[PROCS], proc[PROCS];
00210 struct winsize winsize;
00211 static struct pm_mem_info pmi;
00212 static int prev_uptime, uptime;
00213 static struct mproc mproc[NR_PROCS];
00214 struct tms tms;
00215
00216 uptime = times(&tms);
00217
00218 if(ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize) != 0) {
00219 perror("TIOCGWINSZ");
00220 fprintf(stderr, "TIOCGWINSZ failed\n");
00221 exit(1);
00222 }
00223
00224 if(getsysinfo(PM_PROC_NR, SI_MEM_ALLOC, &pmi) < 0) {
00225 fprintf(stderr, "getsysinfo() for SI_MEM_ALLOC failed.\n");
00226 exit(1);;
00227 }
00228
00229 if(getsysinfo(PM_PROC_NR, SI_KPROC_TAB, proc) < 0) {
00230 fprintf(stderr, "getsysinfo() for SI_KPROC_TAB failed.\n");
00231 exit(1);
00232 }
00233
00234 if(getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc) < 0) {
00235 fprintf(stderr, "getsysinfo() for SI_PROC_TAB failed.\n");
00236 exit(1);
00237 }
00238
00239 if((nloads = getloadavg(loads, NLOADS)) != NLOADS) {
00240 fprintf(stderr, "getloadavg() failed - %d loads\n", nloads);
00241 exit(1);
00242 }
00243
00244
00245 printf("%s", Tclr_all);
00246
00247 lines += print_load(loads, NLOADS);
00248 lines += print_proc_summary(proc);
00249 lines += print_memory(&pmi);
00250
00251 if(winsize.ws_row > 0) r = winsize.ws_row;
00252
00253 print_procs(r - lines - 2, prev_proc,
00254 proc, uptime-prev_uptime, mproc);
00255
00256 memcpy(prev_proc, proc, sizeof(prev_proc));
00257 prev_uptime = uptime;
00258 }
00259
00260 void init(int *rows)
00261 {
00262 char *term;
00263 static char buffer[TC_BUFFER], strings[TC_STRINGS];
00264 char *s = strings, *v;
00265
00266 *rows = 0;
00267
00268 if(!(term = getenv("TERM"))) {
00269 fprintf(stderr, "No TERM set\n");
00270 exit(1);
00271 }
00272
00273 if ( tgetent( buffer, term ) != 1 ) {
00274 fprintf(stderr, "tgetent failed for term %s\n", term);
00275 exit(1);
00276 }
00277
00278 if ( (Tclr_all = tgetstr( "cl", &s )) == NULL )
00279 Tclr_all = "\f";
00280
00281 if((v = tgetstr ("li", &s)) != NULL)
00282 sscanf(v, "%d", rows);
00283 if(*rows < 1) *rows = 24;
00284 if(!initscr()) {
00285 fprintf(stderr, "initscr() failed\n");
00286 exit(1);
00287 }
00288 cbreak();
00289 nl();
00290 }
00291
00292 void sigwinch(int sig) { }
00293
00294 int main(int argc, char *argv[])
00295 {
00296 int r, c, s = 0, orig;
00297
00298 init(&r);
00299
00300 while((c=getopt(argc, argv, "s:")) != EOF) {
00301 switch(c) {
00302 case 's':
00303 s = atoi(optarg);
00304 break;
00305 default:
00306 fprintf(stderr,
00307 "Usage: %s [-s<secdelay>]\n", argv[0]);
00308 return 1;
00309 }
00310 }
00311
00312 if(s < 1)
00313 s = 2;
00314
00315
00316 signal(SIGWINCH, sigwinch);
00317
00318 while(1) {
00319 fd_set fds;
00320 int ns;
00321 struct timeval tv;
00322 showtop(r);
00323 tv.tv_sec = s;
00324 tv.tv_usec = 0;
00325
00326 FD_ZERO(&fds);
00327 FD_SET(STDIN_FILENO, &fds);
00328 if((ns=select(STDIN_FILENO+1, &fds, NULL, NULL, &tv)) < 0
00329 && errno != EINTR) {
00330 perror("select");
00331 sleep(1);
00332 }
00333
00334 if(ns > 0 && FD_ISSET(STDIN_FILENO, &fds)) {
00335 char c;
00336 if(read(STDIN_FILENO, &c, 1) == 1) {
00337 switch(c) {
00338 case 'q':
00339 return 0;
00340 break;
00341 }
00342 }
00343 }
00344 }
00345
00346 return 0;
00347 }
00348