]>
Commit | Line | Data |
---|---|---|
1815bff5 A |
1 | /* |
2 | * Top users display for Berkeley Unix | |
3 | * Version 1.8 | |
4 | * | |
5 | * This program may be freely redistributed to other Unix sites, but this | |
6 | * entire comment MUST remain intact. | |
7 | * | |
8 | * Copyright (c) 1984, William LeFebvre, Rice University | |
9 | * | |
10 | * This program is designed to run on either Berkeley 4.1 or 4.2 Unix. | |
11 | * Compile with the preprocessor constant "FOUR_ONE" set to get an | |
12 | * executable that will run on Berkeley 4.1 Unix. | |
13 | * | |
14 | * The Sun kernel uses scaled integers instead of floating point so compile | |
15 | * with the preprocessor variable "SUN" to get an executable that will run | |
16 | * on Sun Unix version 1.1 or later. | |
17 | * | |
18 | * Fixes and enhancements since version 1.5: | |
19 | * | |
20 | * Jonathon Feiber at sun: | |
21 | * added "#ifdef SUN" code to make top work on a Sun, | |
22 | * fixed race bug in getkval for getting user structure, | |
23 | * efficiency improvements: added register variables and | |
24 | * removed the function hashit | |
25 | * | |
26 | * added real and virtual memory status line | |
27 | * | |
28 | * added second "key" to the qsort comparisn function "proc_compar" | |
29 | * which sorts by on cpu ticks if percentage is equal | |
30 | * | |
31 | ********************************************************************** | |
32 | * HISTORY | |
33 | * 22-Apr-99 Avadis Tevanian (avie) at Apple | |
34 | * Another rewrite for Mach 3.0 | |
35 | * | |
36 | * 21-Apr-90 Avadis Tevanian (avie) at NeXT | |
37 | * Completely rewritten again for processor sets. | |
38 | * | |
39 | * 6-May-88 David Golub (dbg) at Carnegie-Mellon University | |
40 | * Completely rewritten for MACH. This version will NOT run on any | |
41 | * other version of BSD. | |
42 | * | |
43 | */ | |
44 | ||
45 | #define Default_TOPN 16 /* default number of lines */ | |
46 | #define Default_DELAY 1 /* default delay interval */ | |
47 | #define IOKIT 1 /* for io_name_t in device_types.h */ | |
48 | ||
49 | #include <mach/mach.h> | |
50 | #include <stdlib.h> | |
51 | #include <stdio.h> | |
52 | #include <signal.h> | |
53 | #include <strings.h> | |
54 | #include <nlist.h> | |
55 | #include <fcntl.h> | |
56 | #include <string.h> | |
57 | ||
58 | #include <sys/types.h> | |
59 | #include <sys/param.h> | |
60 | #include <sys/sysctl.h> | |
61 | #include <sys/time.h> | |
62 | ||
63 | #include <mach/bootstrap.h> | |
64 | #include <mach/host_info.h> | |
65 | #include <mach/mach_error.h> | |
66 | #include <mach/mach_types.h> | |
67 | #include <mach/message.h> | |
68 | #include <mach/vm_region.h> | |
69 | #include <mach/vm_map.h> | |
70 | #include <mach/vm_types.h> | |
71 | #include <mach/vm_prot.h> | |
b51d5b5f | 72 | #include <mach/shared_memory_server.h> |
1815bff5 A |
73 | |
74 | #include <device/device_types.h> | |
75 | #include <CoreFoundation/CoreFoundation.h> | |
76 | #include <IOKit/IOKitLib.h> | |
77 | #include <IOKit/storage/IOBlockStorageDriver.h> | |
78 | ||
79 | #include <kvm.h> | |
80 | #include <sys/socket.h> | |
81 | #include <net/if.h> | |
82 | #include <net/if_var.h> | |
83 | ||
84 | #include <libc.h> | |
85 | #include <termios.h> | |
b51d5b5f A |
86 | #include <curses.h> |
87 | #include <sys/ioctl.h> | |
1815bff5 A |
88 | |
89 | /* Number of lines of header information on the standard screen */ | |
90 | #define HEADER_LINES 8 | |
91 | ||
92 | #define sec_to_minutes(t) ((t) / 60) | |
93 | #define sec_to_seconds(t) ((t) % 60) | |
94 | #define usec_to_100ths(t) ((t) / 10000) | |
95 | ||
96 | #ifndef TH_USAGE_SCALE | |
97 | #define TH_USAGE_SCALE 1000 | |
98 | #endif TH_USAGE_SCALE | |
99 | #define usage_to_percent(u) ((u*100)/TH_USAGE_SCALE) | |
100 | #define usage_to_tenths(u) (((u*1000)/TH_USAGE_SCALE) % 10) | |
101 | ||
102 | ||
103 | #define time_value_sub(tvp, uvp, vvp) \ | |
104 | do { \ | |
105 | (vvp)->seconds = (tvp)->seconds - (uvp)->seconds; \ | |
106 | (vvp)->microseconds = (tvp)->microseconds - (uvp)->microseconds; \ | |
107 | if ((vvp)->microseconds < 0) { \ | |
108 | (vvp)->seconds--; \ | |
109 | (vvp)->microseconds += 1000000; \ | |
110 | } \ | |
111 | } while (0) | |
112 | ||
113 | ||
114 | ||
115 | /* From libcurses */ | |
116 | int wclear(WINDOW *win); | |
117 | int wmove(WINDOW *win, int y, int x); | |
118 | int wrefresh(WINDOW *win); | |
119 | int endwin(void); | |
120 | int werase(WINDOW *win); | |
121 | ||
122 | int total_threads; | |
123 | unsigned long long total_fw_private; | |
124 | ||
1815bff5 A |
125 | char bytesread[128]; |
126 | ||
127 | host_cpu_load_info_data_t lastcounters, curcounters, startcounters; | |
128 | double userticks, systicks, idleticks, totalticks; | |
129 | ||
130 | struct timeval cur_tod; | |
131 | struct timeval start_tod; | |
132 | struct timeval last_tod; | |
133 | struct timeval elapsed_tod; | |
134 | int elapsed_milliseconds; | |
135 | int newLINES = 0; | |
136 | int Header_lines = HEADER_LINES; | |
137 | ||
138 | int do_proc0_vm; | |
139 | int sort_by_usage; | |
140 | int wide_output; | |
141 | int oneshot; | |
142 | int logcnt; | |
143 | int events_only; | |
144 | int events_delta; | |
145 | int events_accumulate; | |
146 | long start_time = 0; | |
147 | ||
148 | ||
149 | struct io_stats { | |
150 | UInt64 io_accum; | |
151 | UInt64 io_prev; | |
152 | UInt64 io; | |
153 | UInt64 kbytes_accum; | |
154 | UInt64 kbytes_prev; | |
155 | UInt64 kbytes; | |
156 | }; | |
157 | ||
158 | struct io_stats i_net, o_net; | |
159 | struct io_stats i_dsk, o_dsk; | |
160 | struct io_stats i_vm, o_vm; | |
161 | ||
162 | ||
163 | io_iterator_t drivelist = 0; /* needs release */ | |
164 | mach_port_t masterPort = 0; | |
165 | ||
166 | ||
167 | struct proc_info { | |
168 | uid_t uid; | |
169 | short pid; | |
170 | short ppid; | |
171 | short pgrp; | |
172 | int status; | |
173 | int flag; | |
174 | ||
175 | int state; | |
176 | int pri; | |
177 | int base_pri; | |
178 | boolean_t all_swapped; | |
179 | boolean_t has_idle_thread; | |
180 | time_value_t total_time; | |
181 | time_value_t idle_time; | |
182 | time_value_t beg_total_time; | |
183 | time_value_t beg_idle_time; | |
184 | ||
185 | vm_size_t virtual_size; | |
186 | vm_size_t resident_size; | |
187 | vm_size_t orig_virtual_size; | |
188 | vm_offset_t drsize, dvsize; | |
189 | vm_offset_t drprvt, drshrd; | |
190 | vm_offset_t rvsize; | |
191 | unsigned int shared; | |
192 | unsigned int private; | |
193 | unsigned int vprivate; | |
194 | int obj_count; | |
195 | int cpu_usage; | |
196 | int cpu_idle; | |
197 | ||
198 | char command[20]; | |
199 | ||
200 | int num_ports; | |
201 | int orig_num_ports; | |
202 | int dnum_ports; | |
203 | int num_threads; | |
204 | thread_basic_info_t threads; /* array */ | |
205 | task_events_info_data_t tei; | |
206 | task_events_info_data_t deltatei; | |
207 | task_events_info_data_t accumtei; | |
208 | }; | |
209 | ||
210 | typedef struct proc_info *proc_info_t; | |
211 | ||
212 | mach_port_t host_priv_port, host_port; | |
213 | ||
214 | struct object_info { | |
215 | int id; | |
216 | int pid; | |
217 | int share_type; | |
218 | int resident_page_count; | |
219 | int ref_count; | |
220 | int task_ref_count; | |
221 | int size; | |
222 | struct object_info *next; | |
223 | }; | |
224 | ||
225 | #define OBJECT_TABLE_SIZE 537 | |
226 | #define OT_HASH(object) (((unsigned)object)%OBJECT_TABLE_SIZE) | |
227 | ||
228 | struct object_info *shared_hash_table[OBJECT_TABLE_SIZE]; | |
229 | ||
230 | struct object_info *of_free_list = 0; | |
231 | ||
1815bff5 A |
232 | /* |
233 | * Translate thread state to a number in an ordered scale. | |
234 | * When collapsing all the threads' states to one for the | |
235 | * entire task, the lower-numbered state dominates. | |
236 | */ | |
237 | #define STATE_MAX 7 | |
238 | ||
239 | int | |
240 | mach_state_order(s, sleep_time) | |
241 | int s; | |
242 | long sleep_time; | |
243 | { | |
244 | switch (s) { | |
245 | case TH_STATE_RUNNING: return(1); | |
246 | case TH_STATE_UNINTERRUPTIBLE: | |
247 | return(2); | |
248 | case TH_STATE_WAITING: return((sleep_time > 20) ? 4 : 3); | |
249 | case TH_STATE_STOPPED: return(5); | |
250 | case TH_STATE_HALTED: return(6); | |
251 | default: return(7); | |
252 | } | |
253 | } | |
254 | /*01234567 */ | |
255 | char mach_state_table[] = "ZRUSITH?"; | |
256 | ||
257 | char * state_name[] = { | |
258 | "zombie", | |
259 | "running", | |
260 | "stuck", | |
261 | "sleeping", | |
262 | "idle", | |
263 | "stopped", | |
264 | "halted", | |
265 | "unknown", | |
266 | }; | |
267 | int state_breakdown[STATE_MAX+1]; | |
268 | ||
269 | ||
270 | char *state_to_string(pi) | |
271 | proc_info_t pi; | |
272 | { | |
273 | static char s[5]; /* STATIC! */ | |
274 | ||
275 | s[0] = mach_state_table[pi->state]; | |
276 | s[1] = (pi->all_swapped) ? 'W' : ' '; | |
277 | s[2] = (pi->base_pri > 50) ? 'N' : | |
278 | (pi->base_pri < 40) ? '<' : ' '; | |
279 | s[3] = ' '; | |
280 | s[4] = '\0'; | |
281 | return(s); | |
282 | } | |
283 | ||
284 | void print_time(char *p, time_value_t t) | |
285 | { | |
286 | long seconds, useconds, minutes, hours; | |
287 | ||
288 | seconds = t.seconds; | |
289 | useconds = t.microseconds; | |
290 | minutes = seconds / 60; | |
291 | hours = minutes / 60; | |
292 | ||
293 | if (minutes < 100) { // up to 100 minutes | |
294 | sprintf(p, "%2ld:%02ld.%02ld", minutes, seconds % 60, | |
295 | usec_to_100ths(useconds)); | |
296 | } | |
297 | else if (hours < 100) { // up to 100 hours | |
298 | sprintf(p, "%2ld:%02ld:%02ld", hours, minutes % 60, | |
299 | seconds % 60); | |
300 | } | |
301 | else { | |
302 | sprintf(p, "%4ld hrs", hours); | |
303 | } | |
304 | } | |
305 | ||
306 | ||
307 | void | |
308 | print_usage(char *p, int cpu_usage) | |
309 | { | |
310 | int left_of_decimal; | |
311 | int right_of_decimal; | |
312 | ||
313 | if (elapsed_milliseconds) { | |
314 | left_of_decimal = (cpu_usage * 100) / elapsed_milliseconds; | |
315 | ||
316 | right_of_decimal = (((cpu_usage * 100) - (left_of_decimal * elapsed_milliseconds)) * 10) / | |
317 | elapsed_milliseconds; | |
318 | } else { | |
319 | left_of_decimal = 0; | |
320 | right_of_decimal = 0; | |
321 | } | |
322 | sprintf(p, "%3d.%01d%%%%", left_of_decimal, right_of_decimal); /* %cpu */ | |
323 | } | |
324 | ||
325 | ||
326 | ||
327 | char * | |
328 | digits(n) | |
329 | float n; | |
330 | { | |
331 | static char tmp[10]; /* STATIC! */ | |
332 | ||
333 | if ((n > 0) && (n < 10)) | |
334 | sprintf(tmp, "%4.2f", n); | |
335 | else if ((n > 0) && (n < 100)) | |
336 | sprintf(tmp, "%4.1f", n); | |
337 | else if ((n < 0) && (n > -10)) | |
338 | sprintf(tmp, "%4.1f", n); | |
339 | else | |
340 | sprintf(tmp, "%4.0f", n); | |
341 | return(tmp); | |
342 | } | |
343 | ||
344 | char * | |
345 | mem_to_string(n) | |
346 | unsigned long long n; | |
347 | { | |
348 | static char s[10]; /* STATIC! */ | |
349 | ||
350 | /* convert to kilobytes */ | |
351 | n /= 1024; | |
352 | ||
353 | if (n > 1024*1024) | |
354 | sprintf(s, "%sG", digits(((float)n)/(1024.0*1024.0))); | |
355 | else if (n > 1024) | |
356 | sprintf(s, "%sM", digits((float)n/(1024.0))); | |
357 | else | |
358 | sprintf(s, "%dK", (int)n); | |
359 | ||
360 | return(s); | |
361 | } | |
362 | ||
363 | char * | |
364 | offset_to_string(n) | |
365 | int n; | |
366 | { | |
367 | static char s[10]; /* STATIC! */ | |
368 | int an; | |
369 | ||
370 | /* convert to kilobytes */ | |
371 | n /= 1024; | |
372 | an = abs(n); | |
373 | ||
374 | if (an > 1024*1024) | |
375 | sprintf(s, "%sG", digits(((float)n)/(1024.0*1024.0))); | |
376 | else if (an > 1024) | |
377 | sprintf(s, "%sM", digits((float)n/(1024.0))); | |
378 | else | |
379 | sprintf(s, "%dK", n); | |
380 | ||
381 | return(s); | |
382 | } | |
383 | ||
384 | mach_port_t get_host_priv() | |
385 | { | |
386 | return(mach_host_self()); | |
387 | } | |
388 | ||
389 | mach_port_t get_host_port() | |
390 | { | |
391 | return(mach_host_self()); | |
392 | } | |
393 | ||
394 | void | |
395 | shared_hash_enter(int obj_id, int share_type, int resident_page_count, int ref_count, int size, int pid) | |
396 | { | |
397 | register struct object_info **bucket; | |
398 | register struct object_info *of; | |
399 | ||
400 | of = shared_hash_table[OT_HASH(obj_id/OBJECT_TABLE_SIZE)]; | |
401 | while (of) { | |
402 | if (of->id == obj_id) { | |
403 | of->size += size; | |
404 | of->task_ref_count++; | |
405 | of->pid = pid; | |
406 | return; | |
407 | } | |
408 | of = of->next; | |
409 | } | |
410 | bucket = &shared_hash_table[OT_HASH(obj_id/OBJECT_TABLE_SIZE)]; | |
411 | ||
412 | if (of = of_free_list) | |
413 | of_free_list = of->next; | |
414 | else | |
415 | of = (struct object_info *) malloc(sizeof(*of)); | |
416 | ||
417 | of->resident_page_count = resident_page_count; | |
418 | of->id = obj_id; | |
419 | of->share_type = share_type; | |
420 | of->ref_count = ref_count; | |
421 | of->task_ref_count = 1; | |
422 | of->pid = pid; | |
423 | of->size = size; | |
424 | ||
425 | of->next = *bucket; | |
426 | *bucket = of; | |
427 | } | |
428 | ||
429 | void | |
430 | pmem_doit(task_port_t task, int pid, int *shared, int *private, int *aliased, int *obj_count, int *vprivate, vm_size_t *vsize, unsigned long long *fw_private) | |
431 | { | |
432 | vm_address_t address = 0; | |
433 | kern_return_t err = 0; | |
434 | register int i; | |
435 | int split = 0; | |
436 | ||
437 | *obj_count = *aliased = *shared = *private = *vprivate = 0; | |
438 | ||
439 | while (1) { | |
440 | mach_port_t object_name; | |
441 | vm_region_top_info_data_t info; | |
442 | mach_msg_type_number_t count; | |
443 | vm_size_t size; | |
444 | ||
1815bff5 A |
445 | count = VM_REGION_TOP_INFO_COUNT; |
446 | ||
447 | if (err = vm_region(task, &address, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, | |
448 | &count, &object_name)) | |
449 | break; | |
450 | ||
b51d5b5f | 451 | if (address >= GLOBAL_SHARED_TEXT_SEGMENT && address < (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) { |
1815bff5 A |
452 | |
453 | *fw_private += info.private_pages_resident * vm_page_size; | |
454 | ||
1c51fdde A |
455 | if ( !split && info.share_mode == SM_EMPTY) { |
456 | vm_region_basic_info_data_64_t b_info; | |
457 | ||
458 | count = VM_REGION_BASIC_INFO_COUNT_64; | |
459 | if (err = vm_region_64(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, | |
460 | &count, &object_name)) | |
461 | break; | |
462 | ||
463 | if (b_info.reserved) | |
464 | split = 1; | |
465 | } | |
1815bff5 A |
466 | if (info.share_mode != SM_PRIVATE) { |
467 | address += size; | |
468 | continue; | |
469 | } | |
470 | } | |
471 | address += size; | |
472 | ||
473 | *obj_count += 1; | |
474 | ||
475 | switch (info.share_mode) { | |
476 | ||
477 | case SM_PRIVATE: | |
478 | *private += info.private_pages_resident * vm_page_size; | |
479 | *vprivate += size; | |
480 | break; | |
481 | ||
482 | case SM_COW: | |
483 | if (info.ref_count == 1) | |
484 | info.share_mode = SM_PRIVATE; | |
485 | if (pid && info.share_mode == SM_COW) | |
486 | shared_hash_enter(info.obj_id, SM_COW, info.shared_pages_resident, | |
487 | info.ref_count, size, pid); | |
488 | if (info.share_mode == SM_PRIVATE) | |
489 | *private += info.shared_pages_resident * vm_page_size; | |
490 | *private += info.private_pages_resident * vm_page_size; | |
491 | ||
492 | if (info.share_mode == SM_PRIVATE) | |
493 | *vprivate += size; | |
494 | else | |
495 | *vprivate += info.private_pages_resident * vm_page_size; | |
496 | break; | |
497 | ||
498 | case SM_SHARED: | |
499 | if (pid) | |
500 | shared_hash_enter(info.obj_id, SM_SHARED, info.shared_pages_resident, | |
501 | info.ref_count, size, pid); | |
502 | break; | |
503 | } | |
504 | } | |
505 | for (i = 0; i < OBJECT_TABLE_SIZE; i++) { | |
506 | register struct object_info *sl; | |
507 | ||
508 | sl = shared_hash_table[i]; | |
509 | ||
510 | while (sl) { | |
511 | if (sl->pid == pid) { | |
512 | if (sl->share_type == SM_SHARED) { | |
513 | if (sl->ref_count == sl->task_ref_count) { | |
514 | sl->share_type = SM_PRIVATE_ALIASED; | |
515 | ||
516 | *aliased += sl->resident_page_count * vm_page_size; | |
517 | *vprivate += sl->size; | |
518 | } | |
519 | } | |
520 | if (sl->share_type != SM_PRIVATE_ALIASED) | |
521 | *shared += sl->resident_page_count * vm_page_size; | |
522 | } | |
523 | sl->task_ref_count = 0; | |
524 | ||
525 | sl = sl->next; | |
526 | } | |
527 | } | |
528 | if (split) | |
b51d5b5f | 529 | *vsize -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); |
1815bff5 A |
530 | } |
531 | ||
532 | ||
533 | void | |
534 | pmem_fw_resident(unsigned int *num_fw, unsigned long long *vsize, unsigned int *code_size, unsigned int *data_size, unsigned int *linkedit_size) | |
b51d5b5f | 535 | { vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT; |
1815bff5 A |
536 | kern_return_t err = 0; |
537 | int state = 0; | |
538 | ||
539 | *vsize = 0; | |
540 | *num_fw = 0; | |
541 | *code_size = 0; | |
542 | *data_size = 0; | |
543 | *linkedit_size = 0; | |
544 | ||
b51d5b5f | 545 | while (address < (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) { |
1815bff5 A |
546 | vm_region_submap_info_data_64_t s_info; |
547 | mach_msg_type_number_t count; | |
548 | vm_size_t size; | |
549 | int nesting_depth; | |
550 | ||
551 | nesting_depth = 1; | |
552 | count = VM_REGION_SUBMAP_INFO_COUNT_64; | |
553 | ||
554 | if (err = vm_region_recurse_64(mach_task_self(), &address, &size, &nesting_depth, (vm_region_info_t)&s_info, &count)) | |
555 | break; | |
556 | ||
b51d5b5f | 557 | if (address >= (GLOBAL_SHARED_DATA_SEGMENT + SHARED_DATA_REGION_SIZE)) |
1815bff5 | 558 | break; |
b51d5b5f | 559 | if (address < GLOBAL_SHARED_DATA_SEGMENT) { |
1815bff5 A |
560 | |
561 | if (s_info.share_mode == SM_SHARED || s_info.share_mode == SM_COW) { | |
562 | if (s_info.max_protection & VM_PROT_EXECUTE) { | |
563 | *code_size += (s_info.pages_resident * vm_page_size); | |
564 | ||
565 | if (state == 0) | |
566 | *num_fw += 1; | |
567 | state = 1; | |
568 | ||
569 | } else { | |
570 | *linkedit_size += (s_info.pages_resident * vm_page_size); | |
571 | ||
572 | state = 0; | |
573 | } | |
574 | } | |
575 | ||
576 | } else { | |
577 | if (s_info.share_mode == SM_SHARED || s_info.share_mode == SM_COW || s_info.share_mode == SM_TRUESHARED) | |
578 | *data_size += (s_info.pages_resident * vm_page_size); | |
579 | } | |
580 | *vsize += size; | |
581 | ||
582 | address += size; | |
583 | } | |
584 | } | |
585 | ||
586 | ||
587 | ||
588 | ||
589 | void | |
590 | pmem_shared_resident(unsigned long long *total, int *number) | |
591 | { register int i; | |
592 | register int total_size; | |
593 | register int total_num; | |
594 | register struct object_info *sl, *next; | |
595 | ||
596 | total_size = total_num = 0; | |
597 | ||
598 | for (i = 0; i < OBJECT_TABLE_SIZE; i++) { | |
599 | sl = shared_hash_table[i]; | |
600 | shared_hash_table[i] = 0; | |
601 | ||
602 | while (sl) { | |
603 | if (sl->share_type != SM_PRIVATE_ALIASED) { | |
604 | total_size += sl->resident_page_count; | |
605 | total_num++; | |
606 | } | |
607 | next = sl->next; | |
608 | ||
609 | sl->next = of_free_list; | |
610 | of_free_list = sl; | |
611 | ||
612 | sl = next; | |
613 | } | |
614 | } | |
615 | *number = total_num; | |
616 | *total = total_size * vm_page_size; | |
617 | } | |
618 | ||
619 | ||
620 | int | |
621 | get_real_command_name(int pid, char *cbuf, int csize) | |
622 | { | |
623 | /* | |
624 | * Get command and arguments. | |
625 | */ | |
626 | volatile int *ip, *savedip; | |
627 | volatile char *cp; | |
628 | char c; | |
629 | char *end_argc; | |
630 | int mib[4]; | |
631 | char *arguments; | |
632 | int arguments_size = 4096; | |
633 | volatile unsigned int *valuep; | |
634 | unsigned int value; | |
635 | int blahlen=0, skiplen=0; | |
636 | ||
637 | /* | |
638 | * A sysctl() is made to find out the full path that the command | |
639 | * was called with. | |
640 | */ | |
641 | mib[0] = CTL_KERN; | |
642 | mib[1] = KERN_PROCARGS; | |
643 | mib[2] = pid; | |
644 | mib[3] = 0; | |
645 | ||
646 | arguments = (char *) malloc(arguments_size); | |
647 | if (sysctl(mib, 3, arguments, (size_t *)&arguments_size, NULL, 0) < 0) { | |
648 | free(arguments); | |
649 | return(0); | |
650 | } | |
651 | end_argc = &arguments[arguments_size]; | |
652 | ||
653 | ip = (int *)end_argc; | |
654 | ip -= 2; /* last arg word and .long 0 */ | |
655 | while (*--ip) { | |
656 | if (ip == (int *)arguments) { | |
657 | free(arguments); | |
658 | return(0); | |
659 | } | |
660 | } | |
661 | savedip = ip; | |
662 | savedip++; | |
663 | cp = (char *)savedip; | |
664 | while (*--ip) { | |
665 | if (ip == (int *)arguments) { | |
666 | free(arguments); | |
667 | return(0); | |
668 | } | |
669 | } | |
670 | ip++; | |
671 | valuep = (unsigned int *)ip; | |
672 | value = *valuep; | |
673 | ||
674 | if ((value & 0xbfff0000) == 0xbfff0000) { | |
675 | ip++; ip++; | |
676 | valuep = ip; | |
677 | blahlen = strlen((char *)ip); | |
678 | skiplen = (blahlen +3 ) /4 ; | |
679 | valuep += skiplen; | |
680 | cp = (char *)valuep; | |
681 | while (!*cp) | |
682 | cp++; | |
683 | savedip = (int *)cp; | |
684 | } | |
685 | for (cp = (char *)savedip; cp < (end_argc-1); cp++) { | |
686 | c = *cp & 0177; | |
687 | ||
688 | if (c == 0) | |
689 | break; | |
690 | } | |
691 | *cp = 0; | |
692 | ||
693 | if (cp > (char *)savedip) | |
694 | cp--; | |
695 | ||
696 | while (cp > (char *)savedip) { | |
697 | if (*cp == '/') { | |
698 | cp++; | |
699 | break; | |
700 | } | |
701 | cp--; | |
702 | } | |
703 | if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') { | |
704 | /* | |
705 | * Not enough information | |
706 | */ | |
707 | free(arguments); | |
708 | return(0); | |
709 | } | |
710 | (void) strncpy(cbuf, (char *)cp, csize); | |
711 | cbuf[csize] = '\0'; | |
712 | ||
713 | free(arguments); | |
714 | return(1); | |
715 | } | |
716 | ||
717 | ||
718 | /* All of this should come out of the process manager... */ | |
719 | ||
720 | void get_proc_info(kpb, pi) | |
721 | struct kinfo_proc *kpb; | |
722 | struct proc_info *pi; | |
723 | { | |
724 | task_port_t task; | |
725 | mach_port_array_t names, types; | |
726 | unsigned int ncnt, tcnt; | |
727 | ||
728 | pi->uid = kpb->kp_eproc.e_ucred.cr_uid; | |
729 | pi->pid = kpb->kp_proc.p_pid; | |
730 | pi->ppid = kpb->kp_eproc.e_ppid; | |
731 | pi->pgrp = kpb->kp_eproc.e_pgid; | |
732 | pi->status = kpb->kp_proc.p_stat; | |
733 | pi->flag = kpb->kp_proc.p_flag; | |
734 | ||
735 | /* | |
736 | * Find the other stuff | |
737 | */ | |
738 | if (task_for_pid(mach_task_self(), pi->pid, &task) != KERN_SUCCESS) { | |
739 | pi->status = SZOMB; | |
740 | } | |
741 | ||
742 | else { | |
743 | task_basic_info_data_t ti; | |
744 | unsigned int count; | |
745 | unsigned int aliased; | |
746 | thread_array_t thread_table; | |
747 | unsigned int table_size; | |
748 | thread_basic_info_t thi; | |
749 | thread_basic_info_data_t thi_data; | |
750 | int i, t_state; | |
751 | ||
752 | count = TASK_BASIC_INFO_COUNT; | |
753 | if (task_info(task, TASK_BASIC_INFO, (task_info_t)&ti, | |
754 | &count) != KERN_SUCCESS) { | |
755 | pi->status = SZOMB; | |
756 | } else { | |
757 | pi->virtual_size = ti.virtual_size; | |
758 | ||
759 | pi->resident_size = ti.resident_size; | |
760 | ||
761 | if ((pi->pid || do_proc0_vm) && (!events_only)) { | |
762 | pmem_doit(task, pi->pid, &pi->shared, &pi->private, &aliased, &pi->obj_count, &pi->vprivate, &pi->virtual_size, &total_fw_private); | |
763 | pi->private += aliased; | |
764 | } else { | |
765 | pi->shared = 0; | |
766 | pi->private = 0; | |
767 | pi->vprivate = 0; | |
768 | pi->obj_count = 0; | |
769 | } | |
770 | pi->orig_virtual_size = pi->virtual_size; | |
771 | pi->total_time = ti.user_time; | |
772 | time_value_add(&pi->total_time, &ti.system_time); | |
773 | ||
774 | pi->idle_time.seconds = 0; | |
775 | pi->idle_time.microseconds = 0; | |
776 | ||
777 | if (task_threads(task, &thread_table, &table_size) != KERN_SUCCESS) | |
778 | pi->status = SZOMB; | |
779 | else { | |
780 | pi->state = STATE_MAX; | |
781 | pi->pri = 255; | |
782 | pi->base_pri = 255; | |
783 | pi->all_swapped = TRUE; | |
784 | pi->has_idle_thread = FALSE; | |
785 | ||
786 | thi = &thi_data; | |
787 | ||
788 | pi->num_threads = table_size; | |
789 | total_threads += table_size; | |
790 | ||
791 | for (i = 0; i < table_size; i++) { | |
792 | count = THREAD_BASIC_INFO_COUNT; | |
793 | if (thread_info(thread_table[i], THREAD_BASIC_INFO, | |
794 | (thread_info_t)thi, &count) == KERN_SUCCESS) { | |
795 | ||
796 | if (thi->flags & TH_FLAGS_IDLE) { | |
797 | pi->has_idle_thread = TRUE; | |
798 | ||
799 | time_value_add(&pi->idle_time, | |
800 | &thi->user_time); | |
801 | time_value_add(&pi->idle_time, | |
802 | &thi->system_time); | |
803 | } else { | |
804 | time_value_add(&pi->total_time, | |
805 | &thi->user_time); | |
806 | time_value_add(&pi->total_time, | |
807 | &thi->system_time); | |
808 | } | |
809 | t_state = mach_state_order(thi->run_state, | |
810 | thi->sleep_time); | |
811 | if (t_state < pi->state) | |
812 | pi->state = t_state; | |
813 | // update priority info based on schedule policy | |
814 | // if (thi->cur_priority < pi->pri) | |
815 | // pi->pri = thi->cur_priority; | |
816 | // if (thi->base_priority < pi->base_pri) | |
817 | // pi->base_pri = thi->base_priority; | |
818 | if ((thi->flags & TH_FLAGS_SWAPPED) == 0) | |
819 | pi->all_swapped = FALSE; | |
820 | ||
821 | } | |
822 | if (task != mach_task_self()) { | |
823 | mach_port_deallocate(mach_task_self(), | |
824 | thread_table[i]); | |
825 | } | |
826 | } | |
827 | (void) vm_deallocate(mach_task_self(), (vm_offset_t)thread_table, | |
828 | table_size * sizeof(*thread_table)); | |
829 | ||
1c51fdde A |
830 | if (!events_only) { |
831 | if (mach_port_names(task, &names, &ncnt, | |
832 | &types, &tcnt) == KERN_SUCCESS) { | |
833 | pi->num_ports = ncnt; | |
834 | pi->orig_num_ports = ncnt; | |
835 | (void) vm_deallocate(mach_task_self(), | |
836 | (vm_offset_t) names, | |
837 | ncnt * sizeof(*names)); | |
838 | (void) vm_deallocate(mach_task_self(), | |
839 | (vm_offset_t) types, | |
840 | tcnt * sizeof(*types)); | |
841 | } else { | |
842 | pi->num_ports = -1; | |
843 | } | |
844 | } else | |
845 | pi->num_ports = 0; | |
846 | ||
1815bff5 A |
847 | if (events_only) { |
848 | task_events_info_data_t tei; | |
849 | ||
850 | count = TASK_EVENTS_INFO_COUNT; | |
851 | if (task_info(task, TASK_EVENTS_INFO, (task_info_t)&tei, | |
852 | &count) != KERN_SUCCESS) { | |
853 | pi->status = SZOMB; | |
854 | } else { | |
855 | pi->tei = tei; | |
856 | ||
857 | } | |
858 | } | |
859 | } | |
860 | } | |
861 | if (task != mach_task_self()) { | |
862 | mach_port_deallocate(mach_task_self(), task); | |
863 | } | |
864 | } | |
865 | if ( strncmp (kpb->kp_proc.p_comm, "LaunchCFMA", 10) || | |
866 | !get_real_command_name(pi->pid, pi->command, sizeof(kpb->kp_proc.p_comm)-1)) { | |
867 | (void) strncpy(pi->command, kpb->kp_proc.p_comm, | |
868 | sizeof(kpb->kp_proc.p_comm)-1); | |
869 | pi->command[sizeof(kpb->kp_proc.p_comm)-1] = '\0'; | |
870 | } | |
871 | } | |
872 | ||
873 | ||
874 | /* | |
875 | * signal handlers | |
876 | */ | |
877 | ||
878 | void leave() /* exit under normal conditions -- INT handler */ | |
879 | { | |
880 | if (!oneshot) { | |
881 | move(LINES - 1, 0); | |
882 | refresh(); | |
883 | endwin(); | |
1815bff5 A |
884 | } |
885 | exit(0); | |
886 | } | |
887 | ||
888 | void quit(status) /* exit under duress */ | |
889 | int status; | |
890 | { | |
b51d5b5f | 891 | if (!oneshot) |
1815bff5 | 892 | endwin(); |
1815bff5 A |
893 | exit(status); |
894 | } | |
895 | ||
896 | void sigwinch() | |
897 | { | |
898 | newLINES = 1; | |
899 | } | |
900 | ||
901 | ||
902 | /* | |
903 | * comparison function for "qsort" | |
904 | * Do first order sort based on cpu percentage computed by kernel and | |
905 | * second order sort based on total time for the process. | |
906 | */ | |
907 | ||
908 | int proc_compar(p1, p2) | |
909 | register struct proc_info **p1; | |
910 | register struct proc_info **p2; | |
911 | { | |
912 | if (sort_by_usage) { | |
913 | if ((*p1)->cpu_usage < (*p2)->cpu_usage) | |
914 | return(1); | |
915 | else if ((*p1)->cpu_usage > (*p2)->cpu_usage) | |
916 | return(-1); | |
917 | else { | |
918 | if ((*p1)->total_time.seconds < (*p2)->total_time.seconds) | |
919 | return(1); | |
920 | else | |
921 | return(-1); | |
922 | } | |
923 | } | |
924 | else { | |
925 | if ((*p1)->pid < (*p2)->pid) | |
926 | return(1); | |
927 | else | |
928 | return(-1); | |
929 | } | |
930 | } | |
931 | ||
932 | ||
933 | int nproc, total_procs, old_procs; | |
934 | struct kinfo_proc *kbase, *kpb; | |
935 | struct proc_info *proc, *pp, *oldproc; | |
936 | struct proc_info **pref, **prefp; | |
937 | ||
938 | int topn = 0; | |
939 | int wanted_topn = 0; | |
940 | vm_size_t pagesize; | |
941 | ||
942 | ||
943 | ||
944 | void grab_task(task) | |
945 | task_t task; | |
946 | { | |
947 | int pid; | |
948 | size_t size; | |
949 | kern_return_t ret; | |
950 | struct kinfo_proc ki; | |
951 | int mib[4]; | |
952 | ||
953 | ret = pid_for_task(task, &pid); | |
954 | if (ret != KERN_SUCCESS) | |
955 | return; | |
956 | size = sizeof(ki); | |
957 | mib[0] = CTL_KERN; | |
958 | mib[1] = KERN_PROC; | |
959 | mib[2] = KERN_PROC_PID; | |
960 | mib[3] = pid; | |
961 | ||
962 | if (sysctl(mib, 4, &ki, &size, NULL, 0) < 0) { | |
963 | perror("failure calling sysctl"); | |
964 | exit(1); | |
965 | } | |
966 | if (ki.kp_proc.p_stat == 0) { | |
967 | state_breakdown[0]++; | |
968 | return; | |
969 | } | |
970 | if (total_procs == nproc) { | |
971 | nproc *= 2; | |
972 | kbase = (struct kinfo_proc *) realloc(kbase, | |
973 | nproc*sizeof(struct kinfo_proc)); | |
974 | bzero(&kbase[total_procs], total_procs*sizeof(struct kinfo_proc)); | |
975 | proc = (struct proc_info *) realloc(proc, | |
976 | nproc*sizeof(struct proc_info)); | |
977 | bzero(&proc[total_procs], total_procs*sizeof(struct proc_info)); | |
978 | oldproc = (struct proc_info *) realloc(oldproc, | |
979 | nproc*sizeof(struct proc_info)); | |
980 | bzero(&oldproc[total_procs], total_procs*sizeof(struct proc_info)); | |
981 | pref = (struct proc_info **) realloc(pref, | |
982 | nproc*sizeof(struct proc_info *)); | |
983 | bzero(&pref[total_procs], total_procs*sizeof(struct proc_info *)); | |
984 | } | |
985 | kbase[total_procs] = ki; | |
986 | total_procs++; | |
987 | } | |
988 | ||
989 | void update_histdata() | |
990 | { | |
991 | struct proc_info *pp, *oldp; | |
992 | int i, j, pid; | |
993 | time_value_t elapsed_time; | |
994 | ||
995 | i = 0; | |
996 | pp = proc; | |
997 | ||
998 | // XXX use linear search since list is usually small | |
999 | ||
1000 | while (i < total_procs) { | |
1001 | j = 0; | |
1002 | oldp = oldproc; | |
1003 | pid = pp->pid; | |
1004 | ||
1005 | while (j < old_procs) { | |
1006 | if (oldp->pid == pid) { | |
1007 | pp->drprvt = pp->private - oldp->private; | |
1008 | pp->drshrd = pp->shared - oldp->shared; | |
1009 | pp->drsize = pp->resident_size - oldp->resident_size; | |
1010 | pp->dvsize = pp->virtual_size - oldp->virtual_size; | |
1011 | ||
1012 | pp->rvsize = pp->virtual_size - oldp->orig_virtual_size; | |
1013 | pp->orig_virtual_size = oldp->orig_virtual_size; | |
1014 | ||
1015 | pp->dnum_ports = pp->num_ports - oldp->orig_num_ports; | |
1016 | pp->orig_num_ports = oldp->orig_num_ports; | |
1017 | ||
1018 | if (pp->has_idle_thread == TRUE) { | |
1019 | if (events_accumulate) { | |
1020 | time_value_sub(&pp->idle_time, &oldp->beg_idle_time, &elapsed_time); | |
1021 | pp->beg_idle_time = oldp->beg_idle_time; | |
1022 | pp->idle_time = elapsed_time; | |
1023 | } else | |
1024 | time_value_sub(&pp->idle_time, &oldp->idle_time, &elapsed_time); | |
1025 | ||
1026 | pp->cpu_idle = (elapsed_time.seconds * 1000) + (elapsed_time.microseconds / 1000); | |
1027 | } | |
1028 | if (events_accumulate) { | |
1029 | time_value_sub(&pp->total_time, &oldp->beg_total_time, &elapsed_time); | |
1030 | pp->beg_total_time = oldp->beg_total_time; | |
1031 | pp->total_time = elapsed_time; | |
1032 | } else | |
1033 | time_value_sub(&pp->total_time, &oldp->total_time, &elapsed_time); | |
1034 | ||
1035 | pp->cpu_usage = (elapsed_time.seconds * 1000) + (elapsed_time.microseconds / 1000); | |
1036 | ||
1037 | if (events_delta) | |
1038 | { | |
1039 | pp->deltatei.pageins = pp->tei.pageins - oldp->tei.pageins; | |
1040 | pp->deltatei.faults = pp->tei.faults - oldp->tei.faults; | |
1041 | pp->deltatei.cow_faults = pp->tei.cow_faults - oldp->tei.cow_faults; | |
1042 | pp->deltatei.messages_sent = pp->tei.messages_sent - oldp->tei.messages_sent; | |
1043 | pp->deltatei.messages_received = pp->tei.messages_received - oldp->tei.messages_received; | |
1044 | pp->deltatei.syscalls_unix = pp->tei.syscalls_unix - oldp->tei.syscalls_unix; | |
1045 | pp->deltatei.syscalls_mach = pp->tei.syscalls_mach - oldp->tei.syscalls_mach; | |
1046 | pp->deltatei.csw = pp->tei.csw - oldp->tei.csw; | |
1047 | } | |
1048 | if (events_accumulate) | |
1049 | { | |
1050 | pp->deltatei.pageins = pp->tei.pageins - oldp->accumtei.pageins; | |
1051 | pp->deltatei.faults = pp->tei.faults - oldp->accumtei.faults; | |
1052 | pp->deltatei.cow_faults = pp->tei.cow_faults - oldp->accumtei.cow_faults; | |
1053 | pp->deltatei.messages_sent = pp->tei.messages_sent - oldp->accumtei.messages_sent; | |
1054 | pp->deltatei.messages_received = pp->tei.messages_received - oldp->accumtei.messages_received; | |
1055 | pp->deltatei.syscalls_unix = pp->tei.syscalls_unix - oldp->accumtei.syscalls_unix; | |
1056 | pp->deltatei.syscalls_mach = pp->tei.syscalls_mach - oldp->accumtei.syscalls_mach; | |
1057 | pp->deltatei.csw = pp->tei.csw - oldp->accumtei.csw; | |
1058 | ||
1059 | pp->accumtei = oldp->accumtei; | |
1060 | } | |
1061 | break; | |
1062 | } | |
1063 | j++; | |
1064 | oldp++; | |
1065 | } | |
1066 | if (j >= old_procs) { | |
1067 | if (events_accumulate) { | |
1068 | pp->accumtei = pp->tei; | |
1069 | pp->beg_total_time = pp->total_time; | |
1070 | pp->beg_idle_time = pp->idle_time; | |
1071 | ||
1072 | pp->idle_time.seconds = 0; | |
1073 | pp->idle_time.microseconds = 0; | |
1074 | pp->total_time.seconds = 0; | |
1075 | pp->total_time.microseconds = 0; | |
1076 | } | |
1077 | bzero(&pp->deltatei, sizeof (task_events_info_data_t)); | |
1078 | ||
1079 | pp->drprvt = 0; | |
1080 | pp->drshrd = 0; | |
1081 | pp->drsize = 0; | |
1082 | pp->dvsize = 0; | |
1083 | pp->rvsize = 0; | |
1084 | pp->dnum_ports = 0; | |
1085 | pp->cpu_usage = 0; | |
1086 | pp->cpu_idle = 0; | |
1087 | } | |
1088 | i++; | |
1089 | pp++; | |
1090 | } | |
1091 | bcopy(proc, oldproc, total_procs*sizeof(struct proc_info)); | |
1092 | old_procs = total_procs; | |
1093 | } | |
1094 | ||
1095 | void read_proc_table() | |
1096 | { | |
1097 | mach_port_t host; | |
1098 | processor_set_t *psets; | |
1099 | task_t *tasks; | |
1100 | unsigned int pcount, tcount; | |
1101 | kern_return_t ret; | |
1102 | processor_set_t p; | |
1103 | int i, j; | |
1104 | ||
1105 | total_procs = 0; | |
1106 | total_threads = 0; | |
1107 | ||
1108 | host = host_priv_port; | |
1109 | ||
1110 | if (host == MACH_PORT_NULL) { | |
1111 | printf("Insufficient privileges.\n"); | |
1112 | exit(0); | |
1113 | } | |
1114 | ret = host_processor_sets(host, &psets, &pcount); | |
1115 | if (ret != KERN_SUCCESS) { | |
1116 | mach_error("host_processor_sets", ret); | |
1117 | exit(0); | |
1118 | } | |
1119 | for (i = 0; i < pcount; i++) { | |
1120 | ret = host_processor_set_priv(host, psets[i], &p); | |
1121 | if (ret != KERN_SUCCESS) { | |
1122 | mach_error("host_processor_set_priv", ret); | |
1123 | exit(0); | |
1124 | } | |
1125 | ||
1126 | ret = processor_set_tasks(p, &tasks, &tcount); | |
1127 | if (ret != KERN_SUCCESS) { | |
1128 | mach_error("processor_set_tasks", ret); | |
1129 | exit(0); | |
1130 | } | |
1131 | for (j = 0; j < tcount; j++) { | |
1132 | grab_task(tasks[j]); | |
1133 | // don't delete our own task port | |
1134 | if (tasks[j] != mach_task_self()) | |
1135 | mach_port_deallocate(mach_task_self(), | |
1136 | tasks[j]); | |
1137 | } | |
1138 | vm_deallocate(mach_task_self(), (vm_address_t)tasks, | |
1139 | tcount * sizeof(task_t)); | |
1140 | mach_port_deallocate(mach_task_self(), p); | |
1141 | mach_port_deallocate(mach_task_self(), psets[i]); | |
1142 | } | |
1143 | vm_deallocate(mach_task_self(), (vm_address_t)psets, | |
1144 | pcount * sizeof(processor_set_t)); | |
1145 | } | |
1146 | ||
1147 | kern_return_t getCPU(cpucounters) | |
1148 | host_cpu_load_info_t cpucounters; | |
1149 | { | |
1150 | mach_msg_type_number_t count; | |
1151 | kern_return_t kr; | |
1152 | ||
1153 | count = HOST_CPU_LOAD_INFO_COUNT; | |
1154 | kr = host_statistics (host_priv_port, HOST_CPU_LOAD_INFO, | |
1155 | (host_info_t)cpucounters, &count); | |
1156 | ||
1157 | return(kr); | |
1158 | } | |
1159 | ||
1160 | updateCPU() | |
1161 | { | |
1162 | ||
1163 | if (events_accumulate) { | |
1164 | userticks = curcounters.cpu_ticks[CPU_STATE_USER]- | |
1165 | startcounters.cpu_ticks[CPU_STATE_USER]; | |
1166 | ||
1167 | systicks = curcounters.cpu_ticks[CPU_STATE_SYSTEM]- | |
1168 | startcounters.cpu_ticks[CPU_STATE_SYSTEM]; | |
1169 | ||
1170 | idleticks = curcounters.cpu_ticks[CPU_STATE_IDLE]- | |
1171 | startcounters.cpu_ticks[CPU_STATE_IDLE]; | |
1172 | } else if (events_only && !events_delta) { | |
1173 | ||
1174 | userticks = curcounters.cpu_ticks[CPU_STATE_USER]; | |
1175 | ||
1176 | systicks = curcounters.cpu_ticks[CPU_STATE_SYSTEM]; | |
1177 | ||
1178 | idleticks = curcounters.cpu_ticks[CPU_STATE_IDLE]; | |
1179 | } else { | |
1180 | userticks = curcounters.cpu_ticks[CPU_STATE_USER]- | |
1181 | lastcounters.cpu_ticks[CPU_STATE_USER]; | |
1182 | ||
1183 | systicks = curcounters.cpu_ticks[CPU_STATE_SYSTEM]- | |
1184 | lastcounters.cpu_ticks[CPU_STATE_SYSTEM]; | |
1185 | ||
1186 | idleticks = curcounters.cpu_ticks[CPU_STATE_IDLE]- | |
1187 | lastcounters.cpu_ticks[CPU_STATE_IDLE]; | |
1188 | ||
1189 | lastcounters = curcounters; | |
1190 | } | |
1191 | totalticks = userticks + systicks + idleticks; | |
1192 | } | |
1193 | ||
1194 | ||
1195 | ||
1196 | main(argc, argv) | |
1197 | int argc; | |
1198 | char *argv[]; | |
1199 | { | |
1200 | char *myname = "top"; | |
1c51fdde | 1201 | int ch; |
1815bff5 A |
1202 | int delay = Default_DELAY; |
1203 | kern_return_t error; | |
1204 | ||
1205 | void screen_update(); | |
1206 | ||
1207 | /* get our name */ | |
1208 | if (argc > 0) { | |
1209 | if ((myname = rindex(argv[0], '/')) == 0) { | |
1210 | myname = argv[0]; | |
1211 | } | |
1212 | else { | |
1213 | myname++; | |
1214 | } | |
1215 | } | |
1216 | ||
1217 | /* check for options */ | |
1218 | sort_by_usage = 0; | |
1219 | wide_output = 0; | |
1220 | do_proc0_vm = 0; | |
1221 | events_only = 0; | |
1222 | events_delta = 0; | |
1223 | events_accumulate = 0; | |
1224 | ||
1c51fdde A |
1225 | while ((ch = getopt(argc, argv, "uwks:edal:")) != EOF) { |
1226 | switch(ch) { | |
1815bff5 | 1227 | case 's': |
1c51fdde A |
1228 | delay = atoi(optarg); |
1229 | break; | |
1815bff5 A |
1230 | case 'u': |
1231 | sort_by_usage = 1; | |
1232 | break; | |
1233 | case 'w': | |
1234 | wide_output = 1; | |
1235 | break; | |
1236 | case 'k': | |
1237 | do_proc0_vm = 1; | |
1238 | break; | |
1239 | case 'e': | |
1240 | events_only = 1; | |
1241 | break; | |
1242 | case 'd': | |
1243 | events_only = 1; | |
1244 | events_delta = 1; | |
1245 | break; | |
1246 | case 'a': | |
1247 | events_only = 1; | |
1248 | events_accumulate = 1; | |
1249 | break; | |
1250 | case 'l': | |
1c51fdde | 1251 | logcnt = atoi(optarg); |
1815bff5 A |
1252 | oneshot = 1; |
1253 | LINES = 80; | |
1254 | COLS = 132; | |
1255 | break; | |
1256 | default: | |
1c51fdde | 1257 | fprintf(stderr, "Usage: %s [-u] [-w] [-k] [-sn] [-e | -d | -a] [-ln] [number]\n", myname); |
1815bff5 A |
1258 | fprintf(stderr, " -u enables sort by usage\n"); |
1259 | fprintf(stderr, " -w enables wide output of additional info\n"); | |
1260 | fprintf(stderr, " -k generate vm info for kernel(proc 0)... expensive\n"); | |
1261 | fprintf(stderr, " -sn change sample rate to every n seconds\n"); | |
1262 | fprintf(stderr, " -e switch to events info counter mode\n"); | |
1263 | fprintf(stderr, " -d switch to events info counter delta mode\n"); | |
1264 | fprintf(stderr, " -a switch to events info counter accumulate mode\n"); | |
1265 | fprintf(stderr, " -ln log n samples\n"); | |
1266 | fprintf(stderr, " number limit number of processes monitored\n"); | |
1267 | ||
1268 | exit(1); | |
1269 | } | |
1815bff5 | 1270 | } |
1c51fdde A |
1271 | |
1272 | argc -= optind; | |
1273 | //argv += optind; | |
1274 | ||
1815bff5 A |
1275 | if (events_only) |
1276 | { | |
1277 | if ( wide_output || do_proc0_vm) | |
1278 | { | |
1279 | fprintf(stderr, " The -w and -k flag have no effect in event mode.\n"); | |
1280 | wide_output = 0; | |
1281 | do_proc0_vm = 0; | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | host_priv_port = get_host_priv(); | |
1286 | host_port = get_host_port(); | |
1287 | ||
1288 | /* get count of top processes to display (if any) */ | |
1c51fdde A |
1289 | if (argc) { |
1290 | wanted_topn = topn = atoi(argv[optind]); | |
1815bff5 A |
1291 | } else |
1292 | wanted_topn = -1; | |
1293 | ||
1294 | /* allocate space for proc structure array and array of pointers */ | |
1295 | nproc = 50; /* starting point */ | |
1296 | kbase = (struct kinfo_proc *) malloc(nproc*sizeof(struct kinfo_proc)); | |
1297 | bzero(kbase, nproc*sizeof(struct kinfo_proc)); | |
1298 | proc = (struct proc_info *) malloc(nproc*sizeof(struct proc_info)); | |
1299 | bzero(proc, nproc*sizeof(struct proc_info)); | |
1300 | oldproc = (struct proc_info *) malloc(nproc*sizeof(struct proc_info)); | |
1301 | bzero(oldproc, nproc*sizeof(struct proc_info)); | |
1302 | pref = (struct proc_info **) malloc(nproc*sizeof(struct proc_info *)); | |
1303 | bzero(pref, nproc*sizeof(struct proc_info *)); | |
1304 | ||
1305 | (void) host_page_size(host_port, &pagesize); | |
1306 | /* initializes curses and screen (last) */ | |
1307 | ||
1308 | if (!oneshot) { | |
1815bff5 | 1309 | initscr(); |
b51d5b5f A |
1310 | cbreak(); |
1311 | timeout(delay * 1000); | |
1312 | noecho(); | |
1815bff5 A |
1313 | erase(); |
1314 | clear(); | |
1315 | refresh(); | |
1316 | } | |
1317 | /* set up signal handlers */ | |
1318 | signal(SIGINT, leave); | |
1319 | signal(SIGQUIT, leave); | |
1320 | signal(SIGWINCH, sigwinch); | |
1321 | ||
1322 | /* can only display (LINES - Header_lines) processes */ | |
1323 | if (topn > LINES - Header_lines) { | |
1324 | if (!oneshot) | |
1325 | printw("Warning: this terminal can only display %d processes...\n", | |
1326 | LINES - Header_lines); | |
1327 | else | |
1328 | printf("Warning: this terminal can only display %d processes...\n", | |
1329 | LINES - Header_lines); | |
1330 | ||
1331 | if (!oneshot) | |
1332 | refresh(); | |
1333 | sleep(2); | |
1334 | topn = LINES - Header_lines; | |
1335 | if (!oneshot) | |
1336 | clear(); | |
1337 | } | |
1338 | if (topn == 0) { // use default | |
1339 | // leave one blank line at bottom | |
1340 | ||
1341 | topn = LINES - Header_lines - 1; | |
1342 | } | |
1343 | ||
1344 | /* prime the pump for gathering networking stats */ | |
1345 | kread(0, 0, 0); | |
1346 | ||
1347 | /**************************************************/ | |
1348 | /* get ports and services for drive stats */ | |
1349 | /* Obtain the I/O Kit communication handle */ | |
1350 | ||
1351 | error = IOMasterPort(bootstrap_port, &masterPort); | |
1352 | ||
1353 | /* Obtain the list of all drive objects */ | |
1354 | ||
1355 | error = IOServiceGetMatchingServices(masterPort, | |
1356 | IOServiceMatching("IOBlockStorageDriver"), | |
1357 | &drivelist); | |
1358 | getCPU(&lastcounters); | |
1359 | startcounters = lastcounters; | |
1360 | ||
1361 | gettimeofday(&cur_tod, NULL); | |
1362 | start_tod = cur_tod; | |
1363 | elapsed_milliseconds = -1; | |
1364 | ||
1365 | /* main loop */ | |
1366 | ||
1367 | while (1) { | |
1368 | int n; | |
1369 | ||
1370 | if (newLINES) { | |
b51d5b5f | 1371 | newLINES = 0; |
1815bff5 A |
1372 | |
1373 | if (!oneshot) { | |
b51d5b5f A |
1374 | struct winsize size; |
1375 | ||
1376 | if (ioctl(1, TIOCGWINSZ, &size) != -1) { | |
1377 | resizeterm(size.ws_row, size.ws_col); | |
1378 | erase(); | |
1379 | clear(); | |
1380 | } | |
1815bff5 A |
1381 | } |
1382 | n = LINES - Header_lines; | |
1383 | ||
1384 | if (topn >= n) | |
1385 | topn = n; | |
1386 | else { | |
1387 | if (wanted_topn == -1) | |
1388 | topn = n; | |
1389 | else if (topn < wanted_topn) { | |
1390 | if (wanted_topn < n) | |
1391 | topn = wanted_topn; | |
1392 | else | |
1393 | topn = n; | |
1394 | } | |
1395 | } | |
1815bff5 A |
1396 | } |
1397 | (void)screen_update(); | |
1398 | ||
1399 | if (!oneshot) { | |
b51d5b5f | 1400 | int c; |
1815bff5 | 1401 | |
b51d5b5f A |
1402 | if ((c = getch()) != ERR && (char)c == 'q') |
1403 | leave(); | |
1815bff5 A |
1404 | } else |
1405 | sleep(delay); | |
1406 | } | |
1407 | } | |
1408 | ||
1409 | void screen_update() | |
1410 | { | |
1411 | char c; | |
1412 | int i, n, mpid; | |
1413 | int active_procs; | |
1414 | int avenrun[3]; | |
1415 | long curr_time; | |
1416 | long elapsed_secs; | |
1417 | unsigned long long total_fw_vsize; | |
1418 | unsigned long long total_virtual_size; | |
1419 | unsigned long long total_private_size; | |
1420 | unsigned long long total_shared_size; | |
1c51fdde | 1421 | unsigned int total_memory_regions = 0; |
1815bff5 A |
1422 | unsigned int total_shared_objects; |
1423 | unsigned int total_fw_code_size; | |
1424 | unsigned int total_fw_data_size; | |
1425 | unsigned int total_fw_linkedit_size; | |
1426 | unsigned int total_frameworks; | |
1427 | vm_statistics_data_t vm_stat; | |
1428 | struct host_load_info load_data; | |
1429 | int host_count; | |
1430 | kern_return_t error; | |
1431 | char tbuf[256]; | |
1432 | char *dp; | |
1433 | int clen; | |
1434 | ||
1435 | bzero((char *)state_breakdown, sizeof(state_breakdown)); | |
1436 | ||
1437 | if (!oneshot) { | |
1438 | /* clear for new display */ | |
1439 | erase(); | |
1440 | } | |
1441 | /* read all of the process information */ | |
1442 | read_proc_table(); | |
1443 | ||
1444 | /* get the load averages */ | |
1445 | host_count = sizeof(load_data)/sizeof(integer_t); | |
1446 | error = host_statistics(host_priv_port, HOST_LOAD_INFO, | |
1447 | (host_info_t)&load_data, &host_count); | |
1448 | if (error != KERN_SUCCESS) { | |
1449 | mach_error("host_statistics", error); | |
1450 | exit(EXIT_FAILURE); | |
1451 | } | |
1452 | ||
1453 | avenrun[0] = load_data.avenrun[0]; | |
1454 | avenrun[1] = load_data.avenrun[1]; | |
1455 | avenrun[2] = load_data.avenrun[2]; | |
1456 | ||
1457 | /* get total - systemwide main memory usage structure */ | |
1458 | host_count = sizeof(vm_stat)/sizeof(integer_t); | |
1459 | error = host_statistics(host_priv_port, HOST_VM_INFO, | |
1460 | (host_info_t)&vm_stat, &host_count); | |
1461 | if (error != KERN_SUCCESS) { | |
1462 | mach_error("host_info", error); | |
1463 | exit(EXIT_FAILURE); | |
1464 | } | |
1c51fdde A |
1465 | |
1466 | if (events_only) { | |
1467 | getNETWORKcounters(); | |
1468 | getDISKcounters(); | |
1469 | } | |
1815bff5 A |
1470 | /* count up process states and get pointers to interesting procs */ |
1471 | ||
1472 | mpid = 0; | |
1473 | active_procs = 0; | |
1474 | total_virtual_size = 0; | |
1475 | total_private_size = 0; | |
1476 | total_fw_private = 0; | |
1477 | ||
1478 | prefp = pref; | |
1479 | for (kpb = kbase, pp = proc, i = 0; | |
1480 | i < total_procs; | |
1481 | kpb++, pp++, i++) { | |
1482 | ||
1483 | /* place pointers to each valid proc structure in pref[] */ | |
1484 | get_proc_info(kpb, pp); | |
1485 | ||
1486 | if (kpb->kp_proc.p_stat != 0) { | |
1487 | *prefp++ = pp; | |
1488 | active_procs++; | |
1489 | if (pp->pid > mpid) | |
1490 | mpid = pp->pid; | |
1491 | ||
1492 | if ((unsigned int)pp->state > (unsigned int)STATE_MAX) | |
1493 | pp->state = STATE_MAX; | |
1494 | state_breakdown[pp->state]++; | |
1495 | total_virtual_size += pp->virtual_size; | |
1496 | total_private_size += pp->private; | |
1497 | total_memory_regions += pp->obj_count; | |
1498 | } | |
1499 | else | |
1500 | state_breakdown[0]++; | |
1501 | } | |
1502 | /* get the cpu counters */ | |
1503 | getCPU(&curcounters); | |
1504 | updateCPU(); | |
1505 | ||
1506 | if (elapsed_milliseconds != -1) { | |
1507 | last_tod = cur_tod; | |
1508 | gettimeofday(&cur_tod, NULL); | |
1509 | ||
1510 | if (events_accumulate) | |
1511 | timersub(&cur_tod, &start_tod, &elapsed_tod); | |
1512 | else | |
1513 | timersub(&cur_tod, &last_tod, &elapsed_tod); | |
1514 | ||
1515 | elapsed_milliseconds = (elapsed_tod.tv_sec * 1000) + (elapsed_tod.tv_usec / 1000); | |
1516 | } else | |
1517 | elapsed_milliseconds = 0; | |
1518 | ||
1519 | if (!events_only) { | |
1520 | pmem_fw_resident(&total_frameworks, &total_fw_vsize, &total_fw_code_size, &total_fw_data_size, &total_fw_linkedit_size); | |
1521 | ||
1522 | pmem_shared_resident(&total_shared_size, &total_shared_objects); | |
1523 | } | |
1524 | if (!oneshot) | |
1525 | move(0,0); | |
1526 | ||
1527 | /* display process state breakdown */ | |
1528 | sprintf(tbuf, "Processes: %d total", total_procs); | |
1529 | clen = strlen(tbuf); | |
1530 | ||
1531 | ||
1532 | for (i = 0; i <= STATE_MAX; i++) { | |
1533 | if (state_breakdown[i] != 0) { | |
1534 | sprintf(&tbuf[clen], ", %d %s%s", | |
1535 | state_breakdown[i], | |
1536 | state_name[i], | |
1537 | (i == 0 && state_breakdown[0] > 1) ? "s" : "" | |
1538 | ); | |
1539 | ||
1540 | clen = clen + strlen(&tbuf[clen]); | |
1541 | } | |
1542 | } | |
1543 | sprintf(&tbuf[clen], "... %d threads", total_threads); | |
1544 | ||
1545 | clen = clen + strlen(&tbuf[clen]); | |
1546 | /* | |
1547 | * Display the current time. | |
1548 | * "ctime" always returns a string that looks like this: | |
1549 | * | |
1550 | * Sun Sep 16 01:03:52 1973 | |
1551 | * 012345678901234567890123 | |
1552 | * 1 2 | |
1553 | * | |
1554 | * We want indices 11 thru 18 (length 8). | |
1555 | */ | |
1556 | curr_time = time((long *)0); | |
1557 | ||
1558 | if (start_time == 0) | |
1559 | start_time = curr_time; | |
1560 | ||
1561 | memset(&tbuf[clen], ' ', 111 - clen); | |
1562 | ||
1563 | if (wide_output) | |
1564 | clen = 118 - 8; | |
1565 | else if (events_accumulate) | |
1566 | clen = 103 - 8; | |
1567 | else if (events_only && !events_delta) | |
1568 | clen = 115 - 8; | |
1569 | else | |
1570 | clen = 79 - 8; | |
1571 | ||
1572 | sprintf(&tbuf[clen], "%-8.8s", &(ctime(&curr_time)[11])); | |
1573 | clen = clen + strlen(&tbuf[clen]); | |
1574 | ||
1575 | if (events_accumulate) { | |
1576 | int hours; | |
1577 | int minutes; | |
1578 | ||
1579 | elapsed_secs = curr_time - start_time; | |
1580 | minutes = elapsed_secs / 60; | |
1581 | hours = minutes / 60; | |
1582 | ||
1583 | sprintf(&tbuf[clen], " %3ld:%02ld:%02ld\n", hours, minutes % 60, elapsed_secs % 60); | |
1584 | } else { | |
1585 | sprintf(&tbuf[clen], "\n"); | |
1586 | } | |
1587 | ||
1588 | if (tbuf[COLS-2] != '\n') { | |
1589 | tbuf[COLS-1] = '\n'; | |
1590 | tbuf[COLS] = 0; | |
1591 | } | |
1592 | if (!oneshot) | |
1593 | printw(tbuf); | |
1594 | else | |
1595 | printf(tbuf); | |
1596 | ||
1597 | /* display the load averages */ | |
1598 | sprintf(tbuf, "Load Avg"); | |
1599 | clen = strlen(tbuf); | |
1600 | ||
1601 | for (i = 0; i < 3; i++) { | |
1602 | sprintf(&tbuf[clen], "%s %4.2f", i == 0 ? ": " : ",", | |
1603 | (double)avenrun[i] / LOAD_SCALE); | |
1604 | clen = clen + strlen(&tbuf[clen]); | |
1605 | } | |
1606 | if (totalticks) { | |
1607 | sprintf(&tbuf[clen], " CPU usage: %.1f%%%% user, %.1f%%%% sys, %.1f%%%% idle\n", | |
1608 | (100*userticks)/totalticks, (100*systicks)/totalticks, (100*idleticks)/totalticks); | |
1609 | clen = clen + strlen(&tbuf[clen]); | |
1610 | } | |
1611 | if (tbuf[COLS-2] != '\n') { | |
1612 | tbuf[COLS-1] = '\n'; | |
1613 | tbuf[COLS] = 0; | |
1614 | } | |
1615 | if (!oneshot) | |
1616 | printw(tbuf); | |
1617 | else | |
1618 | printf(tbuf); | |
1619 | ||
1620 | if (!events_only) { | |
1621 | sprintf(tbuf, "SharedLibs: num = %4d, ", total_frameworks); | |
1622 | clen = strlen(tbuf); | |
1623 | sprintf(&tbuf[clen], "resident = %s code, ", mem_to_string((unsigned long long)total_fw_code_size)); | |
1624 | clen = clen + strlen(&tbuf[clen]); | |
1625 | sprintf(&tbuf[clen], "%s data, ", mem_to_string((unsigned long long)total_fw_data_size)); | |
1626 | clen = clen + strlen(&tbuf[clen]); | |
1627 | sprintf(&tbuf[clen], "%s LinkEdit\n", mem_to_string((unsigned long long)total_fw_linkedit_size)); | |
1628 | ||
1629 | if (tbuf[COLS-2] != '\n') { | |
1630 | tbuf[COLS-1] = '\n'; | |
1631 | tbuf[COLS] = 0; | |
1632 | } | |
1633 | if (!oneshot) | |
1634 | printw(tbuf); | |
1635 | else | |
1636 | printf(tbuf); | |
1637 | ||
1638 | sprintf(tbuf, "MemRegions: num = %4d, ", total_memory_regions); | |
1639 | clen = strlen(tbuf); | |
1640 | sprintf(&tbuf[clen], "resident = %s + ", mem_to_string(total_private_size - total_fw_private)); | |
1641 | clen = clen + strlen(&tbuf[clen]); | |
1642 | sprintf(&tbuf[clen], "%s private, ", mem_to_string(total_fw_private)); | |
1643 | clen = clen + strlen(&tbuf[clen]); | |
1644 | sprintf(&tbuf[clen], "%s shared\n", mem_to_string(total_shared_size)); | |
1645 | ||
1646 | if (tbuf[COLS-2] != '\n') { | |
1647 | tbuf[COLS-1] = '\n'; | |
1648 | tbuf[COLS] = 0; | |
1649 | } | |
1650 | if (!oneshot) | |
1651 | printw(tbuf); | |
1652 | else | |
1653 | printf(tbuf); | |
1654 | ||
1655 | /* display main memory statistics */ | |
1656 | { | |
1657 | unsigned long long total_resident_size, | |
1658 | active_resident_size, | |
1659 | inactive_resident_size, | |
1660 | wire_resident_size, | |
1661 | free_size; | |
1662 | ||
756446ec A |
1663 | active_resident_size = (unsigned long long) vm_stat.active_count * (unsigned long long) pagesize; |
1664 | inactive_resident_size = (unsigned long long) vm_stat.inactive_count * (unsigned long long) pagesize; | |
1665 | wire_resident_size = (unsigned long long) vm_stat.wire_count * (unsigned long long) pagesize; | |
1666 | total_resident_size = (unsigned long long) (vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count) * (unsigned long long) pagesize; | |
1667 | free_size = (unsigned long long) vm_stat.free_count * (unsigned long long) pagesize; | |
1815bff5 A |
1668 | |
1669 | sprintf(tbuf, "PhysMem: "); | |
1670 | clen = strlen(tbuf); | |
1671 | sprintf(&tbuf[clen], "%s wired, ", mem_to_string(wire_resident_size)); | |
1672 | clen = clen + strlen(&tbuf[clen]); | |
1673 | sprintf(&tbuf[clen], "%s active, ", mem_to_string(active_resident_size)); | |
1674 | clen = clen + strlen(&tbuf[clen]); | |
1675 | sprintf(&tbuf[clen], "%s inactive, ", mem_to_string(inactive_resident_size)); | |
1676 | clen = clen + strlen(&tbuf[clen]); | |
1677 | sprintf(&tbuf[clen], "%s used, ", mem_to_string(total_resident_size)); | |
1678 | clen = clen + strlen(&tbuf[clen]); | |
1679 | sprintf(&tbuf[clen], "%s free\n", mem_to_string(free_size)); | |
1680 | ||
1681 | if (tbuf[COLS-2] != '\n') { | |
1682 | tbuf[COLS-1] = '\n'; | |
1683 | tbuf[COLS] = 0; | |
1684 | } | |
1685 | if (!oneshot) | |
1686 | printw(tbuf); | |
1687 | else | |
1688 | printf(tbuf); | |
1689 | } | |
1690 | } else { | |
1691 | int i_io, o_io, i_kbytes, o_kbytes; | |
1692 | ||
1693 | i_io = o_io = i_kbytes = o_kbytes = 0; | |
1694 | ||
1695 | if (events_delta) { | |
1696 | if (i_net.io_prev || o_net.io_prev) { | |
1697 | i_io = i_net.io - i_net.io_prev; | |
1698 | o_io = o_net.io - o_net.io_prev; | |
1699 | i_kbytes = i_net.kbytes - i_net.kbytes_prev; | |
1700 | o_kbytes = o_net.kbytes - o_net.kbytes_prev; | |
1701 | } | |
1702 | } else if (events_accumulate) { | |
1703 | if (i_net.io_prev || o_net.io_prev) { | |
1704 | i_net.io_accum += i_net.io - i_net.io_prev; | |
1705 | o_net.io_accum += o_net.io - o_net.io_prev; | |
1706 | i_net.kbytes_accum += i_net.kbytes - i_net.kbytes_prev; | |
1707 | o_net.kbytes_accum += o_net.kbytes - o_net.kbytes_prev; | |
1708 | ||
1709 | i_io = i_net.io_accum; | |
1710 | o_io = o_net.io_accum; | |
1711 | i_kbytes = i_net.kbytes_accum; | |
1712 | o_kbytes = o_net.kbytes_accum; | |
1713 | } | |
1714 | } else { | |
1715 | i_io = i_net.io; | |
1716 | o_io = o_net.io; | |
1717 | i_kbytes = i_net.kbytes; | |
1718 | o_kbytes = o_net.kbytes; | |
1719 | } | |
1c51fdde | 1720 | sprintf(tbuf, "Networks:%10d ipkts/%dK", i_io, i_kbytes); |
1815bff5 A |
1721 | clen = strlen(tbuf); |
1722 | memset(&tbuf[clen], ' ', 36 - clen); | |
1723 | sprintf(&tbuf[36], "%10d opkts /%dK\n", o_io, o_kbytes); | |
1724 | ||
1725 | i_net.io_prev = i_net.io; | |
1726 | o_net.io_prev = o_net.io; | |
1727 | i_net.kbytes_prev = i_net.kbytes; | |
1728 | o_net.kbytes_prev = o_net.kbytes; | |
1729 | ||
1730 | if (tbuf[COLS-2] != '\n') { | |
1731 | tbuf[COLS-1] = '\n'; | |
1732 | tbuf[COLS] = 0; | |
1733 | } | |
1734 | if (!oneshot) | |
1735 | printw(tbuf); | |
1736 | else | |
1737 | printf(tbuf); | |
1738 | ||
1739 | i_io = o_io = i_kbytes = o_kbytes = 0; | |
1740 | ||
1741 | if (events_delta) { | |
1742 | if (i_dsk.io_prev || o_dsk.io_prev) { | |
1743 | i_io = i_dsk.io - i_dsk.io_prev; | |
1744 | o_io = o_dsk.io - o_dsk.io_prev; | |
1745 | i_kbytes = i_dsk.kbytes - i_dsk.kbytes_prev; | |
1746 | o_kbytes = o_dsk.kbytes - o_dsk.kbytes_prev; | |
1747 | } | |
1748 | } else if (events_accumulate) { | |
1749 | if (i_dsk.io_prev || o_dsk.io_prev) { | |
1750 | i_dsk.io_accum += i_dsk.io - i_dsk.io_prev; | |
1751 | o_dsk.io_accum += o_dsk.io - o_dsk.io_prev; | |
1752 | i_dsk.kbytes_accum += i_dsk.kbytes - i_dsk.kbytes_prev; | |
1753 | o_dsk.kbytes_accum += o_dsk.kbytes - o_dsk.kbytes_prev; | |
1754 | ||
1755 | i_io = i_dsk.io_accum; | |
1756 | o_io = o_dsk.io_accum; | |
1757 | i_kbytes = i_dsk.kbytes_accum; | |
1758 | o_kbytes = o_dsk.kbytes_accum; | |
1759 | } | |
1760 | } else { | |
1761 | i_io = i_dsk.io; | |
1762 | o_io = o_dsk.io; | |
1763 | i_kbytes = i_dsk.kbytes; | |
1764 | o_kbytes = o_dsk.kbytes; | |
1765 | } | |
1c51fdde | 1766 | sprintf(tbuf, "Disks: %10d reads/%dK", i_io, i_kbytes); |
1815bff5 A |
1767 | clen = strlen(tbuf); |
1768 | memset(&tbuf[clen], ' ', 36 - clen); | |
1769 | sprintf(&tbuf[36], "%10d writes/%dK\n", o_io, o_kbytes); | |
1770 | ||
1771 | i_dsk.io_prev = i_dsk.io; | |
1772 | o_dsk.io_prev = o_dsk.io; | |
1773 | i_dsk.kbytes_prev = i_dsk.kbytes; | |
1774 | o_dsk.kbytes_prev = o_dsk.kbytes; | |
1775 | ||
1776 | if (tbuf[COLS-2] != '\n') { | |
1777 | tbuf[COLS-1] = '\n'; | |
1778 | tbuf[COLS] = 0; | |
1779 | } | |
1780 | if (!oneshot) | |
1781 | printw(tbuf); | |
1782 | else | |
1783 | printf(tbuf); | |
1784 | } | |
1785 | ||
1786 | /* display paging statistics */ | |
1787 | if (events_only) { | |
1788 | int pageins, pageouts; | |
1789 | ||
1790 | pageins = pageouts = 0; | |
1791 | ||
1792 | if (events_delta) { | |
1793 | if (i_vm.io_prev || o_vm.io_prev) { | |
1794 | pageins = vm_stat.pageins - i_vm.io_prev; | |
1795 | pageouts = vm_stat.pageouts - o_vm.io_prev; | |
1796 | } | |
1797 | } else if (events_accumulate) { | |
1798 | if (i_vm.io_prev || o_vm.io_prev) { | |
1799 | i_vm.io_accum += vm_stat.pageins - i_vm.io_prev; | |
1800 | o_vm.io_accum += vm_stat.pageouts - o_vm.io_prev; | |
1801 | ||
1802 | pageins = i_vm.io_accum; | |
1803 | pageouts = o_vm.io_accum; | |
1804 | } | |
1805 | } else { | |
1806 | pageins = vm_stat.pageins; | |
1807 | pageouts = vm_stat.pageouts; | |
1808 | } | |
1c51fdde | 1809 | sprintf(tbuf, "VM: %10d pageins", pageins); |
1815bff5 A |
1810 | clen = strlen(tbuf); |
1811 | memset(&tbuf[clen], ' ', 36 - clen); | |
1812 | sprintf(&tbuf[36], "%10d pageouts\n", pageouts); | |
1813 | } else { | |
1814 | sprintf(tbuf, "VM: %5.5s + ", mem_to_string(total_virtual_size)); | |
1815 | clen = strlen(tbuf); | |
1816 | sprintf(&tbuf[clen], "%5.5s ", mem_to_string(total_fw_vsize)); | |
1817 | clen = clen + strlen(&tbuf[clen]); | |
1818 | sprintf(&tbuf[clen], "%d(%d) pageins, ", vm_stat.pageins, vm_stat.pageins - (int)i_vm.io_prev); | |
1819 | clen = clen + strlen(&tbuf[clen]); | |
1820 | sprintf(&tbuf[clen], "%d(%d) pageouts\n", vm_stat.pageouts, vm_stat.pageouts - (int)o_vm.io_prev); | |
1821 | } | |
1822 | if (tbuf[COLS-2] != '\n') { | |
1823 | tbuf[COLS-1] = '\n'; | |
1824 | tbuf[COLS] = 0; | |
1825 | } | |
1826 | if (!oneshot) | |
1827 | printw(tbuf); | |
1828 | else | |
1829 | printf(tbuf); | |
1830 | ||
1831 | i_vm.io_prev = vm_stat.pageins; | |
1832 | o_vm.io_prev = vm_stat.pageouts; | |
1833 | ||
1834 | ||
1835 | /* display the processes */ | |
1836 | if (topn > 0) { | |
1837 | if (events_delta) | |
1838 | sprintf(tbuf, "\n PID COMMAND %%%%CPU TIME FAULTS PGINS/COWS MSENT/MRCVD BSD/MACH CSW\n"); | |
1839 | else if (events_only) | |
1840 | sprintf(tbuf, "\n PID COMMAND %%%%CPU TIME FAULTS PAGEINS COW_FAULTS MSGS_SENT MSGS_RCVD BSDSYSCALL MACHSYSCALL CSWITCH\n"); | |
1841 | else if (wide_output) | |
1842 | sprintf(tbuf, "\n PID COMMAND %%%%CPU TIME #TH #PRTS(delta) #MREGS VPRVT RPRVT(delta) RSHRD(delta) RSIZE(delta) VSIZE(delta)\n"); | |
1843 | else | |
1844 | sprintf(tbuf, "\n PID COMMAND %%%%CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE\n"); | |
1845 | ||
1846 | ||
1847 | if (tbuf[COLS] != '\n') { | |
1848 | tbuf[COLS+1] = '\n'; | |
1849 | tbuf[COLS+2] = 0; | |
1850 | } | |
1851 | if (!oneshot) | |
1852 | printw(tbuf); | |
1853 | else | |
1854 | printf(tbuf); | |
1855 | ||
1856 | update_histdata(); | |
1857 | ||
1858 | /* sort */ | |
1859 | qsort((char *)pref, | |
1860 | active_procs, | |
1861 | sizeof(struct proc_info *), | |
1862 | proc_compar); | |
1863 | ||
1864 | /* now, show the top whatever */ | |
1865 | if (active_procs > topn) | |
1866 | { | |
1867 | /* adjust for too many processes */ | |
1868 | active_procs = topn; | |
1869 | } | |
1870 | ||
1871 | for (prefp = pref, i = 0; i < active_procs; prefp++, i++) | |
1872 | { | |
1873 | pp = *prefp; | |
1874 | ||
1875 | sprintf(tbuf, "%5d", pp->pid); /* pid */ | |
1876 | clen = strlen(tbuf); | |
1877 | sprintf(&tbuf[clen], " %-10.10s ", pp->command); /* command */ | |
1878 | clen = clen + strlen(&tbuf[clen]); | |
1879 | ||
1880 | print_usage(&tbuf[clen], pp->cpu_usage); | |
1881 | clen = clen + strlen(&tbuf[clen]); | |
1882 | ||
1883 | sprintf(&tbuf[clen], " "); | |
1884 | clen++; | |
1885 | ||
1886 | print_time(&tbuf[clen], pp->total_time); /* cputime */ | |
1887 | clen = clen + strlen(&tbuf[clen]); | |
1888 | ||
1889 | ||
1890 | if (events_only) { | |
1891 | if (events_delta) { | |
1892 | sprintf(&tbuf[clen], " %6d", pp->deltatei.faults); | |
1893 | clen = clen + strlen(&tbuf[clen]); | |
1894 | sprintf(&tbuf[clen], " %5d", pp->deltatei.pageins); | |
1895 | clen = clen + strlen(&tbuf[clen]); | |
1896 | sprintf(&tbuf[clen], "/%-4d", pp->deltatei.cow_faults); | |
1897 | clen = clen + strlen(&tbuf[clen]); | |
1898 | sprintf(&tbuf[clen], " %5d", pp->deltatei.messages_sent); | |
1899 | clen = clen + strlen(&tbuf[clen]); | |
1900 | sprintf(&tbuf[clen], "/%-4d", pp->deltatei.messages_received); | |
1901 | clen = clen + strlen(&tbuf[clen]); | |
1902 | sprintf(&tbuf[clen], " %5d", pp->deltatei.syscalls_unix); | |
1903 | clen = clen + strlen(&tbuf[clen]); | |
1904 | sprintf(&tbuf[clen], "/%-5d", pp->deltatei.syscalls_mach); | |
1905 | clen = clen + strlen(&tbuf[clen]); | |
1906 | sprintf(&tbuf[clen], "%6d", pp->deltatei.csw); | |
1907 | clen = clen + strlen(&tbuf[clen]); | |
1908 | } else if (events_accumulate) { | |
1909 | sprintf(&tbuf[clen], " %-8d", pp->deltatei.faults); | |
1910 | clen = clen + strlen(&tbuf[clen]); | |
1911 | sprintf(&tbuf[clen], " %-8d", pp->deltatei.pageins); | |
1912 | clen = clen + strlen(&tbuf[clen]); | |
1913 | sprintf(&tbuf[clen], " %-10d", pp->deltatei.cow_faults); | |
1914 | clen = clen + strlen(&tbuf[clen]); | |
1915 | sprintf(&tbuf[clen], " %-10d", pp->deltatei.messages_sent); | |
1916 | clen = clen + strlen(&tbuf[clen]); | |
1917 | sprintf(&tbuf[clen], " %-10d", pp->deltatei.messages_received); | |
1918 | clen = clen + strlen(&tbuf[clen]); | |
1919 | sprintf(&tbuf[clen], " %-10d", pp->deltatei.syscalls_unix); | |
1920 | clen = clen + strlen(&tbuf[clen]); | |
1921 | sprintf(&tbuf[clen], " %-11d", pp->deltatei.syscalls_mach); | |
1922 | clen = clen + strlen(&tbuf[clen]); | |
1923 | sprintf(&tbuf[clen], " %-8d", pp->deltatei.csw); | |
1924 | clen = clen + strlen(&tbuf[clen]); | |
1925 | } else { | |
1926 | sprintf(&tbuf[clen], " %-8d", pp->tei.faults); | |
1927 | clen = clen + strlen(&tbuf[clen]); | |
1928 | sprintf(&tbuf[clen], " %-8d", pp->tei.pageins); | |
1929 | clen = clen + strlen(&tbuf[clen]); | |
1930 | sprintf(&tbuf[clen], " %-10d", pp->tei.cow_faults); | |
1931 | clen = clen + strlen(&tbuf[clen]); | |
1932 | sprintf(&tbuf[clen], " %-10d", pp->tei.messages_sent); | |
1933 | clen = clen + strlen(&tbuf[clen]); | |
1934 | sprintf(&tbuf[clen], " %-10d", pp->tei.messages_received); | |
1935 | clen = clen + strlen(&tbuf[clen]); | |
1936 | sprintf(&tbuf[clen], " %-10d", pp->tei.syscalls_unix); | |
1937 | clen = clen + strlen(&tbuf[clen]); | |
1938 | sprintf(&tbuf[clen], " %-11d", pp->tei.syscalls_mach); | |
1939 | clen = clen + strlen(&tbuf[clen]); | |
1940 | sprintf(&tbuf[clen], " %-8d", pp->tei.csw); | |
1941 | clen = clen + strlen(&tbuf[clen]); | |
1942 | } | |
1943 | } else { | |
1944 | ||
1945 | sprintf(&tbuf[clen], " %3d", pp->num_threads); /* # of threads */ | |
1946 | clen = clen + strlen(&tbuf[clen]); | |
1947 | sprintf(&tbuf[clen], " %5d", pp->num_ports); /* # of ports */ | |
1948 | clen = clen + strlen(&tbuf[clen]); | |
1949 | ||
1950 | if (wide_output) { | |
1951 | if (pp->dnum_ports) | |
1952 | sprintf(&tbuf[clen], "(%5d)", pp->dnum_ports); | |
1953 | else | |
1954 | sprintf(&tbuf[clen], " "); | |
1955 | clen = clen + strlen(&tbuf[clen]); | |
1956 | } | |
1957 | if (pp->pid || do_proc0_vm) | |
1958 | sprintf(&tbuf[clen], " %4d", pp->obj_count); | |
1959 | else | |
1960 | sprintf(&tbuf[clen], " -"); | |
1961 | clen = clen + strlen(&tbuf[clen]); | |
1962 | ||
1963 | if (wide_output) { | |
1964 | if (pp->pid || do_proc0_vm) { | |
1965 | sprintf(&tbuf[clen], " %5.5s", mem_to_string((unsigned long long)pp->vprivate)); /* res size */ | |
1966 | clen = clen + strlen(&tbuf[clen]); | |
1967 | sprintf(&tbuf[clen], " %5.5s", mem_to_string((unsigned long long)pp->private)); /* res size */ | |
1968 | clen = clen + strlen(&tbuf[clen]); | |
1969 | ||
1970 | if (pp->drprvt) | |
1971 | sprintf(&tbuf[clen], "(%5.5s)", offset_to_string(pp->drprvt)); | |
1972 | else | |
1973 | sprintf(&tbuf[clen], " "); | |
1974 | } else | |
1975 | sprintf(&tbuf[clen], " - - "); | |
1976 | } else { | |
1977 | if (pp->drprvt == 0) | |
1978 | dp = " "; | |
1979 | else if ((int)pp->drprvt > 0) | |
1980 | dp = "+"; | |
1981 | else | |
1982 | dp = "-"; | |
1983 | ||
1984 | if (pp->pid || do_proc0_vm) | |
1985 | sprintf(&tbuf[clen], " %5.5s%s", mem_to_string((unsigned long long)pp->private), dp); /* res size */ | |
1986 | else | |
1987 | sprintf(&tbuf[clen], " -"); | |
1988 | } | |
1989 | clen = clen + strlen(&tbuf[clen]); | |
1990 | ||
1991 | if (wide_output) { | |
1992 | if (pp->pid || do_proc0_vm) { | |
1993 | sprintf(&tbuf[clen], " %5.5s", mem_to_string((unsigned long long)pp->shared)); | |
1994 | clen = clen + strlen(&tbuf[clen]); | |
1995 | ||
1996 | if (pp->drshrd) | |
1997 | sprintf(&tbuf[clen], "(%5.5s)", offset_to_string(pp->drshrd)); | |
1998 | else | |
1999 | sprintf(&tbuf[clen], " "); | |
2000 | } else | |
2001 | sprintf(&tbuf[clen], " - "); | |
2002 | } else { | |
2003 | if (pp->drshrd == 0) | |
2004 | dp = " "; | |
2005 | else if ((int)pp->drshrd > 0) | |
2006 | dp = "+"; | |
2007 | else | |
2008 | dp = "-"; | |
2009 | ||
2010 | if (pp->pid || do_proc0_vm) | |
2011 | sprintf(&tbuf[clen], " %5.5s%s", mem_to_string((unsigned long long)pp->shared), dp); | |
2012 | else | |
2013 | sprintf(&tbuf[clen], " - "); | |
2014 | } | |
2015 | clen = clen + strlen(&tbuf[clen]); | |
2016 | ||
2017 | if (wide_output) { | |
2018 | sprintf(&tbuf[clen], " %5.5s", mem_to_string((unsigned long long)pp->resident_size)); /* res size */ | |
2019 | clen = clen + strlen(&tbuf[clen]); | |
2020 | ||
2021 | if (pp->drsize) | |
2022 | sprintf(&tbuf[clen], "(%5.5s)", offset_to_string(pp->drsize)); | |
2023 | else | |
2024 | sprintf(&tbuf[clen], " "); | |
2025 | } else { | |
2026 | if (pp->drsize == 0) | |
2027 | dp = " "; | |
2028 | else if ((int)pp->drsize > 0) | |
2029 | dp = "+"; | |
2030 | else | |
2031 | dp = "-"; | |
2032 | ||
2033 | sprintf(&tbuf[clen], " %5.5s%s", mem_to_string((unsigned long long)pp->resident_size), dp); /* res size */ | |
2034 | } | |
2035 | clen = clen + strlen(&tbuf[clen]); | |
2036 | ||
2037 | if (wide_output) { | |
2038 | sprintf(&tbuf[clen], " %5.5s", mem_to_string((unsigned long long)pp->virtual_size)); /* size */ | |
2039 | clen = clen + strlen(&tbuf[clen]); | |
2040 | ||
2041 | if (pp->rvsize) | |
2042 | sprintf(&tbuf[clen], "(%5.5s)", offset_to_string(pp->rvsize)); | |
2043 | else | |
2044 | sprintf(&tbuf[clen], " "); | |
2045 | } else { | |
2046 | if (pp->dvsize == 0) | |
2047 | dp = " "; | |
2048 | else if ((int)pp->dvsize > 0) | |
2049 | dp = "+"; | |
2050 | else | |
2051 | dp = "-"; | |
2052 | ||
2053 | sprintf(&tbuf[clen], " %5.5s%s", mem_to_string((unsigned long long)pp->virtual_size), dp); /* size */ | |
2054 | } | |
2055 | clen = clen + strlen(&tbuf[clen]); | |
2056 | ||
2057 | } /* else not events only */ | |
2058 | ||
2059 | sprintf(&tbuf[clen], "\n"); | |
2060 | ||
2061 | if (tbuf[COLS-1] != '\n') { | |
2062 | tbuf[COLS] = '\n'; | |
2063 | tbuf[COLS+1] = 0; | |
2064 | } | |
2065 | if (!oneshot) | |
2066 | printw(tbuf); | |
2067 | else | |
2068 | printf(tbuf); | |
2069 | } | |
2070 | ||
2071 | for (n = 0, prefp = pref; n < total_procs && i < topn; prefp++, n++) | |
2072 | { | |
2073 | pp = *prefp; | |
2074 | ||
2075 | if (pp->has_idle_thread == TRUE) { | |
2076 | sprintf(tbuf, "%5d", pp->pid); | |
2077 | clen = strlen(tbuf); | |
2078 | sprintf(&tbuf[clen], " %-10.10s ", "idle_thread"); | |
2079 | clen = clen + strlen(&tbuf[clen]); | |
2080 | ||
2081 | print_usage(&tbuf[clen], pp->cpu_idle); | |
2082 | clen = clen + strlen(&tbuf[clen]); | |
2083 | sprintf(&tbuf[clen], " "); | |
2084 | clen++; | |
2085 | print_time(&tbuf[clen], pp->idle_time); | |
2086 | clen = clen + strlen(&tbuf[clen]); | |
2087 | sprintf(&tbuf[clen], "\n"); | |
2088 | ||
2089 | if (tbuf[COLS-1] != '\n') { | |
2090 | tbuf[COLS] = '\n'; | |
2091 | tbuf[COLS+1] = 0; | |
2092 | } | |
2093 | if (!oneshot) | |
2094 | printw(tbuf); | |
2095 | else | |
2096 | printf(tbuf); | |
2097 | i++; | |
2098 | } | |
2099 | } | |
2100 | } | |
2101 | if (oneshot) { | |
2102 | printf("\n"); | |
2103 | ||
2104 | if (--logcnt <= 0) | |
2105 | leave(); | |
2106 | } else | |
2107 | refresh(); | |
2108 | } | |
2109 | ||
2110 | ||
2111 | void | |
2112 | update_eventsdata() | |
2113 | { | |
2114 | /* unimplemented */ | |
2115 | } | |
2116 | ||
2117 | ||
2118 | static struct nlist nl_net[] = { | |
2119 | #define N_IFNET 0 | |
2120 | { "_ifnet" }, | |
2121 | { "" }, | |
2122 | }; | |
2123 | ||
2124 | ||
2125 | ||
2126 | /* | |
2127 | * Read kernel memory, return 0 on success. | |
2128 | */ | |
2129 | int | |
2130 | kread(addr, buf, size) | |
2131 | u_long addr; | |
2132 | char *buf; | |
2133 | int size; | |
2134 | { | |
2135 | static kvm_t *kvmd = 0; | |
2136 | ||
2137 | if (kvmd == 0) { | |
2138 | /* | |
2139 | * XXX. | |
2140 | */ | |
2141 | kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, buf); | |
2142 | if (kvmd != NULL) { | |
2143 | if (kvm_nlist(kvmd, nl_net) < 0) | |
2144 | errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); | |
2145 | ||
2146 | if (nl_net[0].n_type == 0) | |
2147 | errx(1, "no namelist"); | |
2148 | } else { | |
2149 | return(-1); | |
2150 | } | |
2151 | } | |
2152 | if (!buf) | |
2153 | return (0); | |
2154 | if (kvm_read(kvmd, addr, buf, size) != size) { | |
2155 | warnx("%s", kvm_geterr(kvmd)); | |
2156 | return (-1); | |
2157 | } | |
2158 | return (0); | |
2159 | } | |
2160 | ||
2161 | ||
2162 | getNETWORKcounters() | |
2163 | { | |
2164 | struct ifnet ifnet; | |
2165 | struct ifnethead ifnethead; | |
2166 | u_long off; | |
2167 | ||
2168 | if (nl_net[N_IFNET].n_value == 0) | |
2169 | return; | |
2170 | if (kread(nl_net[N_IFNET].n_value, (char *)&ifnethead, sizeof ifnethead)) | |
2171 | return; | |
2172 | ||
1c51fdde A |
2173 | i_net.io = 0; |
2174 | o_net.io = 0; | |
2175 | ||
2176 | i_net.kbytes = 0; | |
2177 | o_net.kbytes = 0; | |
2178 | ||
1815bff5 | 2179 | for (off = (u_long)ifnethead.tqh_first; off; ) { |
1c51fdde | 2180 | char tname[16]; |
1815bff5 A |
2181 | |
2182 | if (kread(off, (char *)&ifnet, sizeof ifnet)) | |
2183 | break; | |
2184 | if (kread((u_long)ifnet.if_name, tname, 16)) | |
2185 | break; | |
1815bff5 | 2186 | |
1c51fdde A |
2187 | if (strncmp(tname, "lo", 2)) { |
2188 | i_net.io += ifnet.if_ipackets; | |
2189 | o_net.io += ifnet.if_opackets; | |
1815bff5 | 2190 | |
1c51fdde A |
2191 | i_net.kbytes += ifnet.if_ibytes/1024; |
2192 | o_net.kbytes += ifnet.if_obytes/1024; | |
1815bff5 A |
2193 | } |
2194 | off = (u_long) ifnet.if_link.tqe_next; | |
2195 | } | |
2196 | return; | |
2197 | } | |
2198 | ||
2199 | ||
2200 | getDISKcounters() | |
2201 | { | |
2202 | io_registry_entry_t drive = 0; /* needs release */ | |
2203 | UInt64 totalReadBytes = 0; | |
2204 | UInt64 totalReadCount = 0; | |
2205 | UInt64 totalWriteBytes = 0; | |
2206 | UInt64 totalWriteCount = 0; | |
2207 | ||
2208 | kern_return_t status = 0; | |
2209 | ||
2210 | while ( (drive = IOIteratorNext(drivelist)) ) | |
2211 | { | |
2212 | CFNumberRef number = 0; /* don't release */ | |
2213 | CFDictionaryRef properties = 0; /* needs release */ | |
2214 | CFDictionaryRef statistics = 0; /* don't release */ | |
2215 | UInt64 value = 0; | |
2216 | ||
2217 | /* Obtain the properties for this drive object */ | |
2218 | ||
2219 | status = IORegistryEntryCreateCFProperties (drive, | |
2220 | (CFMutableDictionaryRef *) &properties, | |
2221 | kCFAllocatorDefault, | |
2222 | kNilOptions); | |
b51d5b5f | 2223 | if (properties) { |
1815bff5 | 2224 | |
b51d5b5f A |
2225 | /* Obtain the statistics from the drive properties */ |
2226 | statistics = (CFDictionaryRef) CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)); | |
1815bff5 | 2227 | |
b51d5b5f | 2228 | if (statistics) { |
1815bff5 A |
2229 | /* Obtain the number of bytes read from the drive statistics */ |
2230 | number = (CFNumberRef) CFDictionaryGetValue (statistics, | |
2231 | CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)); | |
2232 | if (number) { | |
2233 | status = CFNumberGetValue(number, kCFNumberSInt64Type, &value); | |
2234 | totalReadBytes += value; | |
2235 | } | |
2236 | /* Obtain the number of reads from the drive statistics */ | |
2237 | number = (CFNumberRef) CFDictionaryGetValue (statistics, | |
2238 | CFSTR(kIOBlockStorageDriverStatisticsReadsKey)); | |
2239 | if (number) { | |
2240 | status = CFNumberGetValue(number, kCFNumberSInt64Type, &value); | |
2241 | totalReadCount += value; | |
2242 | } | |
2243 | ||
2244 | /* Obtain the number of writes from the drive statistics */ | |
2245 | number = (CFNumberRef) CFDictionaryGetValue (statistics, | |
2246 | CFSTR(kIOBlockStorageDriverStatisticsWritesKey)); | |
2247 | if (number) { | |
2248 | status = CFNumberGetValue(number, kCFNumberSInt64Type, &value); | |
2249 | totalWriteCount += value; | |
2250 | } | |
2251 | /* Obtain the number of bytes written from the drive statistics */ | |
2252 | number = (CFNumberRef) CFDictionaryGetValue (statistics, | |
2253 | CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)); | |
2254 | if (number) { | |
2255 | status = CFNumberGetValue(number, kCFNumberSInt64Type, &value); | |
2256 | totalWriteBytes += value; | |
2257 | } | |
b51d5b5f A |
2258 | } |
2259 | /* Release resources */ | |
1815bff5 | 2260 | |
b51d5b5f A |
2261 | CFRelease(properties); properties = 0; |
2262 | } | |
1815bff5 A |
2263 | IOObjectRelease(drive); drive = 0; |
2264 | } | |
2265 | IOIteratorReset(drivelist); | |
2266 | ||
2267 | i_dsk.io = (int)totalReadCount; | |
2268 | o_dsk.io = (int)totalWriteCount; | |
2269 | i_dsk.kbytes = (int)(totalReadBytes / 1024); | |
2270 | o_dsk.kbytes = (int)(totalWriteBytes / 1024); | |
2271 | } |