URI:
       tDarwin.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tDarwin.c (10102B)
       ---
            1 #include <u.h>
            2 #include <sys/types.h>
            3 #include <sys/protosw.h>
            4 #include <sys/socket.h>
            5 #include <sys/sysctl.h>
            6 #include <sys/time.h>
            7 #include <sys/dkstat.h>
            8 #include <net/if.h>
            9 #include <net/if_var.h>
           10 #include <net/if_dl.h>
           11 #include <net/if_types.h>
           12 #include <ifaddrs.h>
           13 #include <sys/ioctl.h>
           14 #include <limits.h>
           15 #include <libc.h>
           16 #include <bio.h>
           17 
           18 #include <mach/mach.h>
           19 #include <mach/mach_time.h>
           20 #include <CoreFoundation/CoreFoundation.h>
           21 #include <IOKit/ps/IOPowerSources.h>
           22 AUTOFRAMEWORK(CoreFoundation)
           23 AUTOFRAMEWORK(IOKit)
           24 
           25 #include "dat.h"
           26 
           27 typedef struct Sample Sample;
           28 
           29 struct Sample
           30 {
           31         uint seq;
           32         host_cpu_load_info_data_t cpu, p_cpu;
           33         vm_size_t pgsize;
           34         double divisor;
           35         uint64_t time, p_time;
           36         vm_statistics_data_t vm_stat, p_vm_stat;
           37         boolean_t purgeable_is_valid;
           38 #ifdef VM_SWAPUSAGE        /* 10.4+ */
           39         struct xsw_usage xsu;
           40 #endif
           41         boolean_t xsu_valid;
           42         integer_t syscalls_mach, p_syscalls_mach;
           43         integer_t syscalls_unix, p_syscalls_unix;
           44         ulong csw, p_csw;
           45         uint net_ifaces;
           46         uvlong net_ipackets, p_net_ipackets;
           47         uvlong net_opackets, p_net_opackets;
           48         uvlong net_ibytes, p_net_ibytes;
           49         uvlong net_obytes, p_net_obytes;
           50         uvlong net_errors, p_net_errors;
           51         ulong usecs;
           52 };
           53 
           54 static Sample sample;
           55 
           56 void xsample(int);
           57 void xapm(int);
           58 void xloadavg(int);
           59 void xcpu(int);
           60 void xswap(int);
           61 void xvm(int);
           62 void xnet(int);
           63 
           64 void (*statfn[])(int) =
           65 {
           66         xsample,
           67         xapm,
           68         xloadavg,
           69         xswap,
           70         xcpu,
           71         xvm,
           72         xnet,
           73         0
           74 };
           75 
           76 static mach_port_t stat_port;
           77 
           78 void
           79 sampleinit(void)
           80 {
           81         mach_timebase_info_data_t info;
           82 
           83         if(stat_port)
           84                 return;
           85 
           86         stat_port = mach_host_self();
           87         memset(&sample, 0, sizeof sample);
           88         if(host_page_size(stat_port, &sample.pgsize) != KERN_SUCCESS)
           89                 sample.pgsize = 4096;
           90 
           91         /* populate clock tick info for timestamps */
           92         mach_timebase_info(&info);
           93         sample.divisor = 1000.0 * (double)info.denom/info.numer;
           94         sample.time = mach_absolute_time();
           95 }
           96 
           97 void
           98 samplenet(void)
           99 {
          100         struct ifaddrs *ifa_list, *ifa;
          101         struct if_data *if_data;
          102 
          103         ifa_list = nil;
          104         sample.net_ifaces = 0;
          105         if(getifaddrs(&ifa_list) == 0){
          106                 sample.p_net_ipackets = sample.net_ipackets;
          107                 sample.p_net_opackets = sample.net_opackets;
          108                 sample.p_net_ibytes = sample.net_ibytes;
          109                 sample.p_net_obytes = sample.net_obytes;
          110                 sample.p_net_errors = sample.net_errors;
          111 
          112                 sample.net_ipackets = 0;
          113                 sample.net_opackets = 0;
          114                 sample.net_ibytes = 0;
          115                 sample.net_obytes = 0;
          116                 sample.net_errors = 0;
          117                 sample.net_ifaces = 0;
          118 
          119                 for(ifa=ifa_list; ifa; ifa=ifa->ifa_next){
          120                         if(ifa->ifa_addr->sa_family != AF_LINK)
          121                                 continue;
          122                         if((ifa->ifa_flags&(IFF_UP|IFF_RUNNING)) == 0)
          123                                 continue;
          124                         if(ifa->ifa_data == nil)
          125                                 continue;
          126                         if(strncmp(ifa->ifa_name, "lo", 2) == 0)        /* loopback */
          127                                 continue;
          128 
          129                         if_data = (struct if_data*)ifa->ifa_data;
          130                         sample.net_ipackets += if_data->ifi_ipackets;
          131                         sample.net_opackets += if_data->ifi_opackets;
          132                         sample.net_ibytes += if_data->ifi_ibytes;
          133                         sample.net_obytes += if_data->ifi_obytes;
          134                         sample.net_errors += if_data->ifi_ierrors + if_data->ifi_oerrors;
          135                         sample.net_ifaces++;
          136                 }
          137                 freeifaddrs(ifa_list);
          138         }
          139 }
          140 
          141 
          142 /*
          143  * The following forces the program to be run with the suid root as
          144  * all the other stat monitoring apps get set:
          145  *
          146  * -rwsr-xr-x   1 root  wheel  83088 Mar 20  2005 /usr/bin/top
          147  * -rwsrwxr-x   1 root  admin  54048 Mar 20  2005
          148  *        /Applications/Utilities/Activity Monitor.app/Contents/Resources/pmTool
          149  *
          150  * If Darwin eventually encompases more into sysctl then this
          151  * won't be required.
          152  */
          153 void
          154 sampleevents(void)
          155 {
          156         uint i, j, pcnt, tcnt;
          157         mach_msg_type_number_t count;
          158         kern_return_t error;
          159         processor_set_t *psets, pset;
          160         task_t *tasks;
          161         task_events_info_data_t events;
          162 
          163         if((error = host_processor_sets(stat_port, &psets, &pcnt)) != KERN_SUCCESS){
          164                 Bprint(&bout, "host_processor_sets: %s (make sure auxstats is setuid root)\n",
          165                         mach_error_string(error));
          166                 return;
          167         }
          168 
          169         sample.p_syscalls_mach = sample.syscalls_mach;
          170         sample.p_syscalls_unix = sample.syscalls_unix;
          171         sample.p_csw = sample.csw;
          172 
          173         sample.syscalls_mach = 0;
          174         sample.syscalls_unix = 0;
          175         sample.csw = 0;
          176 
          177         for(i=0; i<pcnt; i++){
          178                 if((error=host_processor_set_priv(stat_port, psets[i], &pset)) != KERN_SUCCESS){
          179                         Bprint(&bout, "host_processor_set_priv: %s\n", mach_error_string(error));
          180                         return;
          181                 }
          182                 if((error=processor_set_tasks(pset, &tasks, &tcnt)) != KERN_SUCCESS){
          183                         Bprint(&bout, "processor_set_tasks: %s\n", mach_error_string(error));
          184                         return;
          185                 }
          186                 for(j=0; j<tcnt; j++){
          187                         count = TASK_EVENTS_INFO_COUNT;
          188                         if(task_info(tasks[j], TASK_EVENTS_INFO, (task_info_t)&events, &count) == KERN_SUCCESS){
          189                                 sample.syscalls_mach += events.syscalls_mach;
          190                                 sample.syscalls_unix += events.syscalls_unix;
          191                                 sample.csw += events.csw;
          192                         }
          193 
          194                         if(tasks[j] != mach_task_self())
          195                                 mach_port_deallocate(mach_task_self(), tasks[j]);
          196                 }
          197 
          198                 if((error = vm_deallocate((vm_map_t)mach_task_self(),
          199                                 (vm_address_t)tasks, tcnt*sizeof(task_t))) != KERN_SUCCESS){
          200                         Bprint(&bout, "vm_deallocate: %s\n", mach_error_string(error));
          201                         return;
          202                 }
          203 
          204                 if((error = mach_port_deallocate(mach_task_self(), pset)) != KERN_SUCCESS
          205                 || (error = mach_port_deallocate(mach_task_self(), psets[i])) != KERN_SUCCESS){
          206                         Bprint(&bout, "mach_port_deallocate: %s\n", mach_error_string(error));
          207                         return;
          208                 }
          209         }
          210 
          211         if((error = vm_deallocate((vm_map_t)mach_task_self(), (vm_address_t)psets,
          212                         pcnt*sizeof(processor_set_t))) != KERN_SUCCESS){
          213                 Bprint(&bout, "vm_deallocate: %s\n", mach_error_string(error));
          214                 return;
          215         }
          216 }
          217 
          218 void
          219 xsample(int first)
          220 {
          221         int mib[2];
          222         mach_msg_type_number_t count;
          223         size_t len;
          224 
          225         if(first){
          226                 sampleinit();
          227                 return;
          228         }
          229 
          230         sample.seq++;
          231         sample.p_time = sample.time;
          232         sample.time = mach_absolute_time();
          233 
          234         sample.p_vm_stat = sample.vm_stat;
          235         count = sizeof(sample.vm_stat) / sizeof(natural_t);
          236         host_statistics(stat_port, HOST_VM_INFO, (host_info_t)&sample.vm_stat, &count);
          237 
          238         if(sample.seq == 1)
          239                 sample.p_vm_stat = sample.vm_stat;
          240 
          241 #ifdef VM_SWAPUSAGE
          242         mib[0] = CTL_VM;
          243         mib[1] = VM_SWAPUSAGE;
          244         len = sizeof sample.xsu;
          245         sample.xsu_valid = TRUE;
          246         if(sysctl(mib, 2, &sample.xsu, &len, NULL, 0) < 0 && errno == ENOENT)
          247                 sample.xsu_valid = FALSE;
          248 #endif
          249 
          250         samplenet();
          251         sampleevents();
          252 
          253         sample.p_cpu = sample.cpu;
          254         count = HOST_CPU_LOAD_INFO_COUNT;
          255         host_statistics(stat_port, HOST_CPU_LOAD_INFO, (host_info_t)&sample.cpu, &count);
          256         sample.usecs = (double)(sample.time - sample.p_time)/sample.divisor;
          257         Bprint(&bout, "usecs %lud\n", sample.usecs);
          258 }
          259 
          260 void
          261 xapm(int first)
          262 {
          263         int i, battery;
          264         CFArrayRef array;
          265         CFDictionaryRef dict;
          266         CFTypeRef cf, src, value;
          267 
          268         if(first)
          269                 return;
          270 
          271         src = IOPSCopyPowerSourcesInfo();
          272         array = IOPSCopyPowerSourcesList(src);
          273 
          274         for(i=0; i<CFArrayGetCount(array); i++){
          275                 cf = CFArrayGetValueAtIndex(array, i);
          276                 dict = IOPSGetPowerSourceDescription(src, cf);
          277                 if(dict != nil){
          278                         value = CFDictionaryGetValue(dict, CFSTR("Current Capacity"));
          279                         if(value != nil){
          280                                 if(!CFNumberGetValue(value, kCFNumberIntType, &battery))
          281                                         battery = 100;
          282                                 Bprint(&bout, "battery =%d 100\n", battery);
          283                                 break;
          284                         }
          285                 }
          286         }
          287 
          288         CFRelease(array);
          289         CFRelease(src);
          290 }
          291 
          292 void
          293 xnet(int first)
          294 {
          295         uint n;
          296         ulong err, in, inb, out, outb;
          297 
          298         n = sample.net_ifaces;
          299         in = sample.net_ipackets - sample.p_net_ipackets;
          300         out = sample.net_opackets - sample.p_net_opackets;
          301         inb = sample.net_ibytes - sample.p_net_ibytes;
          302         outb = sample.net_obytes - sample.p_net_obytes;
          303         err = sample.net_errors - sample.p_net_errors;
          304 
          305        Bprint(&bout, "etherb %lud %d\n", inb+outb, n*1000000);
          306        Bprint(&bout, "ether %lud %d\n", in+out, n*1000);
          307        Bprint(&bout, "ethererr %lud %d\n", err, n*1000);
          308        Bprint(&bout, "etherin %lud %d\n", in, n*1000);
          309        Bprint(&bout, "etherout %lud %d\n", out, n*1000);
          310        Bprint(&bout, "etherinb %lud %d\n", inb, n*1000);
          311        Bprint(&bout, "etheroutb %lud %d\n", outb, n*1000);
          312 }
          313 
          314 int
          315 rsys(char *name, char *buf, int len)
          316 {
          317         size_t l;
          318 
          319         l = len;
          320         if(sysctlbyname(name, buf, &l, nil, 0) < 0)
          321                 return -1;
          322         buf[l] = 0;
          323         return l;
          324 }
          325 
          326 vlong
          327 isys(char *name)
          328 {
          329         ulong u;
          330         size_t l;
          331 
          332         l = sizeof u;
          333         if(sysctlbyname(name, &u, &l, nil, 0) < 0)
          334                 return 0;
          335         return u;
          336 }
          337 
          338 void
          339 xvm(int first)
          340 {
          341         natural_t total, active;
          342 
          343         if(first)
          344                 return;
          345 
          346         total = sample.vm_stat.free_count
          347                 + sample.vm_stat.active_count
          348                 + sample.vm_stat.inactive_count
          349                 + sample.vm_stat.wire_count;
          350 
          351         active = sample.vm_stat.active_count
          352                 + sample.vm_stat.inactive_count
          353                 + sample.vm_stat.wire_count;
          354 
          355         if(total)
          356                 Bprint(&bout, "mem =%lud %lud\n", active, total);
          357 
          358         Bprint(&bout, "context %lld 1000\n", (vlong)sample.csw);
          359         Bprint(&bout, "syscall %lld 1000\n", (vlong)sample.syscalls_mach+sample.syscalls_unix);
          360         Bprint(&bout, "intr %lld 1000\n",
          361                 isys("vm.stats.sys.v_intr")
          362                 +isys("vm.stats.sys.v_trap"));
          363 
          364         Bprint(&bout, "fault %lld 1000\n", sample.vm_stat.faults);
          365         Bprint(&bout, "fork %lld 1000\n",
          366                 isys("vm.stats.vm.v_rforks")
          367                 +isys("vm.stats.vm.v_vforks"));
          368 
          369 /*    Bprint(&bout, "hits %lud of %lud lookups (%d%% hit rate)\n", */
          370 /*               (asamp.vm_stat.hits), */
          371 /*               (asamp.vm_stat.lookups), */
          372 /*               (natural_t)(((double)asamp.vm_stat.hits*100)/ (double)asamp.vm_stat.lookups)); */
          373 }
          374 
          375 void
          376 xcpu(int first)
          377 {
          378         ulong user, sys, idle, nice, t;
          379 
          380         if(first)
          381                 return;
          382 
          383         sys = sample.cpu.cpu_ticks[CPU_STATE_SYSTEM] -
          384                 sample.p_cpu.cpu_ticks[CPU_STATE_SYSTEM];
          385         idle = sample.cpu.cpu_ticks[CPU_STATE_IDLE] -
          386                 sample.p_cpu.cpu_ticks[CPU_STATE_IDLE];
          387         user = sample.cpu.cpu_ticks[CPU_STATE_USER] -
          388                 sample.p_cpu.cpu_ticks[CPU_STATE_USER];
          389         nice = sample.cpu.cpu_ticks[CPU_STATE_NICE] -
          390                 sample.p_cpu.cpu_ticks[CPU_STATE_NICE];
          391 
          392         t = sys+idle+user+nice;
          393 
          394         Bprint(&bout, "user =%lud %lud\n", user, t);
          395         Bprint(&bout, "sys =%lud %lud\n", sys, t);
          396         Bprint(&bout, "idle =%lud %lud\n", idle, t);
          397         Bprint(&bout, "nice =%lud %lud\n", nice, t);
          398 }
          399 
          400 void
          401 xloadavg(int first)
          402 {
          403         double l[3];
          404 
          405         if(first)
          406                 return;
          407 
          408         if(getloadavg(l, 3) < 0)
          409                 return;
          410         Bprint(&bout, "load %d 1000\n", (int)(l[0]*1000.0));
          411 }
          412 
          413 void
          414 xswap(int first)
          415 {
          416         if(first)
          417                 return;
          418 
          419 #ifdef VM_SWAPUSAGE
          420         if(sample.xsu_valid)
          421                 Bprint(&bout, "swap %lld %lld\n",
          422                         (vlong)sample.xsu.xsu_used,
          423                         (vlong)sample.xsu.xsu_total);
          424 #endif
          425 }