diff --git a/commands/simple/Makefile b/commands/simple/Makefile index eac38e2ca..143f6991e 100755 --- a/commands/simple/Makefile +++ b/commands/simple/Makefile @@ -188,6 +188,7 @@ ALL = \ tget \ time \ touch \ + top \ tr \ truncate \ treecmp \ @@ -808,6 +809,9 @@ touch: touch.c $(CCLD) -o $@ $? @install -S 4kw $@ +top: top.c + $(CCLD) -o $@ $? + tr: tr.c $(CCLD) -o $@ $? @install -S 4kw $@ @@ -1077,6 +1081,7 @@ install: \ /usr/bin/termcap \ /usr/bin/tget \ /usr/bin/time \ + /usr/bin/top \ /usr/bin/touch \ /usr/bin/tr \ /usr/bin/treecmp \ @@ -1610,6 +1615,9 @@ install: \ /usr/bin/time: time install -cs -o bin $? $@ +/usr/bin/top: top + install -cs -o bin $? $@ + /usr/bin/touch: touch install -cs -o bin $? $@ diff --git a/commands/simple/top.c b/commands/simple/top.c new file mode 100644 index 000000000..ca4443374 --- /dev/null +++ b/commands/simple/top.c @@ -0,0 +1,259 @@ + +#define _MINIX 1 +#define _POSIX_SOURCE 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "../../servers/pm/mproc.h" +#include "../../kernel/const.h" +#include "../../kernel/proc.h" + +char *Tclr_all; +#define TC_BUFFER 1024 /* Size of termcap(3) buffer */ +#define TC_STRINGS 200 /* Enough room for cm,cl,so,se */ + +int print_memory(struct pm_mem_info *pmi) +{ + int h; + int largest_bytes = 0, total_bytes = 0; + for(h = 0; h < _NR_HOLES; h++) { + if(pmi->pmi_holes[h].h_base && pmi->pmi_holes[h].h_len) { + int bytes; + bytes = pmi->pmi_holes[h].h_len << CLICK_SHIFT; + if(bytes > largest_bytes) largest_bytes = bytes; + total_bytes += bytes; + } + } + + printf("Mem: %dK Free, %dK Contiguous Free\n", + total_bytes/1024, largest_bytes/1024); + + return 1; +} + +int print_load(double *loads, int nloads) +{ + int i; + printf("load averages: "); + for(i = 0; i < nloads; i++) + printf("%s %.2f", (i > 0) ? "," : "", loads[i]); + printf("\n"); + return 1; +} + +#define PROCS (NR_PROCS+NR_TASKS) + +int print_proc_summary(struct proc *proc) +{ + int p, alive, running, sleeping; + + alive = running = sleeping = 0; + + for(p = 0; p < PROCS; p++) { + if(p - NR_TASKS == IDLE) + continue; + if(proc[p].p_rts_flags & SLOT_FREE) + continue; + alive++; + if(proc[p].p_rts_flags & ~SLOT_FREE) + sleeping++; + else + running++; + } + printf("%d processes: %d running, %d sleeping\n", + alive, running, sleeping); + return 1; +} + +static struct tp { + struct proc *p; + int ticks; +} tick_procs[PROCS]; + +int cmp_ticks(const void *v1, const void *v2) +{ + struct tp *p1 = (struct tp *) v1, *p2 = (struct tp *) v2; + if(p1->ticks < p2->ticks) + return 1; + if(p1->ticks > p2->ticks) + return -1; + if(p1->p->p_nr < p2->p->p_nr) + return -1; + if(p1->p->p_nr > p2->p->p_nr) + return 1; + return 0; +} + +void print_procs(int maxlines, + struct proc *proc1, struct proc *proc2, int dt, + struct mproc *mproc) +{ + int p, nprocs; + int idleticks = 0; + + for(p = nprocs = 0; p < PROCS; p++) { + if(proc2[p].p_rts_flags & SLOT_FREE) + continue; + tick_procs[nprocs].p = proc2 + p; + tick_procs[nprocs].ticks = + proc2[p].p_user_time-proc1[p].p_user_time; + if(p-NR_TASKS == IDLE) { + idleticks = tick_procs[nprocs].ticks; + continue; + } + nprocs++; + } + + qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_ticks); + + printf("CPU states: %5.2f%% user, %5.2f%% idle\n\n", + 100.0*(dt-idleticks)/dt, 100.0*idleticks/dt); + maxlines -= 2; + + printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND\n"); + maxlines--; + for(p = 0; p < nprocs; p++) { + int euid = 0; + struct passwd *who = NULL; + struct proc *pr; + int pnr, ticks; + char *name = ""; + + if(maxlines-- <= 0) break; + + pnr = tick_procs[p].p->p_nr; + pr = tick_procs[p].p; + ticks = pr->p_user_time; + if(pnr >= 0) { + printf("%5d ", mproc[pnr].mp_pid); + euid = mproc[pnr].mp_effuid; + name = mproc[pnr].mp_name; + } else { + printf("[%3d] ", pnr); + name = pr->p_name; + } + who = getpwuid(euid); + + if(who && who->pw_name) printf("%-8s ", who->pw_name); + else if(pnr >= 0) printf("%8d ", mproc[pnr].mp_effuid); + else printf(" "); + + printf(" %2d ", pr->p_priority); + if(pnr >= 0) { + printf(" %3d ", mproc[pnr].mp_nice); + } else printf(" "); + printf("%5dK", + ((pr->p_memmap[T].mem_len + + pr->p_memmap[D].mem_len) << CLICK_SHIFT)/1024); + printf("%6s", pr->p_rts_flags ? "" : "RUN"); + printf(" %3d:%02d ", (ticks/HZ/60), (ticks/HZ)%60); + + printf("%5.2f%% %s\n", + 100.0*tick_procs[p].ticks/dt, name); + } +} + +void showtop(void) +{ +#define NLOADS 3 + double loads[NLOADS]; + int nloads, i, p, lines = 0; + static struct proc prev_proc[PROCS], proc[PROCS]; + struct winsize winsize; + static struct pm_mem_info pmi; + static int prev_uptime, uptime; + static struct mproc mproc[NR_PROCS]; + struct tms tms; + + uptime = times(&tms); + + if(ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize) != 0) { + perror("TIOCGWINSZ"); + fprintf(stderr, "TIOCGWINSZ failed\n"); + exit(1); + } + + if(getsysinfo(PM_PROC_NR, SI_MEM_ALLOC, &pmi) < 0) { + fprintf(stderr, "getsysinfo() for SI_MEM_ALLOC failed.\n"); + exit(1);; + } + + if(getsysinfo(PM_PROC_NR, SI_KPROC_TAB, proc) < 0) { + fprintf(stderr, "getsysinfo() for SI_KPROC_TAB failed.\n"); + exit(1); + } + + if(getsysinfo(PM_PROC_NR, SI_PROC_TAB, mproc) < 0) { + fprintf(stderr, "getsysinfo() for SI_PROC_TAB failed.\n"); + exit(1); + } + + if((nloads = getloadavg(loads, NLOADS)) != NLOADS) { + fprintf(stderr, "getloadavg() failed - %d loads\n", nloads); + exit(1); + } + + + + printf("%s", Tclr_all); + + lines += print_load(loads, NLOADS); + lines += print_proc_summary(proc); + lines += print_memory(&pmi); + + print_procs(winsize.ws_row - lines - 2, prev_proc, + proc, uptime-prev_uptime, mproc); + + memcpy(prev_proc, proc, sizeof(prev_proc)); + prev_uptime = uptime; +} + +void init(void) +{ + char *term; + static char buffer[TC_BUFFER], strings[TC_STRINGS]; + char *s = strings; + + if(!(term = getenv("TERM"))) { + fprintf(stderr, "No TERM set\n"); + exit(1); + } + + if ( tgetent( buffer, term ) != 1 ) { + fprintf(stderr, "tgetent failed for term %s\n", term); + exit(1); + } + + if ( (Tclr_all = tgetstr( "cl", &s )) == NULL ) + Tclr_all = "\f"; +} + +int main(int argc, char *argv[]) +{ + init(); + + while(1) { + showtop(); + sleep(5); + } +} +