2 * Top users display for Berkeley Unix
5 * This program may be freely redistributed to other Unix sites, but this
6 * entire comment MUST remain intact.
8 * Copyright (c) 1984, William LeFebvre, Rice University
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.
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.
18 * Fixes and enhancements since version 1.5:
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
26 * added real and virtual memory status line
28 * added second "key" to the qsort comparisn function "proc_compar"
29 * which sorts by on cpu ticks if percentage is equal
31 **********************************************************************
33 * 22-Apr-99 Avadis Tevanian (avie) at Apple
34 * Another rewrite for Mach 3.0
36 * 21-Apr-90 Avadis Tevanian (avie) at NeXT
37 * Completely rewritten again for processor sets.
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.
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 */
49 #include <mach/mach.h>
58 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <sys/sysctl.h>
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>
73 #include <device/device_types.h>
74 #include <CoreFoundation/CoreFoundation.h>
75 #include <IOKit/IOKitLib.h>
76 #include <IOKit/storage/IOBlockStorageDriver.h>
79 #include <sys/socket.h>
81 #include <net/if_var.h>
85 #include <bsd/curses.h>
87 /* Number of lines of header information on the standard screen */
88 #define HEADER_LINES 8
90 #define sec_to_minutes(t) ((t) / 60)
91 #define sec_to_seconds(t) ((t) % 60)
92 #define usec_to_100ths(t) ((t) / 10000)
94 #ifndef TH_USAGE_SCALE
95 #define TH_USAGE_SCALE 1000
97 #define usage_to_percent(u) ((u*100)/TH_USAGE_SCALE)
98 #define usage_to_tenths(u) (((u*1000)/TH_USAGE_SCALE) % 10)
101 #define time_value_sub(tvp, uvp, vvp) \
103 (vvp)->seconds = (tvp)->seconds - (uvp)->seconds; \
104 (vvp)->microseconds = (tvp)->microseconds - (uvp)->microseconds; \
105 if ((vvp)->microseconds < 0) { \
107 (vvp)->microseconds += 1000000; \
114 int wclear(WINDOW
*win
);
115 int wmove(WINDOW
*win
, int y
, int x
);
116 int wrefresh(WINDOW
*win
);
118 int werase(WINDOW
*win
);
121 unsigned long long total_fw_private
;
123 struct termios tmode
, omode
;
126 host_cpu_load_info_data_t lastcounters
, curcounters
, startcounters
;
127 double userticks
, systicks
, idleticks
, totalticks
;
129 struct timeval cur_tod
;
130 struct timeval start_tod
;
131 struct timeval last_tod
;
132 struct timeval elapsed_tod
;
133 int elapsed_milliseconds
;
135 int Header_lines
= HEADER_LINES
;
144 int events_accumulate
;
157 struct io_stats i_net
, o_net
;
158 struct io_stats i_dsk
, o_dsk
;
159 struct io_stats i_vm
, o_vm
;
162 io_iterator_t drivelist
= 0; /* needs release */
163 mach_port_t masterPort
= 0;
177 boolean_t all_swapped
;
178 boolean_t has_idle_thread
;
179 time_value_t total_time
;
180 time_value_t idle_time
;
181 time_value_t beg_total_time
;
182 time_value_t beg_idle_time
;
184 vm_size_t virtual_size
;
185 vm_size_t resident_size
;
186 vm_size_t orig_virtual_size
;
187 vm_offset_t drsize
, dvsize
;
188 vm_offset_t drprvt
, drshrd
;
191 unsigned int private;
192 unsigned int vprivate
;
203 thread_basic_info_t threads
; /* array */
204 task_events_info_data_t tei
;
205 task_events_info_data_t deltatei
;
206 task_events_info_data_t accumtei
;
209 typedef struct proc_info
*proc_info_t
;
211 mach_port_t host_priv_port
, host_port
;
217 int resident_page_count
;
221 struct object_info
*next
;
224 #define OBJECT_TABLE_SIZE 537
225 #define OT_HASH(object) (((unsigned)object)%OBJECT_TABLE_SIZE)
227 struct object_info
*shared_hash_table
[OBJECT_TABLE_SIZE
];
229 struct object_info
*of_free_list
= 0;
231 #define FW_CODE_BEG_ADDR 0x70000000
232 #define FW_DATA_BEG_ADDR 0x80000000
233 #define FW_DATA_END_ADDR 0x90000000
236 * Translate thread state to a number in an ordered scale.
237 * When collapsing all the threads' states to one for the
238 * entire task, the lower-numbered state dominates.
243 mach_state_order(s
, sleep_time
)
248 case TH_STATE_RUNNING
: return(1);
249 case TH_STATE_UNINTERRUPTIBLE
:
251 case TH_STATE_WAITING
: return((sleep_time
> 20) ? 4 : 3);
252 case TH_STATE_STOPPED
: return(5);
253 case TH_STATE_HALTED
: return(6);
258 char mach_state_table
[] = "ZRUSITH?";
260 char * state_name
[] = {
270 int state_breakdown
[STATE_MAX
+1];
273 char *state_to_string(pi
)
276 static char s
[5]; /* STATIC! */
278 s
[0] = mach_state_table
[pi
->state
];
279 s
[1] = (pi
->all_swapped
) ? 'W' : ' ';
280 s
[2] = (pi
->base_pri
> 50) ? 'N' :
281 (pi
->base_pri
< 40) ? '<' : ' ';
287 void print_time(char *p
, time_value_t t
)
289 long seconds
, useconds
, minutes
, hours
;
292 useconds
= t
.microseconds
;
293 minutes
= seconds
/ 60;
294 hours
= minutes
/ 60;
296 if (minutes
< 100) { // up to 100 minutes
297 sprintf(p
, "%2ld:%02ld.%02ld", minutes
, seconds
% 60,
298 usec_to_100ths(useconds
));
300 else if (hours
< 100) { // up to 100 hours
301 sprintf(p
, "%2ld:%02ld:%02ld", hours
, minutes
% 60,
305 sprintf(p
, "%4ld hrs", hours
);
311 print_usage(char *p
, int cpu_usage
)
314 int right_of_decimal
;
316 if (elapsed_milliseconds
) {
317 left_of_decimal
= (cpu_usage
* 100) / elapsed_milliseconds
;
319 right_of_decimal
= (((cpu_usage
* 100) - (left_of_decimal
* elapsed_milliseconds
)) * 10) /
320 elapsed_milliseconds
;
323 right_of_decimal
= 0;
325 sprintf(p
, "%3d.%01d%%%%", left_of_decimal
, right_of_decimal
); /* %cpu */
334 static char tmp
[10]; /* STATIC! */
336 if ((n
> 0) && (n
< 10))
337 sprintf(tmp
, "%4.2f", n
);
338 else if ((n
> 0) && (n
< 100))
339 sprintf(tmp
, "%4.1f", n
);
340 else if ((n
< 0) && (n
> -10))
341 sprintf(tmp
, "%4.1f", n
);
343 sprintf(tmp
, "%4.0f", n
);
349 unsigned long long n
;
351 static char s
[10]; /* STATIC! */
353 /* convert to kilobytes */
357 sprintf(s
, "%sG", digits(((float)n
)/(1024.0*1024.0)));
359 sprintf(s
, "%sM", digits((float)n
/(1024.0)));
361 sprintf(s
, "%dK", (int)n
);
370 static char s
[10]; /* STATIC! */
373 /* convert to kilobytes */
378 sprintf(s
, "%sG", digits(((float)n
)/(1024.0*1024.0)));
380 sprintf(s
, "%sM", digits((float)n
/(1024.0)));
382 sprintf(s
, "%dK", n
);
387 mach_port_t
get_host_priv()
389 return(mach_host_self());
392 mach_port_t
get_host_port()
394 return(mach_host_self());
398 shared_hash_enter(int obj_id
, int share_type
, int resident_page_count
, int ref_count
, int size
, int pid
)
400 register struct object_info
**bucket
;
401 register struct object_info
*of
;
403 of
= shared_hash_table
[OT_HASH(obj_id
/OBJECT_TABLE_SIZE
)];
405 if (of
->id
== obj_id
) {
407 of
->task_ref_count
++;
413 bucket
= &shared_hash_table
[OT_HASH(obj_id
/OBJECT_TABLE_SIZE
)];
415 if (of
= of_free_list
)
416 of_free_list
= of
->next
;
418 of
= (struct object_info
*) malloc(sizeof(*of
));
420 of
->resident_page_count
= resident_page_count
;
422 of
->share_type
= share_type
;
423 of
->ref_count
= ref_count
;
424 of
->task_ref_count
= 1;
433 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
)
435 vm_address_t address
= 0;
436 kern_return_t err
= 0;
440 *obj_count
= *aliased
= *shared
= *private = *vprivate
= 0;
443 mach_port_t object_name
;
444 vm_region_top_info_data_t info
;
445 mach_msg_type_number_t count
;
448 count
= VM_REGION_TOP_INFO_COUNT
;
450 if (err
= vm_region(task
, &address
, &size
, VM_REGION_TOP_INFO
, (vm_region_info_t
)&info
,
451 &count
, &object_name
))
454 if (address
>= FW_CODE_BEG_ADDR
&& address
< FW_DATA_END_ADDR
) {
456 *fw_private
+= info
.private_pages_resident
* vm_page_size
;
458 if ( !split
&& info
.share_mode
== SM_EMPTY
) {
459 vm_region_basic_info_data_64_t b_info
;
461 count
= VM_REGION_BASIC_INFO_COUNT_64
;
462 if (err
= vm_region_64(task
, &address
, &size
, VM_REGION_BASIC_INFO
, (vm_region_info_t
)&b_info
,
463 &count
, &object_name
))
469 if (info
.share_mode
!= SM_PRIVATE
) {
478 switch (info
.share_mode
) {
481 *private += info
.private_pages_resident
* vm_page_size
;
486 if (info
.ref_count
== 1)
487 info
.share_mode
= SM_PRIVATE
;
488 if (pid
&& info
.share_mode
== SM_COW
)
489 shared_hash_enter(info
.obj_id
, SM_COW
, info
.shared_pages_resident
,
490 info
.ref_count
, size
, pid
);
491 if (info
.share_mode
== SM_PRIVATE
)
492 *private += info
.shared_pages_resident
* vm_page_size
;
493 *private += info
.private_pages_resident
* vm_page_size
;
495 if (info
.share_mode
== SM_PRIVATE
)
498 *vprivate
+= info
.private_pages_resident
* vm_page_size
;
503 shared_hash_enter(info
.obj_id
, SM_SHARED
, info
.shared_pages_resident
,
504 info
.ref_count
, size
, pid
);
508 for (i
= 0; i
< OBJECT_TABLE_SIZE
; i
++) {
509 register struct object_info
*sl
;
511 sl
= shared_hash_table
[i
];
514 if (sl
->pid
== pid
) {
515 if (sl
->share_type
== SM_SHARED
) {
516 if (sl
->ref_count
== sl
->task_ref_count
) {
517 sl
->share_type
= SM_PRIVATE_ALIASED
;
519 *aliased
+= sl
->resident_page_count
* vm_page_size
;
520 *vprivate
+= sl
->size
;
523 if (sl
->share_type
!= SM_PRIVATE_ALIASED
)
524 *shared
+= sl
->resident_page_count
* vm_page_size
;
526 sl
->task_ref_count
= 0;
532 *vsize
-= (FW_DATA_END_ADDR
- FW_CODE_BEG_ADDR
);
537 pmem_fw_resident(unsigned int *num_fw
, unsigned long long *vsize
, unsigned int *code_size
, unsigned int *data_size
, unsigned int *linkedit_size
)
538 { vm_address_t address
= FW_CODE_BEG_ADDR
;
539 kern_return_t err
= 0;
548 while (address
< FW_DATA_END_ADDR
) {
549 vm_region_submap_info_data_64_t s_info
;
550 mach_msg_type_number_t count
;
555 count
= VM_REGION_SUBMAP_INFO_COUNT_64
;
557 if (err
= vm_region_recurse_64(mach_task_self(), &address
, &size
, &nesting_depth
, (vm_region_info_t
)&s_info
, &count
))
560 if (address
>= FW_DATA_END_ADDR
)
562 if (address
< FW_DATA_BEG_ADDR
) {
564 if (s_info
.share_mode
== SM_SHARED
|| s_info
.share_mode
== SM_COW
) {
565 if (s_info
.max_protection
& VM_PROT_EXECUTE
) {
566 *code_size
+= (s_info
.pages_resident
* vm_page_size
);
573 *linkedit_size
+= (s_info
.pages_resident
* vm_page_size
);
580 if (s_info
.share_mode
== SM_SHARED
|| s_info
.share_mode
== SM_COW
|| s_info
.share_mode
== SM_TRUESHARED
)
581 *data_size
+= (s_info
.pages_resident
* vm_page_size
);
593 pmem_shared_resident(unsigned long long *total
, int *number
)
595 register int total_size
;
596 register int total_num
;
597 register struct object_info
*sl
, *next
;
599 total_size
= total_num
= 0;
601 for (i
= 0; i
< OBJECT_TABLE_SIZE
; i
++) {
602 sl
= shared_hash_table
[i
];
603 shared_hash_table
[i
] = 0;
606 if (sl
->share_type
!= SM_PRIVATE_ALIASED
) {
607 total_size
+= sl
->resident_page_count
;
612 sl
->next
= of_free_list
;
619 *total
= total_size
* vm_page_size
;
624 get_real_command_name(int pid
, char *cbuf
, int csize
)
627 * Get command and arguments.
629 volatile int *ip
, *savedip
;
635 int arguments_size
= 4096;
636 volatile unsigned int *valuep
;
638 int blahlen
=0, skiplen
=0;
641 * A sysctl() is made to find out the full path that the command
645 mib
[1] = KERN_PROCARGS
;
649 arguments
= (char *) malloc(arguments_size
);
650 if (sysctl(mib
, 3, arguments
, (size_t *)&arguments_size
, NULL
, 0) < 0) {
654 end_argc
= &arguments
[arguments_size
];
656 ip
= (int *)end_argc
;
657 ip
-= 2; /* last arg word and .long 0 */
659 if (ip
== (int *)arguments
) {
666 cp
= (char *)savedip
;
668 if (ip
== (int *)arguments
) {
674 valuep
= (unsigned int *)ip
;
677 if ((value
& 0xbfff0000) == 0xbfff0000) {
680 blahlen
= strlen((char *)ip
);
681 skiplen
= (blahlen
+3 ) /4 ;
688 for (cp
= (char *)savedip
; cp
< (end_argc
-1); cp
++) {
696 if (cp
> (char *)savedip
)
699 while (cp
> (char *)savedip
) {
706 if (cp
[0] == '-' || cp
[0] == '?' || cp
[0] <= ' ') {
708 * Not enough information
713 (void) strncpy(cbuf
, (char *)cp
, csize
);
721 /* All of this should come out of the process manager... */
723 void get_proc_info(kpb
, pi
)
724 struct kinfo_proc
*kpb
;
725 struct proc_info
*pi
;
728 mach_port_array_t names
, types
;
729 unsigned int ncnt
, tcnt
;
731 pi
->uid
= kpb
->kp_eproc
.e_ucred
.cr_uid
;
732 pi
->pid
= kpb
->kp_proc
.p_pid
;
733 pi
->ppid
= kpb
->kp_eproc
.e_ppid
;
734 pi
->pgrp
= kpb
->kp_eproc
.e_pgid
;
735 pi
->status
= kpb
->kp_proc
.p_stat
;
736 pi
->flag
= kpb
->kp_proc
.p_flag
;
739 * Find the other stuff
741 if (task_for_pid(mach_task_self(), pi
->pid
, &task
) != KERN_SUCCESS
) {
746 task_basic_info_data_t ti
;
748 unsigned int aliased
;
749 thread_array_t thread_table
;
750 unsigned int table_size
;
751 thread_basic_info_t thi
;
752 thread_basic_info_data_t thi_data
;
755 count
= TASK_BASIC_INFO_COUNT
;
756 if (task_info(task
, TASK_BASIC_INFO
, (task_info_t
)&ti
,
757 &count
) != KERN_SUCCESS
) {
760 pi
->virtual_size
= ti
.virtual_size
;
762 pi
->resident_size
= ti
.resident_size
;
764 if ((pi
->pid
|| do_proc0_vm
) && (!events_only
)) {
765 pmem_doit(task
, pi
->pid
, &pi
->shared
, &pi
->private, &aliased
, &pi
->obj_count
, &pi
->vprivate
, &pi
->virtual_size
, &total_fw_private
);
766 pi
->private += aliased
;
773 pi
->orig_virtual_size
= pi
->virtual_size
;
774 pi
->total_time
= ti
.user_time
;
775 time_value_add(&pi
->total_time
, &ti
.system_time
);
777 pi
->idle_time
.seconds
= 0;
778 pi
->idle_time
.microseconds
= 0;
780 if (task_threads(task
, &thread_table
, &table_size
) != KERN_SUCCESS
)
783 pi
->state
= STATE_MAX
;
786 pi
->all_swapped
= TRUE
;
787 pi
->has_idle_thread
= FALSE
;
791 pi
->num_threads
= table_size
;
792 total_threads
+= table_size
;
794 for (i
= 0; i
< table_size
; i
++) {
795 count
= THREAD_BASIC_INFO_COUNT
;
796 if (thread_info(thread_table
[i
], THREAD_BASIC_INFO
,
797 (thread_info_t
)thi
, &count
) == KERN_SUCCESS
) {
799 if (thi
->flags
& TH_FLAGS_IDLE
) {
800 pi
->has_idle_thread
= TRUE
;
802 time_value_add(&pi
->idle_time
,
804 time_value_add(&pi
->idle_time
,
807 time_value_add(&pi
->total_time
,
809 time_value_add(&pi
->total_time
,
812 t_state
= mach_state_order(thi
->run_state
,
814 if (t_state
< pi
->state
)
816 // update priority info based on schedule policy
817 // if (thi->cur_priority < pi->pri)
818 // pi->pri = thi->cur_priority;
819 // if (thi->base_priority < pi->base_pri)
820 // pi->base_pri = thi->base_priority;
821 if ((thi
->flags
& TH_FLAGS_SWAPPED
) == 0)
822 pi
->all_swapped
= FALSE
;
825 if (task
!= mach_task_self()) {
826 mach_port_deallocate(mach_task_self(),
830 (void) vm_deallocate(mach_task_self(), (vm_offset_t
)thread_table
,
831 table_size
* sizeof(*thread_table
));
834 if (mach_port_names(task
, &names
, &ncnt
,
835 &types
, &tcnt
) == KERN_SUCCESS
) {
836 pi
->num_ports
= ncnt
;
837 pi
->orig_num_ports
= ncnt
;
838 (void) vm_deallocate(mach_task_self(),
840 ncnt
* sizeof(*names
));
841 (void) vm_deallocate(mach_task_self(),
843 tcnt
* sizeof(*types
));
851 task_events_info_data_t tei
;
853 count
= TASK_EVENTS_INFO_COUNT
;
854 if (task_info(task
, TASK_EVENTS_INFO
, (task_info_t
)&tei
,
855 &count
) != KERN_SUCCESS
) {
864 if (task
!= mach_task_self()) {
865 mach_port_deallocate(mach_task_self(), task
);
868 if ( strncmp (kpb
->kp_proc
.p_comm
, "LaunchCFMA", 10) ||
869 !get_real_command_name(pi
->pid
, pi
->command
, sizeof(kpb
->kp_proc
.p_comm
)-1)) {
870 (void) strncpy(pi
->command
, kpb
->kp_proc
.p_comm
,
871 sizeof(kpb
->kp_proc
.p_comm
)-1);
872 pi
->command
[sizeof(kpb
->kp_proc
.p_comm
)-1] = '\0';
881 void leave() /* exit under normal conditions -- INT handler */
888 tcsetattr(0, TCSANOW
, &omode
);
893 void quit(status
) /* exit under duress */
898 tcsetattr(0, TCSANOW
, &omode
);
910 * comparison function for "qsort"
911 * Do first order sort based on cpu percentage computed by kernel and
912 * second order sort based on total time for the process.
915 int proc_compar(p1
, p2
)
916 register struct proc_info
**p1
;
917 register struct proc_info
**p2
;
920 if ((*p1
)->cpu_usage
< (*p2
)->cpu_usage
)
922 else if ((*p1
)->cpu_usage
> (*p2
)->cpu_usage
)
925 if ((*p1
)->total_time
.seconds
< (*p2
)->total_time
.seconds
)
932 if ((*p1
)->pid
< (*p2
)->pid
)
940 int nproc
, total_procs
, old_procs
;
941 struct kinfo_proc
*kbase
, *kpb
;
942 struct proc_info
*proc
, *pp
, *oldproc
;
943 struct proc_info
**pref
, **prefp
;
957 struct kinfo_proc ki
;
960 ret
= pid_for_task(task
, &pid
);
961 if (ret
!= KERN_SUCCESS
)
966 mib
[2] = KERN_PROC_PID
;
969 if (sysctl(mib
, 4, &ki
, &size
, NULL
, 0) < 0) {
970 perror("failure calling sysctl");
973 if (ki
.kp_proc
.p_stat
== 0) {
974 state_breakdown
[0]++;
977 if (total_procs
== nproc
) {
979 kbase
= (struct kinfo_proc
*) realloc(kbase
,
980 nproc
*sizeof(struct kinfo_proc
));
981 bzero(&kbase
[total_procs
], total_procs
*sizeof(struct kinfo_proc
));
982 proc
= (struct proc_info
*) realloc(proc
,
983 nproc
*sizeof(struct proc_info
));
984 bzero(&proc
[total_procs
], total_procs
*sizeof(struct proc_info
));
985 oldproc
= (struct proc_info
*) realloc(oldproc
,
986 nproc
*sizeof(struct proc_info
));
987 bzero(&oldproc
[total_procs
], total_procs
*sizeof(struct proc_info
));
988 pref
= (struct proc_info
**) realloc(pref
,
989 nproc
*sizeof(struct proc_info
*));
990 bzero(&pref
[total_procs
], total_procs
*sizeof(struct proc_info
*));
992 kbase
[total_procs
] = ki
;
996 void update_histdata()
998 struct proc_info
*pp
, *oldp
;
1000 time_value_t elapsed_time
;
1005 // XXX use linear search since list is usually small
1007 while (i
< total_procs
) {
1012 while (j
< old_procs
) {
1013 if (oldp
->pid
== pid
) {
1014 pp
->drprvt
= pp
->private - oldp
->private;
1015 pp
->drshrd
= pp
->shared
- oldp
->shared
;
1016 pp
->drsize
= pp
->resident_size
- oldp
->resident_size
;
1017 pp
->dvsize
= pp
->virtual_size
- oldp
->virtual_size
;
1019 pp
->rvsize
= pp
->virtual_size
- oldp
->orig_virtual_size
;
1020 pp
->orig_virtual_size
= oldp
->orig_virtual_size
;
1022 pp
->dnum_ports
= pp
->num_ports
- oldp
->orig_num_ports
;
1023 pp
->orig_num_ports
= oldp
->orig_num_ports
;
1025 if (pp
->has_idle_thread
== TRUE
) {
1026 if (events_accumulate
) {
1027 time_value_sub(&pp
->idle_time
, &oldp
->beg_idle_time
, &elapsed_time
);
1028 pp
->beg_idle_time
= oldp
->beg_idle_time
;
1029 pp
->idle_time
= elapsed_time
;
1031 time_value_sub(&pp
->idle_time
, &oldp
->idle_time
, &elapsed_time
);
1033 pp
->cpu_idle
= (elapsed_time
.seconds
* 1000) + (elapsed_time
.microseconds
/ 1000);
1035 if (events_accumulate
) {
1036 time_value_sub(&pp
->total_time
, &oldp
->beg_total_time
, &elapsed_time
);
1037 pp
->beg_total_time
= oldp
->beg_total_time
;
1038 pp
->total_time
= elapsed_time
;
1040 time_value_sub(&pp
->total_time
, &oldp
->total_time
, &elapsed_time
);
1042 pp
->cpu_usage
= (elapsed_time
.seconds
* 1000) + (elapsed_time
.microseconds
/ 1000);
1046 pp
->deltatei
.pageins
= pp
->tei
.pageins
- oldp
->tei
.pageins
;
1047 pp
->deltatei
.faults
= pp
->tei
.faults
- oldp
->tei
.faults
;
1048 pp
->deltatei
.cow_faults
= pp
->tei
.cow_faults
- oldp
->tei
.cow_faults
;
1049 pp
->deltatei
.messages_sent
= pp
->tei
.messages_sent
- oldp
->tei
.messages_sent
;
1050 pp
->deltatei
.messages_received
= pp
->tei
.messages_received
- oldp
->tei
.messages_received
;
1051 pp
->deltatei
.syscalls_unix
= pp
->tei
.syscalls_unix
- oldp
->tei
.syscalls_unix
;
1052 pp
->deltatei
.syscalls_mach
= pp
->tei
.syscalls_mach
- oldp
->tei
.syscalls_mach
;
1053 pp
->deltatei
.csw
= pp
->tei
.csw
- oldp
->tei
.csw
;
1055 if (events_accumulate
)
1057 pp
->deltatei
.pageins
= pp
->tei
.pageins
- oldp
->accumtei
.pageins
;
1058 pp
->deltatei
.faults
= pp
->tei
.faults
- oldp
->accumtei
.faults
;
1059 pp
->deltatei
.cow_faults
= pp
->tei
.cow_faults
- oldp
->accumtei
.cow_faults
;
1060 pp
->deltatei
.messages_sent
= pp
->tei
.messages_sent
- oldp
->accumtei
.messages_sent
;
1061 pp
->deltatei
.messages_received
= pp
->tei
.messages_received
- oldp
->accumtei
.messages_received
;
1062 pp
->deltatei
.syscalls_unix
= pp
->tei
.syscalls_unix
- oldp
->accumtei
.syscalls_unix
;
1063 pp
->deltatei
.syscalls_mach
= pp
->tei
.syscalls_mach
- oldp
->accumtei
.syscalls_mach
;
1064 pp
->deltatei
.csw
= pp
->tei
.csw
- oldp
->accumtei
.csw
;
1066 pp
->accumtei
= oldp
->accumtei
;
1073 if (j
>= old_procs
) {
1074 if (events_accumulate
) {
1075 pp
->accumtei
= pp
->tei
;
1076 pp
->beg_total_time
= pp
->total_time
;
1077 pp
->beg_idle_time
= pp
->idle_time
;
1079 pp
->idle_time
.seconds
= 0;
1080 pp
->idle_time
.microseconds
= 0;
1081 pp
->total_time
.seconds
= 0;
1082 pp
->total_time
.microseconds
= 0;
1084 bzero(&pp
->deltatei
, sizeof (task_events_info_data_t
));
1098 bcopy(proc
, oldproc
, total_procs
*sizeof(struct proc_info
));
1099 old_procs
= total_procs
;
1102 void read_proc_table()
1105 processor_set_t
*psets
;
1107 unsigned int pcount
, tcount
;
1115 host
= host_priv_port
;
1117 if (host
== MACH_PORT_NULL
) {
1118 printf("Insufficient privileges.\n");
1121 ret
= host_processor_sets(host
, &psets
, &pcount
);
1122 if (ret
!= KERN_SUCCESS
) {
1123 mach_error("host_processor_sets", ret
);
1126 for (i
= 0; i
< pcount
; i
++) {
1127 ret
= host_processor_set_priv(host
, psets
[i
], &p
);
1128 if (ret
!= KERN_SUCCESS
) {
1129 mach_error("host_processor_set_priv", ret
);
1133 ret
= processor_set_tasks(p
, &tasks
, &tcount
);
1134 if (ret
!= KERN_SUCCESS
) {
1135 mach_error("processor_set_tasks", ret
);
1138 for (j
= 0; j
< tcount
; j
++) {
1139 grab_task(tasks
[j
]);
1140 // don't delete our own task port
1141 if (tasks
[j
] != mach_task_self())
1142 mach_port_deallocate(mach_task_self(),
1145 vm_deallocate(mach_task_self(), (vm_address_t
)tasks
,
1146 tcount
* sizeof(task_t
));
1147 mach_port_deallocate(mach_task_self(), p
);
1148 mach_port_deallocate(mach_task_self(), psets
[i
]);
1150 vm_deallocate(mach_task_self(), (vm_address_t
)psets
,
1151 pcount
* sizeof(processor_set_t
));
1154 kern_return_t
getCPU(cpucounters
)
1155 host_cpu_load_info_t cpucounters
;
1157 mach_msg_type_number_t count
;
1160 count
= HOST_CPU_LOAD_INFO_COUNT
;
1161 kr
= host_statistics (host_priv_port
, HOST_CPU_LOAD_INFO
,
1162 (host_info_t
)cpucounters
, &count
);
1170 if (events_accumulate
) {
1171 userticks
= curcounters
.cpu_ticks
[CPU_STATE_USER
]-
1172 startcounters
.cpu_ticks
[CPU_STATE_USER
];
1174 systicks
= curcounters
.cpu_ticks
[CPU_STATE_SYSTEM
]-
1175 startcounters
.cpu_ticks
[CPU_STATE_SYSTEM
];
1177 idleticks
= curcounters
.cpu_ticks
[CPU_STATE_IDLE
]-
1178 startcounters
.cpu_ticks
[CPU_STATE_IDLE
];
1179 } else if (events_only
&& !events_delta
) {
1181 userticks
= curcounters
.cpu_ticks
[CPU_STATE_USER
];
1183 systicks
= curcounters
.cpu_ticks
[CPU_STATE_SYSTEM
];
1185 idleticks
= curcounters
.cpu_ticks
[CPU_STATE_IDLE
];
1187 userticks
= curcounters
.cpu_ticks
[CPU_STATE_USER
]-
1188 lastcounters
.cpu_ticks
[CPU_STATE_USER
];
1190 systicks
= curcounters
.cpu_ticks
[CPU_STATE_SYSTEM
]-
1191 lastcounters
.cpu_ticks
[CPU_STATE_SYSTEM
];
1193 idleticks
= curcounters
.cpu_ticks
[CPU_STATE_IDLE
]-
1194 lastcounters
.cpu_ticks
[CPU_STATE_IDLE
];
1196 lastcounters
= curcounters
;
1198 totalticks
= userticks
+ systicks
+ idleticks
;
1207 char *myname
= "top";
1209 int delay
= Default_DELAY
;
1210 kern_return_t error
;
1212 void screen_update();
1216 if ((myname
= rindex(argv
[0], '/')) == 0) {
1224 /* check for options */
1230 events_accumulate
= 0;
1232 while ((ch
= getopt(argc
, argv
, "uwks:edal:")) != EOF
) {
1235 delay
= atoi(optarg
);
1255 events_accumulate
= 1;
1258 logcnt
= atoi(optarg
);
1264 fprintf(stderr
, "Usage: %s [-u] [-w] [-k] [-sn] [-e | -d | -a] [-ln] [number]\n", myname
);
1265 fprintf(stderr
, " -u enables sort by usage\n");
1266 fprintf(stderr
, " -w enables wide output of additional info\n");
1267 fprintf(stderr
, " -k generate vm info for kernel(proc 0)... expensive\n");
1268 fprintf(stderr
, " -sn change sample rate to every n seconds\n");
1269 fprintf(stderr
, " -e switch to events info counter mode\n");
1270 fprintf(stderr
, " -d switch to events info counter delta mode\n");
1271 fprintf(stderr
, " -a switch to events info counter accumulate mode\n");
1272 fprintf(stderr
, " -ln log n samples\n");
1273 fprintf(stderr
, " number limit number of processes monitored\n");
1284 if ( wide_output
|| do_proc0_vm
)
1286 fprintf(stderr
, " The -w and -k flag have no effect in event mode.\n");
1292 host_priv_port
= get_host_priv();
1293 host_port
= get_host_port();
1295 /* get count of top processes to display (if any) */
1297 wanted_topn
= topn
= atoi(argv
[optind
]);
1301 /* allocate space for proc structure array and array of pointers */
1302 nproc
= 50; /* starting point */
1303 kbase
= (struct kinfo_proc
*) malloc(nproc
*sizeof(struct kinfo_proc
));
1304 bzero(kbase
, nproc
*sizeof(struct kinfo_proc
));
1305 proc
= (struct proc_info
*) malloc(nproc
*sizeof(struct proc_info
));
1306 bzero(proc
, nproc
*sizeof(struct proc_info
));
1307 oldproc
= (struct proc_info
*) malloc(nproc
*sizeof(struct proc_info
));
1308 bzero(oldproc
, nproc
*sizeof(struct proc_info
));
1309 pref
= (struct proc_info
**) malloc(nproc
*sizeof(struct proc_info
*));
1310 bzero(pref
, nproc
*sizeof(struct proc_info
*));
1312 (void) host_page_size(host_port
, &pagesize
);
1313 /* initializes curses and screen (last) */
1316 if (tcgetattr(0, &tmode
) < 0) {
1317 printf("can't get terminal attributes\n");
1322 tmode
.c_lflag
&= ~ICANON
;
1323 tmode
.c_cc
[VMIN
] = 0;
1324 tmode
.c_cc
[VTIME
] = (delay
* 10);
1326 if (tcsetattr(0, TCSANOW
, &tmode
) < 0) {
1327 printf("can't set terminal attributes\n");
1336 /* set up signal handlers */
1337 signal(SIGINT
, leave
);
1338 signal(SIGQUIT
, leave
);
1339 signal(SIGWINCH
, sigwinch
);
1341 /* can only display (LINES - Header_lines) processes */
1342 if (topn
> LINES
- Header_lines
) {
1344 printw("Warning: this terminal can only display %d processes...\n",
1345 LINES
- Header_lines
);
1347 printf("Warning: this terminal can only display %d processes...\n",
1348 LINES
- Header_lines
);
1353 topn
= LINES
- Header_lines
;
1357 if (topn
== 0) { // use default
1358 // leave one blank line at bottom
1360 topn
= LINES
- Header_lines
- 1;
1363 /* prime the pump for gathering networking stats */
1366 /**************************************************/
1367 /* get ports and services for drive stats */
1368 /* Obtain the I/O Kit communication handle */
1370 error
= IOMasterPort(bootstrap_port
, &masterPort
);
1372 /* Obtain the list of all drive objects */
1374 error
= IOServiceGetMatchingServices(masterPort
,
1375 IOServiceMatching("IOBlockStorageDriver"),
1377 getCPU(&lastcounters
);
1378 startcounters
= lastcounters
;
1380 gettimeofday(&cur_tod
, NULL
);
1381 start_tod
= cur_tod
;
1382 elapsed_milliseconds
= -1;
1397 n
= LINES
- Header_lines
;
1402 if (wanted_topn
== -1)
1404 else if (topn
< wanted_topn
) {
1405 if (wanted_topn
< n
)
1413 (void)screen_update();
1417 if ((n
= read(0, &bytesread
, 128)) > 0) {
1420 for (i
= 0; i
< n
; i
++)
1421 if (bytesread
[i
] == 'q')
1429 void screen_update()
1437 unsigned long long total_fw_vsize
;
1438 unsigned long long total_virtual_size
;
1439 unsigned long long total_private_size
;
1440 unsigned long long total_shared_size
;
1441 unsigned int total_memory_regions
= 0;
1442 unsigned int total_shared_objects
;
1443 unsigned int total_fw_code_size
;
1444 unsigned int total_fw_data_size
;
1445 unsigned int total_fw_linkedit_size
;
1446 unsigned int total_frameworks
;
1447 vm_statistics_data_t vm_stat
;
1448 struct host_load_info load_data
;
1450 kern_return_t error
;
1455 bzero((char *)state_breakdown
, sizeof(state_breakdown
));
1458 /* clear for new display */
1461 /* read all of the process information */
1464 /* get the load averages */
1465 host_count
= sizeof(load_data
)/sizeof(integer_t
);
1466 error
= host_statistics(host_priv_port
, HOST_LOAD_INFO
,
1467 (host_info_t
)&load_data
, &host_count
);
1468 if (error
!= KERN_SUCCESS
) {
1469 mach_error("host_statistics", error
);
1473 avenrun
[0] = load_data
.avenrun
[0];
1474 avenrun
[1] = load_data
.avenrun
[1];
1475 avenrun
[2] = load_data
.avenrun
[2];
1477 /* get total - systemwide main memory usage structure */
1478 host_count
= sizeof(vm_stat
)/sizeof(integer_t
);
1479 error
= host_statistics(host_priv_port
, HOST_VM_INFO
,
1480 (host_info_t
)&vm_stat
, &host_count
);
1481 if (error
!= KERN_SUCCESS
) {
1482 mach_error("host_info", error
);
1487 getNETWORKcounters();
1490 /* count up process states and get pointers to interesting procs */
1494 total_virtual_size
= 0;
1495 total_private_size
= 0;
1496 total_fw_private
= 0;
1499 for (kpb
= kbase
, pp
= proc
, i
= 0;
1503 /* place pointers to each valid proc structure in pref[] */
1504 get_proc_info(kpb
, pp
);
1506 if (kpb
->kp_proc
.p_stat
!= 0) {
1512 if ((unsigned int)pp
->state
> (unsigned int)STATE_MAX
)
1513 pp
->state
= STATE_MAX
;
1514 state_breakdown
[pp
->state
]++;
1515 total_virtual_size
+= pp
->virtual_size
;
1516 total_private_size
+= pp
->private;
1517 total_memory_regions
+= pp
->obj_count
;
1520 state_breakdown
[0]++;
1522 /* get the cpu counters */
1523 getCPU(&curcounters
);
1526 if (elapsed_milliseconds
!= -1) {
1528 gettimeofday(&cur_tod
, NULL
);
1530 if (events_accumulate
)
1531 timersub(&cur_tod
, &start_tod
, &elapsed_tod
);
1533 timersub(&cur_tod
, &last_tod
, &elapsed_tod
);
1535 elapsed_milliseconds
= (elapsed_tod
.tv_sec
* 1000) + (elapsed_tod
.tv_usec
/ 1000);
1537 elapsed_milliseconds
= 0;
1540 pmem_fw_resident(&total_frameworks
, &total_fw_vsize
, &total_fw_code_size
, &total_fw_data_size
, &total_fw_linkedit_size
);
1542 pmem_shared_resident(&total_shared_size
, &total_shared_objects
);
1547 /* display process state breakdown */
1548 sprintf(tbuf
, "Processes: %d total", total_procs
);
1549 clen
= strlen(tbuf
);
1552 for (i
= 0; i
<= STATE_MAX
; i
++) {
1553 if (state_breakdown
[i
] != 0) {
1554 sprintf(&tbuf
[clen
], ", %d %s%s",
1557 (i
== 0 && state_breakdown
[0] > 1) ? "s" : ""
1560 clen
= clen
+ strlen(&tbuf
[clen
]);
1563 sprintf(&tbuf
[clen
], "... %d threads", total_threads
);
1565 clen
= clen
+ strlen(&tbuf
[clen
]);
1567 * Display the current time.
1568 * "ctime" always returns a string that looks like this:
1570 * Sun Sep 16 01:03:52 1973
1571 * 012345678901234567890123
1574 * We want indices 11 thru 18 (length 8).
1576 curr_time
= time((long *)0);
1578 if (start_time
== 0)
1579 start_time
= curr_time
;
1581 memset(&tbuf
[clen
], ' ', 111 - clen
);
1585 else if (events_accumulate
)
1587 else if (events_only
&& !events_delta
)
1592 sprintf(&tbuf
[clen
], "%-8.8s", &(ctime(&curr_time
)[11]));
1593 clen
= clen
+ strlen(&tbuf
[clen
]);
1595 if (events_accumulate
) {
1599 elapsed_secs
= curr_time
- start_time
;
1600 minutes
= elapsed_secs
/ 60;
1601 hours
= minutes
/ 60;
1603 sprintf(&tbuf
[clen
], " %3ld:%02ld:%02ld\n", hours
, minutes
% 60, elapsed_secs
% 60);
1605 sprintf(&tbuf
[clen
], "\n");
1608 if (tbuf
[COLS
-2] != '\n') {
1609 tbuf
[COLS
-1] = '\n';
1617 /* display the load averages */
1618 sprintf(tbuf
, "Load Avg");
1619 clen
= strlen(tbuf
);
1621 for (i
= 0; i
< 3; i
++) {
1622 sprintf(&tbuf
[clen
], "%s %4.2f", i
== 0 ? ": " : ",",
1623 (double)avenrun
[i
] / LOAD_SCALE
);
1624 clen
= clen
+ strlen(&tbuf
[clen
]);
1627 sprintf(&tbuf
[clen
], " CPU usage: %.1f%%%% user, %.1f%%%% sys, %.1f%%%% idle\n",
1628 (100*userticks
)/totalticks
, (100*systicks
)/totalticks
, (100*idleticks
)/totalticks
);
1629 clen
= clen
+ strlen(&tbuf
[clen
]);
1631 if (tbuf
[COLS
-2] != '\n') {
1632 tbuf
[COLS
-1] = '\n';
1641 sprintf(tbuf
, "SharedLibs: num = %4d, ", total_frameworks
);
1642 clen
= strlen(tbuf
);
1643 sprintf(&tbuf
[clen
], "resident = %s code, ", mem_to_string((unsigned long long)total_fw_code_size
));
1644 clen
= clen
+ strlen(&tbuf
[clen
]);
1645 sprintf(&tbuf
[clen
], "%s data, ", mem_to_string((unsigned long long)total_fw_data_size
));
1646 clen
= clen
+ strlen(&tbuf
[clen
]);
1647 sprintf(&tbuf
[clen
], "%s LinkEdit\n", mem_to_string((unsigned long long)total_fw_linkedit_size
));
1649 if (tbuf
[COLS
-2] != '\n') {
1650 tbuf
[COLS
-1] = '\n';
1658 sprintf(tbuf
, "MemRegions: num = %4d, ", total_memory_regions
);
1659 clen
= strlen(tbuf
);
1660 sprintf(&tbuf
[clen
], "resident = %s + ", mem_to_string(total_private_size
- total_fw_private
));
1661 clen
= clen
+ strlen(&tbuf
[clen
]);
1662 sprintf(&tbuf
[clen
], "%s private, ", mem_to_string(total_fw_private
));
1663 clen
= clen
+ strlen(&tbuf
[clen
]);
1664 sprintf(&tbuf
[clen
], "%s shared\n", mem_to_string(total_shared_size
));
1666 if (tbuf
[COLS
-2] != '\n') {
1667 tbuf
[COLS
-1] = '\n';
1675 /* display main memory statistics */
1677 unsigned long long total_resident_size
,
1678 active_resident_size
,
1679 inactive_resident_size
,
1683 active_resident_size
= vm_stat
.active_count
* pagesize
;
1684 inactive_resident_size
= vm_stat
.inactive_count
* pagesize
;
1685 wire_resident_size
= vm_stat
.wire_count
* pagesize
;
1686 total_resident_size
= (vm_stat
.active_count
+ vm_stat
.inactive_count
+
1687 vm_stat
.wire_count
) * pagesize
;
1688 free_size
= vm_stat
.free_count
* pagesize
;
1690 sprintf(tbuf
, "PhysMem: ");
1691 clen
= strlen(tbuf
);
1692 sprintf(&tbuf
[clen
], "%s wired, ", mem_to_string(wire_resident_size
));
1693 clen
= clen
+ strlen(&tbuf
[clen
]);
1694 sprintf(&tbuf
[clen
], "%s active, ", mem_to_string(active_resident_size
));
1695 clen
= clen
+ strlen(&tbuf
[clen
]);
1696 sprintf(&tbuf
[clen
], "%s inactive, ", mem_to_string(inactive_resident_size
));
1697 clen
= clen
+ strlen(&tbuf
[clen
]);
1698 sprintf(&tbuf
[clen
], "%s used, ", mem_to_string(total_resident_size
));
1699 clen
= clen
+ strlen(&tbuf
[clen
]);
1700 sprintf(&tbuf
[clen
], "%s free\n", mem_to_string(free_size
));
1702 if (tbuf
[COLS
-2] != '\n') {
1703 tbuf
[COLS
-1] = '\n';
1712 int i_io
, o_io
, i_kbytes
, o_kbytes
;
1714 i_io
= o_io
= i_kbytes
= o_kbytes
= 0;
1717 if (i_net
.io_prev
|| o_net
.io_prev
) {
1718 i_io
= i_net
.io
- i_net
.io_prev
;
1719 o_io
= o_net
.io
- o_net
.io_prev
;
1720 i_kbytes
= i_net
.kbytes
- i_net
.kbytes_prev
;
1721 o_kbytes
= o_net
.kbytes
- o_net
.kbytes_prev
;
1723 } else if (events_accumulate
) {
1724 if (i_net
.io_prev
|| o_net
.io_prev
) {
1725 i_net
.io_accum
+= i_net
.io
- i_net
.io_prev
;
1726 o_net
.io_accum
+= o_net
.io
- o_net
.io_prev
;
1727 i_net
.kbytes_accum
+= i_net
.kbytes
- i_net
.kbytes_prev
;
1728 o_net
.kbytes_accum
+= o_net
.kbytes
- o_net
.kbytes_prev
;
1730 i_io
= i_net
.io_accum
;
1731 o_io
= o_net
.io_accum
;
1732 i_kbytes
= i_net
.kbytes_accum
;
1733 o_kbytes
= o_net
.kbytes_accum
;
1738 i_kbytes
= i_net
.kbytes
;
1739 o_kbytes
= o_net
.kbytes
;
1741 sprintf(tbuf
, "Networks:%10d ipkts/%dK", i_io
, i_kbytes
);
1742 clen
= strlen(tbuf
);
1743 memset(&tbuf
[clen
], ' ', 36 - clen
);
1744 sprintf(&tbuf
[36], "%10d opkts /%dK\n", o_io
, o_kbytes
);
1746 i_net
.io_prev
= i_net
.io
;
1747 o_net
.io_prev
= o_net
.io
;
1748 i_net
.kbytes_prev
= i_net
.kbytes
;
1749 o_net
.kbytes_prev
= o_net
.kbytes
;
1751 if (tbuf
[COLS
-2] != '\n') {
1752 tbuf
[COLS
-1] = '\n';
1760 i_io
= o_io
= i_kbytes
= o_kbytes
= 0;
1763 if (i_dsk
.io_prev
|| o_dsk
.io_prev
) {
1764 i_io
= i_dsk
.io
- i_dsk
.io_prev
;
1765 o_io
= o_dsk
.io
- o_dsk
.io_prev
;
1766 i_kbytes
= i_dsk
.kbytes
- i_dsk
.kbytes_prev
;
1767 o_kbytes
= o_dsk
.kbytes
- o_dsk
.kbytes_prev
;
1769 } else if (events_accumulate
) {
1770 if (i_dsk
.io_prev
|| o_dsk
.io_prev
) {
1771 i_dsk
.io_accum
+= i_dsk
.io
- i_dsk
.io_prev
;
1772 o_dsk
.io_accum
+= o_dsk
.io
- o_dsk
.io_prev
;
1773 i_dsk
.kbytes_accum
+= i_dsk
.kbytes
- i_dsk
.kbytes_prev
;
1774 o_dsk
.kbytes_accum
+= o_dsk
.kbytes
- o_dsk
.kbytes_prev
;
1776 i_io
= i_dsk
.io_accum
;
1777 o_io
= o_dsk
.io_accum
;
1778 i_kbytes
= i_dsk
.kbytes_accum
;
1779 o_kbytes
= o_dsk
.kbytes_accum
;
1784 i_kbytes
= i_dsk
.kbytes
;
1785 o_kbytes
= o_dsk
.kbytes
;
1787 sprintf(tbuf
, "Disks: %10d reads/%dK", i_io
, i_kbytes
);
1788 clen
= strlen(tbuf
);
1789 memset(&tbuf
[clen
], ' ', 36 - clen
);
1790 sprintf(&tbuf
[36], "%10d writes/%dK\n", o_io
, o_kbytes
);
1792 i_dsk
.io_prev
= i_dsk
.io
;
1793 o_dsk
.io_prev
= o_dsk
.io
;
1794 i_dsk
.kbytes_prev
= i_dsk
.kbytes
;
1795 o_dsk
.kbytes_prev
= o_dsk
.kbytes
;
1797 if (tbuf
[COLS
-2] != '\n') {
1798 tbuf
[COLS
-1] = '\n';
1807 /* display paging statistics */
1809 int pageins
, pageouts
;
1811 pageins
= pageouts
= 0;
1814 if (i_vm
.io_prev
|| o_vm
.io_prev
) {
1815 pageins
= vm_stat
.pageins
- i_vm
.io_prev
;
1816 pageouts
= vm_stat
.pageouts
- o_vm
.io_prev
;
1818 } else if (events_accumulate
) {
1819 if (i_vm
.io_prev
|| o_vm
.io_prev
) {
1820 i_vm
.io_accum
+= vm_stat
.pageins
- i_vm
.io_prev
;
1821 o_vm
.io_accum
+= vm_stat
.pageouts
- o_vm
.io_prev
;
1823 pageins
= i_vm
.io_accum
;
1824 pageouts
= o_vm
.io_accum
;
1827 pageins
= vm_stat
.pageins
;
1828 pageouts
= vm_stat
.pageouts
;
1830 sprintf(tbuf
, "VM: %10d pageins", pageins
);
1831 clen
= strlen(tbuf
);
1832 memset(&tbuf
[clen
], ' ', 36 - clen
);
1833 sprintf(&tbuf
[36], "%10d pageouts\n", pageouts
);
1835 sprintf(tbuf
, "VM: %5.5s + ", mem_to_string(total_virtual_size
));
1836 clen
= strlen(tbuf
);
1837 sprintf(&tbuf
[clen
], "%5.5s ", mem_to_string(total_fw_vsize
));
1838 clen
= clen
+ strlen(&tbuf
[clen
]);
1839 sprintf(&tbuf
[clen
], "%d(%d) pageins, ", vm_stat
.pageins
, vm_stat
.pageins
- (int)i_vm
.io_prev
);
1840 clen
= clen
+ strlen(&tbuf
[clen
]);
1841 sprintf(&tbuf
[clen
], "%d(%d) pageouts\n", vm_stat
.pageouts
, vm_stat
.pageouts
- (int)o_vm
.io_prev
);
1843 if (tbuf
[COLS
-2] != '\n') {
1844 tbuf
[COLS
-1] = '\n';
1852 i_vm
.io_prev
= vm_stat
.pageins
;
1853 o_vm
.io_prev
= vm_stat
.pageouts
;
1856 /* display the processes */
1859 sprintf(tbuf
, "\n PID COMMAND %%%%CPU TIME FAULTS PGINS/COWS MSENT/MRCVD BSD/MACH CSW\n");
1860 else if (events_only
)
1861 sprintf(tbuf
, "\n PID COMMAND %%%%CPU TIME FAULTS PAGEINS COW_FAULTS MSGS_SENT MSGS_RCVD BSDSYSCALL MACHSYSCALL CSWITCH\n");
1862 else if (wide_output
)
1863 sprintf(tbuf
, "\n PID COMMAND %%%%CPU TIME #TH #PRTS(delta) #MREGS VPRVT RPRVT(delta) RSHRD(delta) RSIZE(delta) VSIZE(delta)\n");
1865 sprintf(tbuf
, "\n PID COMMAND %%%%CPU TIME #TH #PRTS #MREGS RPRVT RSHRD RSIZE VSIZE\n");
1868 if (tbuf
[COLS
] != '\n') {
1869 tbuf
[COLS
+1] = '\n';
1882 sizeof(struct proc_info
*),
1885 /* now, show the top whatever */
1886 if (active_procs
> topn
)
1888 /* adjust for too many processes */
1889 active_procs
= topn
;
1892 for (prefp
= pref
, i
= 0; i
< active_procs
; prefp
++, i
++)
1896 sprintf(tbuf
, "%5d", pp
->pid
); /* pid */
1897 clen
= strlen(tbuf
);
1898 sprintf(&tbuf
[clen
], " %-10.10s ", pp
->command
); /* command */
1899 clen
= clen
+ strlen(&tbuf
[clen
]);
1901 print_usage(&tbuf
[clen
], pp
->cpu_usage
);
1902 clen
= clen
+ strlen(&tbuf
[clen
]);
1904 sprintf(&tbuf
[clen
], " ");
1907 print_time(&tbuf
[clen
], pp
->total_time
); /* cputime */
1908 clen
= clen
+ strlen(&tbuf
[clen
]);
1913 sprintf(&tbuf
[clen
], " %6d", pp
->deltatei
.faults
);
1914 clen
= clen
+ strlen(&tbuf
[clen
]);
1915 sprintf(&tbuf
[clen
], " %5d", pp
->deltatei
.pageins
);
1916 clen
= clen
+ strlen(&tbuf
[clen
]);
1917 sprintf(&tbuf
[clen
], "/%-4d", pp
->deltatei
.cow_faults
);
1918 clen
= clen
+ strlen(&tbuf
[clen
]);
1919 sprintf(&tbuf
[clen
], " %5d", pp
->deltatei
.messages_sent
);
1920 clen
= clen
+ strlen(&tbuf
[clen
]);
1921 sprintf(&tbuf
[clen
], "/%-4d", pp
->deltatei
.messages_received
);
1922 clen
= clen
+ strlen(&tbuf
[clen
]);
1923 sprintf(&tbuf
[clen
], " %5d", pp
->deltatei
.syscalls_unix
);
1924 clen
= clen
+ strlen(&tbuf
[clen
]);
1925 sprintf(&tbuf
[clen
], "/%-5d", pp
->deltatei
.syscalls_mach
);
1926 clen
= clen
+ strlen(&tbuf
[clen
]);
1927 sprintf(&tbuf
[clen
], "%6d", pp
->deltatei
.csw
);
1928 clen
= clen
+ strlen(&tbuf
[clen
]);
1929 } else if (events_accumulate
) {
1930 sprintf(&tbuf
[clen
], " %-8d", pp
->deltatei
.faults
);
1931 clen
= clen
+ strlen(&tbuf
[clen
]);
1932 sprintf(&tbuf
[clen
], " %-8d", pp
->deltatei
.pageins
);
1933 clen
= clen
+ strlen(&tbuf
[clen
]);
1934 sprintf(&tbuf
[clen
], " %-10d", pp
->deltatei
.cow_faults
);
1935 clen
= clen
+ strlen(&tbuf
[clen
]);
1936 sprintf(&tbuf
[clen
], " %-10d", pp
->deltatei
.messages_sent
);
1937 clen
= clen
+ strlen(&tbuf
[clen
]);
1938 sprintf(&tbuf
[clen
], " %-10d", pp
->deltatei
.messages_received
);
1939 clen
= clen
+ strlen(&tbuf
[clen
]);
1940 sprintf(&tbuf
[clen
], " %-10d", pp
->deltatei
.syscalls_unix
);
1941 clen
= clen
+ strlen(&tbuf
[clen
]);
1942 sprintf(&tbuf
[clen
], " %-11d", pp
->deltatei
.syscalls_mach
);
1943 clen
= clen
+ strlen(&tbuf
[clen
]);
1944 sprintf(&tbuf
[clen
], " %-8d", pp
->deltatei
.csw
);
1945 clen
= clen
+ strlen(&tbuf
[clen
]);
1947 sprintf(&tbuf
[clen
], " %-8d", pp
->tei
.faults
);
1948 clen
= clen
+ strlen(&tbuf
[clen
]);
1949 sprintf(&tbuf
[clen
], " %-8d", pp
->tei
.pageins
);
1950 clen
= clen
+ strlen(&tbuf
[clen
]);
1951 sprintf(&tbuf
[clen
], " %-10d", pp
->tei
.cow_faults
);
1952 clen
= clen
+ strlen(&tbuf
[clen
]);
1953 sprintf(&tbuf
[clen
], " %-10d", pp
->tei
.messages_sent
);
1954 clen
= clen
+ strlen(&tbuf
[clen
]);
1955 sprintf(&tbuf
[clen
], " %-10d", pp
->tei
.messages_received
);
1956 clen
= clen
+ strlen(&tbuf
[clen
]);
1957 sprintf(&tbuf
[clen
], " %-10d", pp
->tei
.syscalls_unix
);
1958 clen
= clen
+ strlen(&tbuf
[clen
]);
1959 sprintf(&tbuf
[clen
], " %-11d", pp
->tei
.syscalls_mach
);
1960 clen
= clen
+ strlen(&tbuf
[clen
]);
1961 sprintf(&tbuf
[clen
], " %-8d", pp
->tei
.csw
);
1962 clen
= clen
+ strlen(&tbuf
[clen
]);
1966 sprintf(&tbuf
[clen
], " %3d", pp
->num_threads
); /* # of threads */
1967 clen
= clen
+ strlen(&tbuf
[clen
]);
1968 sprintf(&tbuf
[clen
], " %5d", pp
->num_ports
); /* # of ports */
1969 clen
= clen
+ strlen(&tbuf
[clen
]);
1973 sprintf(&tbuf
[clen
], "(%5d)", pp
->dnum_ports
);
1975 sprintf(&tbuf
[clen
], " ");
1976 clen
= clen
+ strlen(&tbuf
[clen
]);
1978 if (pp
->pid
|| do_proc0_vm
)
1979 sprintf(&tbuf
[clen
], " %4d", pp
->obj_count
);
1981 sprintf(&tbuf
[clen
], " -");
1982 clen
= clen
+ strlen(&tbuf
[clen
]);
1985 if (pp
->pid
|| do_proc0_vm
) {
1986 sprintf(&tbuf
[clen
], " %5.5s", mem_to_string((unsigned long long)pp
->vprivate
)); /* res size */
1987 clen
= clen
+ strlen(&tbuf
[clen
]);
1988 sprintf(&tbuf
[clen
], " %5.5s", mem_to_string((unsigned long long)pp
->private)); /* res size */
1989 clen
= clen
+ strlen(&tbuf
[clen
]);
1992 sprintf(&tbuf
[clen
], "(%5.5s)", offset_to_string(pp
->drprvt
));
1994 sprintf(&tbuf
[clen
], " ");
1996 sprintf(&tbuf
[clen
], " - - ");
1998 if (pp
->drprvt
== 0)
2000 else if ((int)pp
->drprvt
> 0)
2005 if (pp
->pid
|| do_proc0_vm
)
2006 sprintf(&tbuf
[clen
], " %5.5s%s", mem_to_string((unsigned long long)pp
->private), dp
); /* res size */
2008 sprintf(&tbuf
[clen
], " -");
2010 clen
= clen
+ strlen(&tbuf
[clen
]);
2013 if (pp
->pid
|| do_proc0_vm
) {
2014 sprintf(&tbuf
[clen
], " %5.5s", mem_to_string((unsigned long long)pp
->shared
));
2015 clen
= clen
+ strlen(&tbuf
[clen
]);
2018 sprintf(&tbuf
[clen
], "(%5.5s)", offset_to_string(pp
->drshrd
));
2020 sprintf(&tbuf
[clen
], " ");
2022 sprintf(&tbuf
[clen
], " - ");
2024 if (pp
->drshrd
== 0)
2026 else if ((int)pp
->drshrd
> 0)
2031 if (pp
->pid
|| do_proc0_vm
)
2032 sprintf(&tbuf
[clen
], " %5.5s%s", mem_to_string((unsigned long long)pp
->shared
), dp
);
2034 sprintf(&tbuf
[clen
], " - ");
2036 clen
= clen
+ strlen(&tbuf
[clen
]);
2039 sprintf(&tbuf
[clen
], " %5.5s", mem_to_string((unsigned long long)pp
->resident_size
)); /* res size */
2040 clen
= clen
+ strlen(&tbuf
[clen
]);
2043 sprintf(&tbuf
[clen
], "(%5.5s)", offset_to_string(pp
->drsize
));
2045 sprintf(&tbuf
[clen
], " ");
2047 if (pp
->drsize
== 0)
2049 else if ((int)pp
->drsize
> 0)
2054 sprintf(&tbuf
[clen
], " %5.5s%s", mem_to_string((unsigned long long)pp
->resident_size
), dp
); /* res size */
2056 clen
= clen
+ strlen(&tbuf
[clen
]);
2059 sprintf(&tbuf
[clen
], " %5.5s", mem_to_string((unsigned long long)pp
->virtual_size
)); /* size */
2060 clen
= clen
+ strlen(&tbuf
[clen
]);
2063 sprintf(&tbuf
[clen
], "(%5.5s)", offset_to_string(pp
->rvsize
));
2065 sprintf(&tbuf
[clen
], " ");
2067 if (pp
->dvsize
== 0)
2069 else if ((int)pp
->dvsize
> 0)
2074 sprintf(&tbuf
[clen
], " %5.5s%s", mem_to_string((unsigned long long)pp
->virtual_size
), dp
); /* size */
2076 clen
= clen
+ strlen(&tbuf
[clen
]);
2078 } /* else not events only */
2080 sprintf(&tbuf
[clen
], "\n");
2082 if (tbuf
[COLS
-1] != '\n') {
2092 for (n
= 0, prefp
= pref
; n
< total_procs
&& i
< topn
; prefp
++, n
++)
2096 if (pp
->has_idle_thread
== TRUE
) {
2097 sprintf(tbuf
, "%5d", pp
->pid
);
2098 clen
= strlen(tbuf
);
2099 sprintf(&tbuf
[clen
], " %-10.10s ", "idle_thread");
2100 clen
= clen
+ strlen(&tbuf
[clen
]);
2102 print_usage(&tbuf
[clen
], pp
->cpu_idle
);
2103 clen
= clen
+ strlen(&tbuf
[clen
]);
2104 sprintf(&tbuf
[clen
], " ");
2106 print_time(&tbuf
[clen
], pp
->idle_time
);
2107 clen
= clen
+ strlen(&tbuf
[clen
]);
2108 sprintf(&tbuf
[clen
], "\n");
2110 if (tbuf
[COLS
-1] != '\n') {
2139 static struct nlist nl_net
[] = {
2148 * Read kernel memory, return 0 on success.
2151 kread(addr
, buf
, size
)
2156 static kvm_t
*kvmd
= 0;
2162 kvmd
= kvm_openfiles(NULL
, NULL
, NULL
, O_RDONLY
, buf
);
2164 if (kvm_nlist(kvmd
, nl_net
) < 0)
2165 errx(1, "kvm_nlist: %s", kvm_geterr(kvmd
));
2167 if (nl_net
[0].n_type
== 0)
2168 errx(1, "no namelist");
2175 if (kvm_read(kvmd
, addr
, buf
, size
) != size
) {
2176 warnx("%s", kvm_geterr(kvmd
));
2183 getNETWORKcounters()
2186 struct ifnethead ifnethead
;
2189 if (nl_net
[N_IFNET
].n_value
== 0)
2191 if (kread(nl_net
[N_IFNET
].n_value
, (char *)&ifnethead
, sizeof ifnethead
))
2200 for (off
= (u_long
)ifnethead
.tqh_first
; off
; ) {
2203 if (kread(off
, (char *)&ifnet
, sizeof ifnet
))
2205 if (kread((u_long
)ifnet
.if_name
, tname
, 16))
2208 if (strncmp(tname
, "lo", 2)) {
2209 i_net
.io
+= ifnet
.if_ipackets
;
2210 o_net
.io
+= ifnet
.if_opackets
;
2212 i_net
.kbytes
+= ifnet
.if_ibytes
/1024;
2213 o_net
.kbytes
+= ifnet
.if_obytes
/1024;
2215 off
= (u_long
) ifnet
.if_link
.tqe_next
;
2223 io_registry_entry_t drive
= 0; /* needs release */
2224 UInt64 totalReadBytes
= 0;
2225 UInt64 totalReadCount
= 0;
2226 UInt64 totalWriteBytes
= 0;
2227 UInt64 totalWriteCount
= 0;
2229 kern_return_t status
= 0;
2231 while ( (drive
= IOIteratorNext(drivelist
)) )
2233 CFNumberRef number
= 0; /* don't release */
2234 CFDictionaryRef properties
= 0; /* needs release */
2235 CFDictionaryRef statistics
= 0; /* don't release */
2238 /* Obtain the properties for this drive object */
2240 status
= IORegistryEntryCreateCFProperties (drive
,
2241 (CFMutableDictionaryRef
*) &properties
,
2242 kCFAllocatorDefault
,
2245 /* Obtain the statistics from the drive properties */
2246 statistics
= (CFDictionaryRef
) CFDictionaryGetValue(properties
, CFSTR(kIOBlockStorageDriverStatisticsKey
));
2249 /* Obtain the number of bytes read from the drive statistics */
2250 number
= (CFNumberRef
) CFDictionaryGetValue (statistics
,
2251 CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey
));
2253 status
= CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
2254 totalReadBytes
+= value
;
2256 /* Obtain the number of reads from the drive statistics */
2257 number
= (CFNumberRef
) CFDictionaryGetValue (statistics
,
2258 CFSTR(kIOBlockStorageDriverStatisticsReadsKey
));
2260 status
= CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
2261 totalReadCount
+= value
;
2264 /* Obtain the number of writes from the drive statistics */
2265 number
= (CFNumberRef
) CFDictionaryGetValue (statistics
,
2266 CFSTR(kIOBlockStorageDriverStatisticsWritesKey
));
2268 status
= CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
2269 totalWriteCount
+= value
;
2271 /* Obtain the number of bytes written from the drive statistics */
2272 number
= (CFNumberRef
) CFDictionaryGetValue (statistics
,
2273 CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey
));
2275 status
= CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
2276 totalWriteBytes
+= value
;
2279 /* Release resources */
2281 CFRelease(properties
); properties
= 0;
2282 IOObjectRelease(drive
); drive
= 0;
2284 IOIteratorReset(drivelist
);
2286 i_dsk
.io
= (int)totalReadCount
;
2287 o_dsk
.io
= (int)totalWriteCount
;
2288 i_dsk
.kbytes
= (int)(totalReadBytes
/ 1024);
2289 o_dsk
.kbytes
= (int)(totalWriteBytes
/ 1024);