xref: /minix3/minix/usr.bin/mtop/mtop.c (revision 305e366fe47197851cc728bd12ee4d4f1d8f7d64)
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