1b89261baSDavid van Moolenbroek
2b89261baSDavid van Moolenbroek /* Author: Ben Gras <beng@few.vu.nl> 17 march 2006 */
3b89261baSDavid van Moolenbroek
4b89261baSDavid van Moolenbroek #define _MINIX_SYSTEM 1
5b89261baSDavid van Moolenbroek
6b89261baSDavid van Moolenbroek #include <stdio.h>
7b89261baSDavid van Moolenbroek #include <unistd.h>
8b89261baSDavid van Moolenbroek #include <pwd.h>
9b89261baSDavid van Moolenbroek #include <curses.h>
10b89261baSDavid van Moolenbroek #include <minix/timers.h>
11b89261baSDavid van Moolenbroek #include <stdlib.h>
12b89261baSDavid van Moolenbroek #include <limits.h>
13b89261baSDavid van Moolenbroek #include <termcap.h>
14b89261baSDavid van Moolenbroek #include <termios.h>
15b89261baSDavid van Moolenbroek #include <time.h>
16b89261baSDavid van Moolenbroek #include <string.h>
17b89261baSDavid van Moolenbroek #include <signal.h>
18b89261baSDavid van Moolenbroek #include <fcntl.h>
19b89261baSDavid van Moolenbroek #include <errno.h>
20b89261baSDavid van Moolenbroek #include <dirent.h>
21b89261baSDavid van Moolenbroek #include <assert.h>
22b89261baSDavid van Moolenbroek
23b89261baSDavid van Moolenbroek #include <sys/ttycom.h>
24b89261baSDavid van Moolenbroek #include <sys/ioctl.h>
25b89261baSDavid van Moolenbroek #include <sys/times.h>
26b89261baSDavid van Moolenbroek #include <sys/types.h>
27b89261baSDavid van Moolenbroek #include <sys/time.h>
28b89261baSDavid van Moolenbroek #include <sys/select.h>
29b89261baSDavid van Moolenbroek
30b89261baSDavid van Moolenbroek #include <minix/com.h>
31b89261baSDavid van Moolenbroek #include <minix/config.h>
32b89261baSDavid van Moolenbroek #include <minix/type.h>
33b89261baSDavid van Moolenbroek #include <minix/endpoint.h>
34b89261baSDavid van Moolenbroek #include <minix/const.h>
35b89261baSDavid van Moolenbroek #include <minix/u64.h>
36b89261baSDavid van Moolenbroek #include <minix/paths.h>
37b89261baSDavid van Moolenbroek #include <minix/procfs.h>
38b89261baSDavid van Moolenbroek
39b89261baSDavid van Moolenbroek #define TIMECYCLEKEY 't'
40b89261baSDavid van Moolenbroek #define ORDERKEY 'o'
41b89261baSDavid van Moolenbroek
42b89261baSDavid van Moolenbroek #define ORDER_CPU 0
43b89261baSDavid van Moolenbroek #define ORDER_MEMORY 1
44b89261baSDavid van Moolenbroek #define ORDER_HIGHEST ORDER_MEMORY
45b89261baSDavid van Moolenbroek int order = ORDER_CPU;
46b89261baSDavid van Moolenbroek
47b89261baSDavid van Moolenbroek u32_t system_hz;
48b89261baSDavid van Moolenbroek
49b89261baSDavid van Moolenbroek /* name of cpu cycle types, in the order they appear in /psinfo. */
50b89261baSDavid van Moolenbroek const char *cputimenames[] = { "user", "ipc", "kernelcall" };
51b89261baSDavid van Moolenbroek
52b89261baSDavid van Moolenbroek #define CPUTIMENAMES ((int) (sizeof(cputimenames)/sizeof(cputimenames[0])))
53b89261baSDavid van Moolenbroek
54b89261baSDavid van Moolenbroek #define CPUTIME(m, i) (m & (1L << (i)))
55b89261baSDavid van Moolenbroek
56b89261baSDavid van Moolenbroek unsigned int nr_procs, nr_tasks;
57b89261baSDavid van Moolenbroek int nr_total;
58b89261baSDavid van Moolenbroek
59b89261baSDavid van Moolenbroek #define SLOT_NR(e) (_ENDPOINT_P(e) + nr_tasks)
60b89261baSDavid van Moolenbroek
61b89261baSDavid van Moolenbroek #define TC_BUFFER 1024 /* Size of termcap(3) buffer */
62b89261baSDavid van Moolenbroek #define TC_STRINGS 200 /* Enough room for cm,cl,so,se */
63b89261baSDavid van Moolenbroek
64b89261baSDavid van Moolenbroek const char *Tclr_all;
65b89261baSDavid van Moolenbroek
66b89261baSDavid van Moolenbroek int blockedverbose = 0;
67b89261baSDavid van Moolenbroek
68b89261baSDavid van Moolenbroek #define USED 0x1
69b89261baSDavid van Moolenbroek #define IS_TASK 0x2
70b89261baSDavid van Moolenbroek #define IS_SYSTEM 0x4
71b89261baSDavid van Moolenbroek #define BLOCKED 0x8
72b89261baSDavid van Moolenbroek
73b89261baSDavid van Moolenbroek struct proc {
74b89261baSDavid van Moolenbroek int p_flags;
75b89261baSDavid van Moolenbroek endpoint_t p_endpoint;
76b89261baSDavid van Moolenbroek pid_t p_pid;
77b89261baSDavid van Moolenbroek u64_t p_cpucycles[CPUTIMENAMES];
78b89261baSDavid van Moolenbroek int p_priority;
79b89261baSDavid van Moolenbroek endpoint_t p_blocked;
80*305e366fSDavid van Moolenbroek clock_t p_user_time;
81b89261baSDavid van Moolenbroek vir_bytes p_memory;
82b89261baSDavid van Moolenbroek uid_t p_effuid;
83b89261baSDavid van Moolenbroek int p_nice;
84b89261baSDavid van Moolenbroek char p_name[PROC_NAME_LEN+1];
85b89261baSDavid van Moolenbroek };
86b89261baSDavid van Moolenbroek
87b89261baSDavid van Moolenbroek struct proc *proc = NULL, *prev_proc = NULL;
88b89261baSDavid van Moolenbroek
89*305e366fSDavid van Moolenbroek static void
parse_file(pid_t pid)90*305e366fSDavid van Moolenbroek parse_file(pid_t pid)
91b89261baSDavid van Moolenbroek {
92b89261baSDavid van Moolenbroek char path[PATH_MAX], name[256], type, state;
93*305e366fSDavid van Moolenbroek int version, endpt;
94b89261baSDavid van Moolenbroek FILE *fp;
95b89261baSDavid van Moolenbroek struct proc *p;
96b89261baSDavid van Moolenbroek int slot;
97b89261baSDavid van Moolenbroek
98b89261baSDavid van Moolenbroek sprintf(path, "%d/psinfo", pid);
99b89261baSDavid van Moolenbroek
100b89261baSDavid van Moolenbroek if ((fp = fopen(path, "r")) == NULL)
101b89261baSDavid van Moolenbroek return;
102b89261baSDavid van Moolenbroek
103b89261baSDavid van Moolenbroek if (fscanf(fp, "%d", &version) != 1) {
104b89261baSDavid van Moolenbroek fclose(fp);
105b89261baSDavid van Moolenbroek return;
106b89261baSDavid van Moolenbroek }
107b89261baSDavid van Moolenbroek
108b89261baSDavid van Moolenbroek if (version != PSINFO_VERSION) {
109b89261baSDavid van Moolenbroek fputs("procfs version mismatch!\n", stderr);
110b89261baSDavid van Moolenbroek exit(1);
111b89261baSDavid van Moolenbroek }
112b89261baSDavid van Moolenbroek
113b89261baSDavid van Moolenbroek if (fscanf(fp, " %c %d", &type, &endpt) != 2) {
114b89261baSDavid van Moolenbroek fclose(fp);
115b89261baSDavid van Moolenbroek return;
116b89261baSDavid van Moolenbroek }
117b89261baSDavid van Moolenbroek
118b89261baSDavid van Moolenbroek slot = SLOT_NR(endpt);
119b89261baSDavid van Moolenbroek
120b89261baSDavid van Moolenbroek if (slot < 0 || slot >= nr_total) {
121*305e366fSDavid van Moolenbroek fprintf(stderr, "top: unreasonable endpoint number %d\n",
122*305e366fSDavid van Moolenbroek endpt);
123b89261baSDavid van Moolenbroek fclose(fp);
124b89261baSDavid van Moolenbroek return;
125b89261baSDavid van Moolenbroek }
126b89261baSDavid van Moolenbroek
127b89261baSDavid van Moolenbroek p = &proc[slot];
128b89261baSDavid van Moolenbroek
129b89261baSDavid van Moolenbroek if (type == TYPE_TASK)
130b89261baSDavid van Moolenbroek p->p_flags |= IS_TASK;
131b89261baSDavid van Moolenbroek else if (type == TYPE_SYSTEM)
132b89261baSDavid van Moolenbroek p->p_flags |= IS_SYSTEM;
133b89261baSDavid van Moolenbroek
134b89261baSDavid van Moolenbroek p->p_endpoint = endpt;
135b89261baSDavid van Moolenbroek p->p_pid = pid;
136b89261baSDavid van Moolenbroek
137*305e366fSDavid van Moolenbroek if (fscanf(fp, " %255s %c %d %d %u %*u %"PRIu64" %"PRIu64" %"PRIu64
138*305e366fSDavid van Moolenbroek " %lu %d %u",
139*305e366fSDavid van Moolenbroek name, &state, &p->p_blocked, &p->p_priority, &p->p_user_time,
140*305e366fSDavid van Moolenbroek &p->p_cpucycles[0], &p->p_cpucycles[1], &p->p_cpucycles[2],
141*305e366fSDavid van Moolenbroek &p->p_memory, &p->p_nice, &p->p_effuid) != 11) {
142b89261baSDavid van Moolenbroek fclose(fp);
143b89261baSDavid van Moolenbroek return;
144b89261baSDavid van Moolenbroek }
145b89261baSDavid van Moolenbroek
146*305e366fSDavid van Moolenbroek strlcpy(p->p_name, name, sizeof(p->p_name));
147b89261baSDavid van Moolenbroek
148b89261baSDavid van Moolenbroek if (state != STATE_RUN)
149b89261baSDavid van Moolenbroek p->p_flags |= BLOCKED;
150b89261baSDavid van Moolenbroek
151b89261baSDavid van Moolenbroek p->p_flags |= USED;
152b89261baSDavid van Moolenbroek
153b89261baSDavid van Moolenbroek fclose(fp);
154b89261baSDavid van Moolenbroek }
155b89261baSDavid van Moolenbroek
parse_dir(void)156b89261baSDavid van Moolenbroek static void parse_dir(void)
157b89261baSDavid van Moolenbroek {
158b89261baSDavid van Moolenbroek DIR *p_dir;
159b89261baSDavid van Moolenbroek struct dirent *p_ent;
160b89261baSDavid van Moolenbroek pid_t pid;
161b89261baSDavid van Moolenbroek char *end;
162b89261baSDavid van Moolenbroek
163b89261baSDavid van Moolenbroek if ((p_dir = opendir(".")) == NULL) {
164b89261baSDavid van Moolenbroek perror("opendir on " _PATH_PROC);
165b89261baSDavid van Moolenbroek exit(1);
166b89261baSDavid van Moolenbroek }
167b89261baSDavid van Moolenbroek
168b89261baSDavid van Moolenbroek for (p_ent = readdir(p_dir); p_ent != NULL; p_ent = readdir(p_dir)) {
169b89261baSDavid van Moolenbroek pid = strtol(p_ent->d_name, &end, 10);
170b89261baSDavid van Moolenbroek
171b89261baSDavid van Moolenbroek if (!end[0] && pid != 0)
172b89261baSDavid van Moolenbroek parse_file(pid);
173b89261baSDavid van Moolenbroek }
174b89261baSDavid van Moolenbroek
175b89261baSDavid van Moolenbroek closedir(p_dir);
176b89261baSDavid van Moolenbroek }
177b89261baSDavid van Moolenbroek
get_procs(void)178b89261baSDavid van Moolenbroek static void get_procs(void)
179b89261baSDavid van Moolenbroek {
180b89261baSDavid van Moolenbroek struct proc *p;
181b89261baSDavid van Moolenbroek int i;
182b89261baSDavid van Moolenbroek
183b89261baSDavid van Moolenbroek p = prev_proc;
184b89261baSDavid van Moolenbroek prev_proc = proc;
185b89261baSDavid van Moolenbroek proc = p;
186b89261baSDavid van Moolenbroek
187b89261baSDavid van Moolenbroek if (proc == NULL) {
188b89261baSDavid van Moolenbroek proc = malloc(nr_total * sizeof(proc[0]));
189b89261baSDavid van Moolenbroek
190b89261baSDavid van Moolenbroek if (proc == NULL) {
191b89261baSDavid van Moolenbroek fprintf(stderr, "Out of memory!\n");
192b89261baSDavid van Moolenbroek exit(1);
193b89261baSDavid van Moolenbroek }
194b89261baSDavid van Moolenbroek }
195b89261baSDavid van Moolenbroek
196b89261baSDavid van Moolenbroek for (i = 0; i < nr_total; i++)
197b89261baSDavid van Moolenbroek proc[i].p_flags = 0;
198b89261baSDavid van Moolenbroek
199b89261baSDavid van Moolenbroek parse_dir();
200b89261baSDavid van Moolenbroek }
201b89261baSDavid van Moolenbroek
print_memory(void)202b89261baSDavid van Moolenbroek static int print_memory(void)
203b89261baSDavid van Moolenbroek {
204b89261baSDavid van Moolenbroek FILE *fp;
205b89261baSDavid van Moolenbroek unsigned int pagesize;
206b89261baSDavid van Moolenbroek unsigned long total, freemem, largest, cached;
207b89261baSDavid van Moolenbroek
208b89261baSDavid van Moolenbroek if ((fp = fopen("meminfo", "r")) == NULL)
209b89261baSDavid van Moolenbroek return 0;
210b89261baSDavid van Moolenbroek
211b89261baSDavid van Moolenbroek if (fscanf(fp, "%u %lu %lu %lu %lu", &pagesize, &total, &freemem,
212b89261baSDavid van Moolenbroek &largest, &cached) != 5) {
213b89261baSDavid van Moolenbroek fclose(fp);
214b89261baSDavid van Moolenbroek return 0;
215b89261baSDavid van Moolenbroek }
216b89261baSDavid van Moolenbroek
217b89261baSDavid van Moolenbroek fclose(fp);
218b89261baSDavid van Moolenbroek
219b89261baSDavid van Moolenbroek printf("main memory: %ldK total, %ldK free, %ldK contig free, "
220b89261baSDavid van Moolenbroek "%ldK cached\n",
221b89261baSDavid van Moolenbroek (pagesize * total)/1024, (pagesize * freemem)/1024,
222b89261baSDavid van Moolenbroek (pagesize * largest)/1024, (pagesize * cached)/1024);
223b89261baSDavid van Moolenbroek
224b89261baSDavid van Moolenbroek return 1;
225b89261baSDavid van Moolenbroek }
226b89261baSDavid van Moolenbroek
print_load(double * loads,int nloads)227b89261baSDavid van Moolenbroek static int print_load(double *loads, int nloads)
228b89261baSDavid van Moolenbroek {
229b89261baSDavid van Moolenbroek int i;
230b89261baSDavid van Moolenbroek printf("load averages: ");
231b89261baSDavid van Moolenbroek for(i = 0; i < nloads; i++)
232b89261baSDavid van Moolenbroek printf("%s %.2f", (i > 0) ? "," : "", loads[i]);
233b89261baSDavid van Moolenbroek printf("\n");
234b89261baSDavid van Moolenbroek return 1;
235b89261baSDavid van Moolenbroek }
236b89261baSDavid van Moolenbroek
print_proc_summary(struct proc * pproc)237b89261baSDavid van Moolenbroek static int print_proc_summary(struct proc *pproc)
238b89261baSDavid van Moolenbroek {
239b89261baSDavid van Moolenbroek int p, alive, running, sleeping;
240b89261baSDavid van Moolenbroek
241b89261baSDavid van Moolenbroek alive = running = sleeping = 0;
242b89261baSDavid van Moolenbroek
243b89261baSDavid van Moolenbroek for(p = 0; p < nr_total; p++) {
244b89261baSDavid van Moolenbroek if (pproc[p].p_endpoint == IDLE)
245b89261baSDavid van Moolenbroek continue;
246b89261baSDavid van Moolenbroek if(!(pproc[p].p_flags & USED))
247b89261baSDavid van Moolenbroek continue;
248b89261baSDavid van Moolenbroek alive++;
249b89261baSDavid van Moolenbroek if(pproc[p].p_flags & BLOCKED)
250b89261baSDavid van Moolenbroek sleeping++;
251b89261baSDavid van Moolenbroek else
252b89261baSDavid van Moolenbroek running++;
253b89261baSDavid van Moolenbroek }
254b89261baSDavid van Moolenbroek printf("%d processes: %d running, %d sleeping\n",
255b89261baSDavid van Moolenbroek alive, running, sleeping);
256b89261baSDavid van Moolenbroek return 1;
257b89261baSDavid van Moolenbroek }
258b89261baSDavid van Moolenbroek
259b89261baSDavid van Moolenbroek struct tp {
260b89261baSDavid van Moolenbroek struct proc *p;
261b89261baSDavid van Moolenbroek u64_t ticks;
262b89261baSDavid van Moolenbroek };
263b89261baSDavid van Moolenbroek
cmp_procs(const void * v1,const void * v2)264b89261baSDavid van Moolenbroek static int cmp_procs(const void *v1, const void *v2)
265b89261baSDavid van Moolenbroek {
266b89261baSDavid van Moolenbroek const struct tp *p1 = (const struct tp *) v1,
267b89261baSDavid van Moolenbroek *p2 = (const struct tp *) v2;
268b89261baSDavid van Moolenbroek int p1blocked, p2blocked;
269b89261baSDavid van Moolenbroek
270b89261baSDavid van Moolenbroek if(order == ORDER_MEMORY) {
271b89261baSDavid van Moolenbroek if(p1->p->p_memory < p2->p->p_memory) return 1;
272b89261baSDavid van Moolenbroek if(p1->p->p_memory > p2->p->p_memory) return -1;
273b89261baSDavid van Moolenbroek return 0;
274b89261baSDavid van Moolenbroek }
275b89261baSDavid van Moolenbroek
276b89261baSDavid van Moolenbroek p1blocked = !!(p1->p->p_flags & BLOCKED);
277b89261baSDavid van Moolenbroek p2blocked = !!(p2->p->p_flags & BLOCKED);
278b89261baSDavid van Moolenbroek
279b89261baSDavid van Moolenbroek /* Primarily order by used number of cpu cycles.
280b89261baSDavid van Moolenbroek *
281b89261baSDavid van Moolenbroek * Exception: if in blockedverbose mode, a blocked
282b89261baSDavid van Moolenbroek * process is always printed after an unblocked
283b89261baSDavid van Moolenbroek * process, and used cpu cycles don't matter.
284b89261baSDavid van Moolenbroek *
285b89261baSDavid van Moolenbroek * In both cases, process slot number is a tie breaker.
286b89261baSDavid van Moolenbroek */
287b89261baSDavid van Moolenbroek
288b89261baSDavid van Moolenbroek if(blockedverbose && (p1blocked || p2blocked)) {
289b89261baSDavid van Moolenbroek if(!p1blocked && p2blocked)
290b89261baSDavid van Moolenbroek return -1;
291b89261baSDavid van Moolenbroek if(!p2blocked && p1blocked)
292b89261baSDavid van Moolenbroek return 1;
293b89261baSDavid van Moolenbroek } else if(p1->ticks != p2->ticks) {
294b89261baSDavid van Moolenbroek if(p1->ticks > p2->ticks) return -1;
295b89261baSDavid van Moolenbroek assert(p1->ticks < p2->ticks);
296b89261baSDavid van Moolenbroek return 1;
297b89261baSDavid van Moolenbroek }
298b89261baSDavid van Moolenbroek
299b89261baSDavid van Moolenbroek /* Process slot number is a tie breaker. */
300b89261baSDavid van Moolenbroek return (int) (p1->p - p2->p);
301b89261baSDavid van Moolenbroek }
302b89261baSDavid van Moolenbroek
lookup(endpoint_t who,struct tp * tptab,int np)303b89261baSDavid van Moolenbroek static struct tp *lookup(endpoint_t who, struct tp *tptab, int np)
304b89261baSDavid van Moolenbroek {
305b89261baSDavid van Moolenbroek int t;
306b89261baSDavid van Moolenbroek
307b89261baSDavid van Moolenbroek for(t = 0; t < np; t++)
308b89261baSDavid van Moolenbroek if(who == tptab[t].p->p_endpoint)
309b89261baSDavid van Moolenbroek return &tptab[t];
310b89261baSDavid van Moolenbroek
311b89261baSDavid van Moolenbroek fprintf(stderr, "lookup: tp %d (0x%x) not found.\n", who, who);
312b89261baSDavid van Moolenbroek abort();
313b89261baSDavid van Moolenbroek
314b89261baSDavid van Moolenbroek return NULL;
315b89261baSDavid van Moolenbroek }
316b89261baSDavid van Moolenbroek
317b89261baSDavid van Moolenbroek double ktotal = 0;
318b89261baSDavid van Moolenbroek
print_proc(struct tp * tp,u64_t total_ticks)319b89261baSDavid van Moolenbroek static void print_proc(struct tp *tp, u64_t total_ticks)
320b89261baSDavid van Moolenbroek {
321b89261baSDavid van Moolenbroek int euid = 0;
322b89261baSDavid van Moolenbroek static struct passwd *who = NULL;
323b89261baSDavid van Moolenbroek static int last_who = -1;
324b89261baSDavid van Moolenbroek const char *name = "";
325b89261baSDavid van Moolenbroek int ticks;
326b89261baSDavid van Moolenbroek struct proc *pr = tp->p;
327b89261baSDavid van Moolenbroek
328b89261baSDavid van Moolenbroek printf("%5d ", pr->p_pid);
329b89261baSDavid van Moolenbroek euid = pr->p_effuid;
330b89261baSDavid van Moolenbroek name = pr->p_name;
331b89261baSDavid van Moolenbroek
332b89261baSDavid van Moolenbroek if(last_who != euid || !who) {
333b89261baSDavid van Moolenbroek who = getpwuid(euid);
334b89261baSDavid van Moolenbroek last_who = euid;
335b89261baSDavid van Moolenbroek }
336b89261baSDavid van Moolenbroek
337b89261baSDavid van Moolenbroek if(who && who->pw_name) printf("%-8s ", who->pw_name);
338b89261baSDavid van Moolenbroek else if(!(pr->p_flags & IS_TASK)) printf("%8d ", pr->p_effuid);
339b89261baSDavid van Moolenbroek else printf(" ");
340b89261baSDavid van Moolenbroek
341b89261baSDavid van Moolenbroek printf(" %2d ", pr->p_priority);
342b89261baSDavid van Moolenbroek if(!(pr->p_flags & IS_TASK)) {
343b89261baSDavid van Moolenbroek printf(" %3d ", pr->p_nice);
344b89261baSDavid van Moolenbroek } else printf(" ");
345b89261baSDavid van Moolenbroek printf("%6ldK", (pr->p_memory + 512) / 1024);
346b89261baSDavid van Moolenbroek printf("%6s", (pr->p_flags & BLOCKED) ? "" : "RUN");
347b89261baSDavid van Moolenbroek ticks = pr->p_user_time;
348b89261baSDavid van Moolenbroek printf(" %3u:%02u ", (ticks/system_hz/60), (ticks/system_hz)%60);
349b89261baSDavid van Moolenbroek
350b89261baSDavid van Moolenbroek printf("%6.2f%% %s", 100.0 * tp->ticks / total_ticks, name);
351b89261baSDavid van Moolenbroek }
352b89261baSDavid van Moolenbroek
cputimemodename(int cputimemode)353b89261baSDavid van Moolenbroek static char *cputimemodename(int cputimemode)
354b89261baSDavid van Moolenbroek {
355b89261baSDavid van Moolenbroek static char name[100];
356b89261baSDavid van Moolenbroek int i;
357b89261baSDavid van Moolenbroek
358b89261baSDavid van Moolenbroek name[0] = '\0';
359b89261baSDavid van Moolenbroek
360b89261baSDavid van Moolenbroek for(i = 0; i < CPUTIMENAMES; i++) {
361b89261baSDavid van Moolenbroek if(CPUTIME(cputimemode, i)) {
362b89261baSDavid van Moolenbroek assert(strlen(name) +
363b89261baSDavid van Moolenbroek strlen(cputimenames[i]) < sizeof(name));
364b89261baSDavid van Moolenbroek strcat(name, cputimenames[i]);
365b89261baSDavid van Moolenbroek strcat(name, " ");
366b89261baSDavid van Moolenbroek }
367b89261baSDavid van Moolenbroek }
368b89261baSDavid van Moolenbroek
369b89261baSDavid van Moolenbroek return name;
370b89261baSDavid van Moolenbroek }
371b89261baSDavid van Moolenbroek
cputicks(struct proc * p1,struct proc * p2,int timemode)372b89261baSDavid van Moolenbroek static u64_t cputicks(struct proc *p1, struct proc *p2, int timemode)
373b89261baSDavid van Moolenbroek {
374b89261baSDavid van Moolenbroek int i;
375b89261baSDavid van Moolenbroek u64_t t = 0;
376b89261baSDavid van Moolenbroek for(i = 0; i < CPUTIMENAMES; i++) {
377b89261baSDavid van Moolenbroek if(!CPUTIME(timemode, i))
378b89261baSDavid van Moolenbroek continue;
379b89261baSDavid van Moolenbroek if(p1->p_endpoint == p2->p_endpoint) {
380b89261baSDavid van Moolenbroek t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i];
381b89261baSDavid van Moolenbroek } else {
382b89261baSDavid van Moolenbroek t = t + p2->p_cpucycles[i];
383b89261baSDavid van Moolenbroek }
384b89261baSDavid van Moolenbroek }
385b89261baSDavid van Moolenbroek
386b89261baSDavid van Moolenbroek return t;
387b89261baSDavid van Moolenbroek }
388b89261baSDavid van Moolenbroek
ordername(int orderno)389b89261baSDavid van Moolenbroek static const char *ordername(int orderno)
390b89261baSDavid van Moolenbroek {
391b89261baSDavid van Moolenbroek switch(orderno) {
392b89261baSDavid van Moolenbroek case ORDER_CPU: return "cpu";
393b89261baSDavid van Moolenbroek case ORDER_MEMORY: return "memory";
394b89261baSDavid van Moolenbroek }
395b89261baSDavid van Moolenbroek return "invalid order";
396b89261baSDavid van Moolenbroek }
397b89261baSDavid van Moolenbroek
print_procs(int maxlines,struct proc * proc1,struct proc * proc2,int cputimemode)398b89261baSDavid van Moolenbroek static void print_procs(int maxlines,
399b89261baSDavid van Moolenbroek struct proc *proc1, struct proc *proc2, int cputimemode)
400b89261baSDavid van Moolenbroek {
401b89261baSDavid van Moolenbroek int p, nprocs;
402b89261baSDavid van Moolenbroek u64_t idleticks = 0;
403b89261baSDavid van Moolenbroek u64_t kernelticks = 0;
404b89261baSDavid van Moolenbroek u64_t systemticks = 0;
405b89261baSDavid van Moolenbroek u64_t userticks = 0;
406b89261baSDavid van Moolenbroek u64_t total_ticks = 0;
407b89261baSDavid van Moolenbroek int blockedseen = 0;
408b89261baSDavid van Moolenbroek static struct tp *tick_procs = NULL;
409b89261baSDavid van Moolenbroek
410b89261baSDavid van Moolenbroek if (tick_procs == NULL) {
411b89261baSDavid van Moolenbroek tick_procs = malloc(nr_total * sizeof(tick_procs[0]));
412b89261baSDavid van Moolenbroek
413b89261baSDavid van Moolenbroek if (tick_procs == NULL) {
414b89261baSDavid van Moolenbroek fprintf(stderr, "Out of memory!\n");
415b89261baSDavid van Moolenbroek exit(1);
416b89261baSDavid van Moolenbroek }
417b89261baSDavid van Moolenbroek }
418b89261baSDavid van Moolenbroek
419b89261baSDavid van Moolenbroek for(p = nprocs = 0; p < nr_total; p++) {
420b89261baSDavid van Moolenbroek u64_t uticks;
421b89261baSDavid van Moolenbroek if(!(proc2[p].p_flags & USED))
422b89261baSDavid van Moolenbroek continue;
423b89261baSDavid van Moolenbroek tick_procs[nprocs].p = proc2 + p;
424b89261baSDavid van Moolenbroek tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p], cputimemode);
425b89261baSDavid van Moolenbroek uticks = cputicks(&proc1[p], &proc2[p], 1);
426b89261baSDavid van Moolenbroek total_ticks = total_ticks + uticks;
427b89261baSDavid van Moolenbroek if(p-NR_TASKS == IDLE) {
428b89261baSDavid van Moolenbroek idleticks = uticks;
429b89261baSDavid van Moolenbroek continue;
430b89261baSDavid van Moolenbroek }
431b89261baSDavid van Moolenbroek if(p-NR_TASKS == KERNEL) {
432b89261baSDavid van Moolenbroek kernelticks = uticks;
433b89261baSDavid van Moolenbroek }
434b89261baSDavid van Moolenbroek if(!(proc2[p].p_flags & IS_TASK)) {
435b89261baSDavid van Moolenbroek if(proc2[p].p_flags & IS_SYSTEM)
436b89261baSDavid van Moolenbroek systemticks = systemticks + tick_procs[nprocs].ticks;
437b89261baSDavid van Moolenbroek else
438b89261baSDavid van Moolenbroek userticks = userticks + tick_procs[nprocs].ticks;
439b89261baSDavid van Moolenbroek }
440b89261baSDavid van Moolenbroek
441b89261baSDavid van Moolenbroek nprocs++;
442b89261baSDavid van Moolenbroek }
443b89261baSDavid van Moolenbroek
444b89261baSDavid van Moolenbroek if (total_ticks == 0)
445b89261baSDavid van Moolenbroek return;
446b89261baSDavid van Moolenbroek
447b89261baSDavid van Moolenbroek qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_procs);
448b89261baSDavid van Moolenbroek
449b89261baSDavid van Moolenbroek printf("CPU states: %6.2f%% user, ", 100.0 * userticks / total_ticks);
450b89261baSDavid van Moolenbroek printf("%6.2f%% system, ", 100.0 * systemticks / total_ticks);
451b89261baSDavid van Moolenbroek printf("%6.2f%% kernel, ", 100.0 * kernelticks/ total_ticks);
452b89261baSDavid van Moolenbroek printf("%6.2f%% idle", 100.0 * idleticks / total_ticks);
453b89261baSDavid van Moolenbroek
454b89261baSDavid van Moolenbroek #define NEWLINE do { printf("\n"); if(--maxlines <= 0) { return; } } while(0)
455b89261baSDavid van Moolenbroek NEWLINE;
456b89261baSDavid van Moolenbroek
457b89261baSDavid van Moolenbroek printf("CPU time displayed ('%c' to cycle): %s; ",
458b89261baSDavid van Moolenbroek TIMECYCLEKEY, cputimemodename(cputimemode));
459b89261baSDavid van Moolenbroek printf(" sort order ('%c' to cycle): %s", ORDERKEY, ordername(order));
460b89261baSDavid van Moolenbroek NEWLINE;
461b89261baSDavid van Moolenbroek
462b89261baSDavid van Moolenbroek NEWLINE;
463b89261baSDavid van Moolenbroek
464b89261baSDavid van Moolenbroek printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND");
465b89261baSDavid van Moolenbroek NEWLINE;
466b89261baSDavid van Moolenbroek for(p = 0; p < nprocs; p++) {
467b89261baSDavid van Moolenbroek struct proc *pr;
468b89261baSDavid van Moolenbroek int level = 0;
469b89261baSDavid van Moolenbroek
470b89261baSDavid van Moolenbroek pr = tick_procs[p].p;
471b89261baSDavid van Moolenbroek
472b89261baSDavid van Moolenbroek if((pr->p_flags & IS_TASK) && pr->p_pid != KERNEL) {
473b89261baSDavid van Moolenbroek /* skip old kernel tasks as they don't run anymore */
474b89261baSDavid van Moolenbroek continue;
475b89261baSDavid van Moolenbroek }
476b89261baSDavid van Moolenbroek
477b89261baSDavid van Moolenbroek /* If we're in blocked verbose mode, indicate start of
478b89261baSDavid van Moolenbroek * blocked processes.
479b89261baSDavid van Moolenbroek */
480b89261baSDavid van Moolenbroek if(blockedverbose && (pr->p_flags & BLOCKED) && !blockedseen) {
481b89261baSDavid van Moolenbroek NEWLINE;
482b89261baSDavid van Moolenbroek printf("Blocked processes:");
483b89261baSDavid van Moolenbroek NEWLINE;
484b89261baSDavid van Moolenbroek blockedseen = 1;
485b89261baSDavid van Moolenbroek }
486b89261baSDavid van Moolenbroek
487b89261baSDavid van Moolenbroek print_proc(&tick_procs[p], total_ticks);
488b89261baSDavid van Moolenbroek NEWLINE;
489b89261baSDavid van Moolenbroek
490b89261baSDavid van Moolenbroek if(!blockedverbose)
491b89261baSDavid van Moolenbroek continue;
492b89261baSDavid van Moolenbroek
493b89261baSDavid van Moolenbroek /* Traverse dependency chain if blocked. */
494b89261baSDavid van Moolenbroek while(pr->p_flags & BLOCKED) {
495b89261baSDavid van Moolenbroek endpoint_t dep = NONE;
496b89261baSDavid van Moolenbroek struct tp *tpdep;
497b89261baSDavid van Moolenbroek level += 5;
498b89261baSDavid van Moolenbroek
499b89261baSDavid van Moolenbroek if((dep = pr->p_blocked) == NONE) {
500b89261baSDavid van Moolenbroek printf("not blocked on a process");
501b89261baSDavid van Moolenbroek NEWLINE;
502b89261baSDavid van Moolenbroek break;
503b89261baSDavid van Moolenbroek }
504b89261baSDavid van Moolenbroek
505b89261baSDavid van Moolenbroek if(dep == ANY)
506b89261baSDavid van Moolenbroek break;
507b89261baSDavid van Moolenbroek
508b89261baSDavid van Moolenbroek tpdep = lookup(dep, tick_procs, nprocs);
509b89261baSDavid van Moolenbroek pr = tpdep->p;
510b89261baSDavid van Moolenbroek printf("%*s> ", level, "");
511b89261baSDavid van Moolenbroek print_proc(tpdep, total_ticks);
512b89261baSDavid van Moolenbroek NEWLINE;
513b89261baSDavid van Moolenbroek }
514b89261baSDavid van Moolenbroek }
515b89261baSDavid van Moolenbroek }
516b89261baSDavid van Moolenbroek
showtop(int cputimemode,int r)517b89261baSDavid van Moolenbroek static void showtop(int cputimemode, int r)
518b89261baSDavid van Moolenbroek {
519b89261baSDavid van Moolenbroek #define NLOADS 3
520b89261baSDavid van Moolenbroek double loads[NLOADS];
521b89261baSDavid van Moolenbroek int nloads, lines = 0;
522b89261baSDavid van Moolenbroek struct winsize winsize;
523b89261baSDavid van Moolenbroek
524b89261baSDavid van Moolenbroek if(ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize) != 0) {
525b89261baSDavid van Moolenbroek perror("TIOCGWINSZ");
526b89261baSDavid van Moolenbroek fprintf(stderr, "TIOCGWINSZ failed\n");
527b89261baSDavid van Moolenbroek exit(1);
528b89261baSDavid van Moolenbroek }
529b89261baSDavid van Moolenbroek
530b89261baSDavid van Moolenbroek get_procs();
531*305e366fSDavid van Moolenbroek if (prev_proc == NULL) {
532*305e366fSDavid van Moolenbroek /*
533*305e366fSDavid van Moolenbroek * A delay short enough to be unnoticable but long enough to
534*305e366fSDavid van Moolenbroek * allow for accumulation of sufficient data for the initial
535*305e366fSDavid van Moolenbroek * display not to show wildly inaccurate numbers.
536*305e366fSDavid van Moolenbroek */
537*305e366fSDavid van Moolenbroek usleep(100000);
538b89261baSDavid van Moolenbroek get_procs();
539*305e366fSDavid van Moolenbroek }
540b89261baSDavid van Moolenbroek
541b89261baSDavid van Moolenbroek if((nloads = getloadavg(loads, NLOADS)) != NLOADS) {
542b89261baSDavid van Moolenbroek fprintf(stderr, "getloadavg() failed - %d loads\n", nloads);
543b89261baSDavid van Moolenbroek exit(1);
544b89261baSDavid van Moolenbroek }
545b89261baSDavid van Moolenbroek
546b89261baSDavid van Moolenbroek
547b89261baSDavid van Moolenbroek printf("%s", Tclr_all);
548b89261baSDavid van Moolenbroek
549b89261baSDavid van Moolenbroek lines += print_load(loads, NLOADS);
550b89261baSDavid van Moolenbroek lines += print_proc_summary(proc);
551b89261baSDavid van Moolenbroek lines += print_memory();
552b89261baSDavid van Moolenbroek
553b89261baSDavid van Moolenbroek if(winsize.ws_row > 0) r = winsize.ws_row;
554b89261baSDavid van Moolenbroek
555b89261baSDavid van Moolenbroek print_procs(r - lines - 2, prev_proc, proc, cputimemode);
556b89261baSDavid van Moolenbroek fflush(NULL);
557b89261baSDavid van Moolenbroek }
558b89261baSDavid van Moolenbroek
init(int * rows)559b89261baSDavid van Moolenbroek static void init(int *rows)
560b89261baSDavid van Moolenbroek {
561b89261baSDavid van Moolenbroek char *term;
562b89261baSDavid van Moolenbroek static char buffer[TC_BUFFER], strings[TC_STRINGS];
563b89261baSDavid van Moolenbroek char *s = strings, *v;
564b89261baSDavid van Moolenbroek
565b89261baSDavid van Moolenbroek *rows = 0;
566b89261baSDavid van Moolenbroek
567b89261baSDavid van Moolenbroek if(!(term = getenv("TERM"))) {
568b89261baSDavid van Moolenbroek fprintf(stderr, "No TERM set\n");
569b89261baSDavid van Moolenbroek exit(1);
570b89261baSDavid van Moolenbroek }
571b89261baSDavid van Moolenbroek
572b89261baSDavid van Moolenbroek if ( tgetent( buffer, term ) != 1 ) {
573b89261baSDavid van Moolenbroek fprintf(stderr, "tgetent failed for term %s\n", term);
574b89261baSDavid van Moolenbroek exit(1);
575b89261baSDavid van Moolenbroek }
576b89261baSDavid van Moolenbroek
577b89261baSDavid van Moolenbroek initscr();
578b89261baSDavid van Moolenbroek cbreak();
579b89261baSDavid van Moolenbroek
580b89261baSDavid van Moolenbroek if ( (Tclr_all = tgetstr( "cl", &s )) == NULL )
581b89261baSDavid van Moolenbroek Tclr_all = "\f";
582b89261baSDavid van Moolenbroek
583b89261baSDavid van Moolenbroek if((v = tgetstr ("li", &s)) != NULL)
584b89261baSDavid van Moolenbroek sscanf(v, "%d", rows);
585b89261baSDavid van Moolenbroek if(*rows < 1) *rows = 24;
586b89261baSDavid van Moolenbroek }
587b89261baSDavid van Moolenbroek
sigwinch(int sig)588b89261baSDavid van Moolenbroek static void sigwinch(int sig) { }
589b89261baSDavid van Moolenbroek
getkinfo(void)590b89261baSDavid van Moolenbroek static void getkinfo(void)
591b89261baSDavid van Moolenbroek {
592b89261baSDavid van Moolenbroek FILE *fp;
593b89261baSDavid van Moolenbroek
594b89261baSDavid van Moolenbroek if ((fp = fopen("kinfo", "r")) == NULL) {
595b89261baSDavid van Moolenbroek fprintf(stderr, "opening " _PATH_PROC "kinfo failed\n");
596b89261baSDavid van Moolenbroek exit(1);
597b89261baSDavid van Moolenbroek }
598b89261baSDavid van Moolenbroek
599b89261baSDavid van Moolenbroek if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2) {
600b89261baSDavid van Moolenbroek fprintf(stderr, "reading from " _PATH_PROC "kinfo failed\n");
601b89261baSDavid van Moolenbroek exit(1);
602b89261baSDavid van Moolenbroek }
603b89261baSDavid van Moolenbroek
604b89261baSDavid van Moolenbroek fclose(fp);
605b89261baSDavid van Moolenbroek
606b89261baSDavid van Moolenbroek nr_total = (int) (nr_procs + nr_tasks);
607b89261baSDavid van Moolenbroek }
608b89261baSDavid van Moolenbroek
main(int argc,char * argv[])609b89261baSDavid van Moolenbroek int main(int argc, char *argv[])
610b89261baSDavid van Moolenbroek {
611b89261baSDavid van Moolenbroek int r, optc, s = 0;
612b89261baSDavid van Moolenbroek int cputimemode = 1; /* bitmap. */
613b89261baSDavid van Moolenbroek
614b89261baSDavid van Moolenbroek if (chdir(_PATH_PROC) != 0) {
615b89261baSDavid van Moolenbroek perror("chdir to " _PATH_PROC);
616b89261baSDavid van Moolenbroek return 1;
617b89261baSDavid van Moolenbroek }
618b89261baSDavid van Moolenbroek
619b89261baSDavid van Moolenbroek system_hz = (u32_t) sysconf(_SC_CLK_TCK);
620b89261baSDavid van Moolenbroek
621b89261baSDavid van Moolenbroek getkinfo();
622b89261baSDavid van Moolenbroek
623b89261baSDavid van Moolenbroek init(&r);
624b89261baSDavid van Moolenbroek
625b89261baSDavid van Moolenbroek while((optc=getopt(argc, argv, "s:B")) != EOF) {
626b89261baSDavid van Moolenbroek switch(optc) {
627b89261baSDavid van Moolenbroek case 's':
628b89261baSDavid van Moolenbroek s = atoi(optarg);
629b89261baSDavid van Moolenbroek break;
630b89261baSDavid van Moolenbroek case 'B':
631b89261baSDavid van Moolenbroek blockedverbose = 1;
632b89261baSDavid van Moolenbroek break;
633b89261baSDavid van Moolenbroek default:
634b89261baSDavid van Moolenbroek fprintf(stderr,
635b89261baSDavid van Moolenbroek "Usage: %s [-s<secdelay>] [-B]\n",
636b89261baSDavid van Moolenbroek argv[0]);
637b89261baSDavid van Moolenbroek return 1;
638b89261baSDavid van Moolenbroek }
639b89261baSDavid van Moolenbroek }
640b89261baSDavid van Moolenbroek
641b89261baSDavid van Moolenbroek if(s < 1)
642b89261baSDavid van Moolenbroek s = 2;
643b89261baSDavid van Moolenbroek
644b89261baSDavid van Moolenbroek /* Catch window size changes so display is updated properly
645b89261baSDavid van Moolenbroek * right away.
646b89261baSDavid van Moolenbroek */
647b89261baSDavid van Moolenbroek signal(SIGWINCH, sigwinch);
648b89261baSDavid van Moolenbroek
649b89261baSDavid van Moolenbroek while(1) {
650b89261baSDavid van Moolenbroek fd_set fds;
651b89261baSDavid van Moolenbroek int ns;
652b89261baSDavid van Moolenbroek struct timeval tv;
653b89261baSDavid van Moolenbroek showtop(cputimemode, r);
654b89261baSDavid van Moolenbroek tv.tv_sec = s;
655b89261baSDavid van Moolenbroek tv.tv_usec = 0;
656b89261baSDavid van Moolenbroek
657b89261baSDavid van Moolenbroek FD_ZERO(&fds);
658b89261baSDavid van Moolenbroek FD_SET(STDIN_FILENO, &fds);
659b89261baSDavid van Moolenbroek
660b89261baSDavid van Moolenbroek if((ns=select(STDIN_FILENO+1, &fds, NULL, NULL, &tv)) < 0
661b89261baSDavid van Moolenbroek && errno != EINTR) {
662b89261baSDavid van Moolenbroek perror("select");
663b89261baSDavid van Moolenbroek sleep(1);
664b89261baSDavid van Moolenbroek }
665b89261baSDavid van Moolenbroek
666b89261baSDavid van Moolenbroek if(ns > 0 && FD_ISSET(STDIN_FILENO, &fds)) {
667b89261baSDavid van Moolenbroek char inc;
668b89261baSDavid van Moolenbroek if(read(STDIN_FILENO, &inc, 1) == 1) {
669b89261baSDavid van Moolenbroek switch(inc) {
670b89261baSDavid van Moolenbroek case 'q':
671b89261baSDavid van Moolenbroek putchar('\r');
672b89261baSDavid van Moolenbroek return 0;
673b89261baSDavid van Moolenbroek break;
674*305e366fSDavid van Moolenbroek case ORDERKEY:
675b89261baSDavid van Moolenbroek order++;
676b89261baSDavid van Moolenbroek if(order > ORDER_HIGHEST)
677b89261baSDavid van Moolenbroek order = 0;
678b89261baSDavid van Moolenbroek break;
679b89261baSDavid van Moolenbroek case TIMECYCLEKEY:
680b89261baSDavid van Moolenbroek cputimemode++;
681b89261baSDavid van Moolenbroek if(cputimemode >= (1L << CPUTIMENAMES))
682b89261baSDavid van Moolenbroek cputimemode = 1;
683b89261baSDavid van Moolenbroek break;
684b89261baSDavid van Moolenbroek }
685b89261baSDavid van Moolenbroek }
686b89261baSDavid van Moolenbroek }
687b89261baSDavid van Moolenbroek }
688b89261baSDavid van Moolenbroek
689b89261baSDavid van Moolenbroek return 0;
690b89261baSDavid van Moolenbroek }
691b89261baSDavid van Moolenbroek
692