updated release notes.
[cpuHistory.git] / CPUInfo.m
blob77d935df7ec04687e96c1925cdb5df47de797be1
1 /*
2  *      CPU History
3  *      Christopher Bowns, 2008
4  */
5 //  CPUInfo.m
6 //  CPU Usage
7 //
8 //  Created by Peter Hosey on 2006-06-21.
9 //  Copyright 2006 Peter Hosey. All rights reserved.
11 //  Modified by Christopher Bowns, starting 2008-1-1.
13 #ifndef NSLOG_DEBUG
14 #define NSLOG_DEBUG
15 #endif
17 #import "CPUInfo.h"
19 #include <sys/types.h>
20 //sqrtf, ceilf
21 #include <math.h>
22 //sysctl and its parameters
23 #include <sys/sysctl.h>
24 //errno, strerror
25 #include <sys/errno.h>
26 #include <string.h>
28 @implementation CPUInfo
32         Accomplishes:
33                 inits cpudata, inptr, outptr
34                 retrieves lastProcessorInfo for refresh method to go to town.
35         
36         if cannot get processor info, returns nil.
38 - (CPUInfo *) initWithCapacity:(unsigned)numItems
40         
41         /*
42                 from Hosey's CPU Usage.app:
43         */      
44         //We could get the number of processors the same way that we get the CPU usage info, but that allocates memory.
45 /*      enum { miblen = 2U };
46         int mib[miblen] = { CTL_HW, HW_NCPU };
47         size_t sizeOfNumCPUs = sizeof(numCPUs);
48         int status = sysctl(mib, miblen,
49                    &numCPUs, &sizeOfNumCPUs,
50 */                 /*newp*/ // NULL, /*newlen*/ 0U);
51 //      if(status != 0) {
52                 numCPUs = 1; // TODO we're going to assume one CPU for the moment.
53 //              NSLog(@"%s error status, assuming one CPU", _cmd);
54 //      }
55         
56         
57         
58         
59         
60         
61         self = [super init];
62         
63         size = numItems;
64         cpudata = calloc(numItems, sizeof(CPUData));
65         if (cpudata == NULL) {
66                 NSLog (@"%s Failed to allocate buffer for CPUInfo", _cmd);
67                 return (nil);
68         }
69         // Set up our data structure ptrs
70         inptr = 0;
71         outptr = -1;
72         
73         // set the lastProcessorInfo array so we can get to work when we call refresh:
74         natural_t numProcessors_nobodyCares = 0U;
75         kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, (natural_t *)&numProcessors_nobodyCares, (processor_info_array_t *)&lastProcessorInfo, (mach_msg_type_number_t *)&numLastProcessorInfo);
76         if(err != KERN_SUCCESS) {
77                 NSLog(@"%s failed to get cpu statistics", _cmd);
78                 
79                 // if we can't get this info, then we're toast. Exit gracefully.
80                 return (nil);
81         }
82         
83         return (self);
88         Assumptions:
89                 init has run.
90                 lastProcessorInfo and numLastProcessorInfo contain valid data from prior refresh of CPU info
91         Accomplishes:
92                 retrieves current data
93                 calculates avg cpu load over last period
94                 updates cpudata array with info
95                 deallocates old numLastProcInfo and lastProcessorInfo and set ptrs to new data
97 - (void)refresh
99         processor_info_array_t processorInfo;
100         natural_t numProcessors_nobodyCares = 0U;
101         mach_msg_type_number_t numProcessorInfo;
103         kern_return_t err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, (natural_t *)&numProcessors_nobodyCares, (processor_info_array_t *)&processorInfo, (mach_msg_type_number_t *)&numProcessorInfo);
104         if(err != KERN_SUCCESS) {
105                 NSLog(@"%s failed to get cpu statistics", _cmd);
106         }
107         
108         /*
109                 TODO make this multicore. First, we're gonna need a multicore machine to test it on.
110         */
111         // for(unsigned i = 0U; i < numCPUs; ++i)
112         
113         unsigned int inUse, total, user, sys, nice, idle;
114                 
115         user = processorInfo[CPU_STATE_USER] - lastProcessorInfo[CPU_STATE_USER];
116         sys = processorInfo[CPU_STATE_SYSTEM] - lastProcessorInfo[CPU_STATE_SYSTEM];
117         nice = processorInfo[CPU_STATE_NICE] - lastProcessorInfo[CPU_STATE_NICE];
118         idle = processorInfo[CPU_STATE_IDLE] - lastProcessorInfo[CPU_STATE_IDLE];
120         inUse = user + sys + nice;
121         total = inUse + idle;
122         
123         cpudata[inptr].user = (double)user / (double)total;
124         cpudata[inptr].sys = (double)sys / (double)total;
125         cpudata[inptr].nice = (double)nice / (double)total;
126         cpudata[inptr].idle = (double)idle / (double)total;
127         
128         
129         // deallocate the last one, since we don't want memory leaks.
130         /*
131                 TODO refresh: test in Shark / malloc debug: this DOES leak if we take this dealloc out, right?
132         */
133         if(lastProcessorInfo) {
134                 size_t lastProcessorInfoSize = sizeof(integer_t) * numLastProcessorInfo;
135                 vm_deallocate(mach_task_self(), (vm_address_t)lastProcessorInfo, lastProcessorInfoSize);
136         }
138         lastProcessorInfo = processorInfo;
139         numLastProcessorInfo = numProcessorInfo;
140         
141         if (++inptr >= size) // advance our data ptr
142                 inptr = 0;
146 - (void)startIterate
148         outptr = inptr;
152 - (BOOL)getNext:(CPUDataPtr)ptr
154         if (outptr == -1)
155                 return (FALSE);
156         *ptr = cpudata[outptr++];
157         if (outptr >= size)
158                 outptr = 0;
159         if (outptr == inptr)
160                 outptr = -1;
161         return (TRUE);
165 - (void)getCurrent:(CPUDataPtr)ptr
167         *ptr = cpudata[inptr ? inptr - 1 : size - 1];
171 - (void)getLast:(CPUDataPtr)ptr
173         *ptr = cpudata[inptr > 1 ? inptr - 2 : size + inptr - 2];
177 - (int)getSize
179         return (size);
182 @end