]>
Commit | Line | Data |
---|---|---|
43bfd57e A |
1 | /* |
2 | * Copyright (c) 2016 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | #import <Foundation/Foundation.h> | |
25 | #import "SCTest.h" | |
26 | #import "SCTestUtils.h" | |
27 | #import <mach/mach_time.h> | |
28 | ||
29 | NSArray<NSString *> * | |
30 | getTestClasses() | |
31 | { | |
32 | static NSMutableArray *subclassNames = nil; | |
33 | Class base; | |
34 | unsigned int classListCount; | |
35 | Class *classList; | |
36 | ||
37 | if (subclassNames != nil) { | |
38 | return subclassNames; | |
39 | } | |
40 | ||
41 | base = [SCTest class]; | |
42 | classListCount = 0; | |
43 | classList = objc_copyClassList(&classListCount); | |
44 | subclassNames = [[NSMutableArray alloc] init]; | |
45 | ||
46 | if (classList) { | |
47 | for (unsigned int i = 0; i < classListCount; i++) { | |
48 | Class superClass = class_getSuperclass(classList[i]); | |
49 | while (superClass && superClass != base) { | |
50 | superClass = class_getSuperclass(superClass); | |
51 | } | |
52 | ||
53 | if (superClass == base) { | |
54 | [subclassNames addObject:@(class_getName(classList[i]))]; | |
55 | } | |
56 | } | |
57 | free(classList); | |
58 | } | |
59 | ||
60 | [subclassNames sortUsingComparator: ^(id obj1, id obj2) { | |
61 | NSString *className1 = obj1; | |
62 | NSString *className2 = obj2; | |
63 | return [className1 compare:className2 options:NSCaseInsensitiveSearch]; | |
64 | }]; | |
65 | ||
66 | return subclassNames; | |
67 | } | |
68 | ||
69 | NSArray<NSString *> * | |
70 | getUnitTestListForClass(Class base) | |
71 | { | |
72 | NSMutableArray<NSString *> *unitTestNames = nil; | |
73 | unsigned int methodListCount = 0; | |
74 | Method *methodList = NULL; | |
75 | ||
76 | methodList = class_copyMethodList(base, &methodListCount); | |
77 | if (methodList) { | |
78 | unitTestNames = [[NSMutableArray alloc] initWithCapacity:methodListCount]; | |
79 | for (unsigned int i = 0; i < methodListCount; i++) { | |
80 | NSString *name = @(sel_getName(method_getName(methodList[i]))); | |
81 | if ([name isEqualToString:@"unitTest"]) { | |
82 | continue; | |
83 | } else if (![name hasPrefix:@"unitTest"]) { | |
84 | continue; | |
85 | } | |
86 | ||
87 | [unitTestNames addObject:name]; | |
88 | } | |
89 | free(methodList); | |
90 | } | |
91 | ||
92 | return unitTestNames; | |
93 | } | |
94 | ||
95 | NSDictionary * | |
96 | getOptionsDictionary(int argc, const char **argv) | |
97 | { | |
98 | NSMutableDictionary *options; | |
99 | NSNumberFormatter *numberFormatter; | |
100 | int ch; | |
101 | int i; | |
102 | struct option entries[] = { | |
103 | kSCTestOptionEntries | |
104 | }; | |
105 | ||
106 | options = [NSMutableDictionary dictionary]; | |
107 | optind = 0; | |
108 | optreset = 1; | |
109 | numberFormatter = [[NSNumberFormatter alloc] init]; | |
110 | ||
111 | while ((ch = getopt_long_only(argc, (char * const *)argv, "", entries, &i)) == 0) { | |
112 | struct option opt = entries[i]; | |
113 | NSString *optKey = [NSString stringWithFormat:@"%s_Str", opt.name]; // ... "_Str" suffix is standardized across all keys. | |
114 | id optVal = nil; | |
115 | ||
116 | if (opt.has_arg) { | |
117 | // Parse the optarg | |
118 | ||
119 | // Attempt string | |
120 | optVal = @(optarg); | |
121 | ||
122 | if (optVal == nil) { | |
123 | // Fall back to NSData | |
124 | // WARNING: Doesn't work if it contains '\0' | |
125 | optVal = [NSData dataWithBytes:optarg length:strlen(optarg)]; | |
126 | } else { | |
127 | // Use NSNumber if the argument is a number | |
128 | NSNumber *number = [numberFormatter numberFromString:optVal]; | |
129 | if (number) { | |
130 | optVal = number; | |
131 | } | |
132 | } | |
133 | } else { | |
134 | optVal = @YES; | |
135 | } | |
136 | ||
137 | // Handle multiple option instances | |
138 | id existingValue = options[optKey]; | |
139 | if (existingValue) { | |
140 | if ([existingValue isKindOfClass:[NSMutableArray class]]) { | |
141 | [(NSMutableArray *)existingValue addObject:optVal]; | |
142 | optVal = existingValue; | |
143 | } else if ([existingValue isKindOfClass:[NSArray class]]) { | |
144 | NSMutableArray *tempArray = [NSMutableArray arrayWithArray:existingValue]; | |
145 | [tempArray addObject:optVal]; | |
146 | optVal = tempArray; | |
147 | } else { | |
148 | optVal = @[existingValue, optVal]; | |
149 | } | |
150 | } | |
151 | ||
152 | options[optKey] = optVal; | |
153 | } | |
154 | ||
155 | if (ch > 0) { | |
156 | return nil; | |
157 | } | |
158 | ||
159 | return options; | |
160 | } | |
161 | ||
162 | static void | |
163 | cpu_routine(CPUUsageInfoInner *usage) | |
164 | { | |
165 | host_name_port_t host; | |
166 | host_cpu_load_info_data_t host_load; | |
167 | mach_msg_type_number_t count; | |
168 | kern_return_t kret; | |
169 | ||
170 | if (usage == NULL) { | |
171 | return; | |
172 | } | |
173 | ||
174 | host = mach_host_self(); | |
175 | count = HOST_CPU_LOAD_INFO_COUNT; | |
176 | kret = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&host_load, &count); | |
177 | if (kret) { | |
178 | return; | |
179 | } | |
180 | ||
181 | // ms per tick. 1 tick is 10 ms. | |
182 | usage->user = ((uint64_t)host_load.cpu_ticks[CPU_STATE_USER]) * 10; | |
183 | usage->sys = ((uint64_t)host_load.cpu_ticks[CPU_STATE_SYSTEM]) * 10; | |
184 | usage->idle = ((uint64_t)host_load.cpu_ticks[CPU_STATE_IDLE]) * 10; | |
185 | } | |
186 | ||
187 | void | |
188 | cpuStart(CPUUsageInfo *cpu) | |
189 | { | |
190 | cpu_routine(&cpu->startCPU); | |
191 | } | |
192 | ||
193 | void | |
194 | cpuEnd(CPUUsageInfo *cpu) | |
195 | { | |
196 | cpu_routine(&cpu->endCPU); | |
197 | } | |
198 | ||
199 | NSString * | |
200 | createUsageStringForCPU(CPUUsageInfo *cpu) | |
201 | { | |
202 | uint64_t userelapsed = cpu->endCPU.user - cpu->startCPU.user; | |
203 | uint64_t systemelapsed = cpu->endCPU.sys - cpu->startCPU.sys; | |
204 | uint64_t idleelapsed = cpu->endCPU.idle - cpu->startCPU.idle; | |
205 | uint64_t totalelapsed = userelapsed + systemelapsed + idleelapsed; | |
206 | double u = ((double)userelapsed * 100)/totalelapsed; | |
207 | double s = ((double)systemelapsed * 100)/totalelapsed; | |
208 | double i = ((double)idleelapsed * 100)/totalelapsed; | |
209 | ||
210 | return [NSString stringWithFormat:@"%1.02f%% user %1.02f%% sys %1.02f%% idle", u, s, i]; | |
211 | } | |
212 | ||
213 | static void | |
214 | timer_routine(struct timespec *ts) | |
215 | { | |
216 | uint64_t diff; | |
217 | static uint32_t orwl_timebase_numer = 0; | |
218 | static uint32_t orwl_timebase_denom = 0; | |
219 | static uint64_t orwl_timestart = 0; | |
220 | if (orwl_timestart == 0) { | |
221 | mach_timebase_info_data_t tb = { 0, 0 }; | |
222 | mach_timebase_info(&tb); | |
223 | orwl_timebase_numer = tb.numer; | |
224 | orwl_timebase_denom = tb.denom; | |
225 | orwl_timestart = mach_absolute_time(); | |
226 | } | |
227 | if (0 == orwl_timebase_denom) { | |
228 | orwl_timebase_denom = 1; | |
229 | } | |
230 | diff = ((mach_absolute_time() - orwl_timestart) * orwl_timebase_numer) / orwl_timebase_denom; | |
231 | ts->tv_sec = (size_t)(diff / NSEC_PER_SEC); | |
232 | ts->tv_nsec = (size_t)(diff - (ts->tv_sec * NSEC_PER_SEC)); | |
233 | } | |
234 | ||
235 | void | |
236 | timerStart(timerInfo *timer) | |
237 | { | |
238 | timer_routine(&timer->startTime); | |
239 | } | |
240 | ||
241 | void | |
242 | timerEnd(timerInfo *timer) | |
243 | { | |
244 | timer_routine(&timer->endTime); | |
245 | } | |
246 | ||
247 | NSString * | |
248 | createUsageStringForTimer(timerInfo *timer) | |
249 | { | |
250 | double elapsed; | |
251 | int64_t nsecs = timer->endTime.tv_nsec - timer->startTime.tv_nsec; | |
252 | uint64_t secs = timer->endTime.tv_sec - timer->startTime.tv_sec; | |
253 | if (nsecs < 0) { | |
254 | nsecs += NSEC_PER_SEC; | |
255 | secs -= 1; | |
256 | } | |
257 | ||
258 | elapsed = (double)secs + (double)nsecs / NSEC_PER_SEC; | |
259 | return [NSString stringWithFormat:@"%f", elapsed]; | |
260 | } |