2 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <Foundation/Foundation.h>
26 #import "SCTestUtils.h"
27 #import <mach/mach_time.h>
32 static NSMutableArray *subclassNames = nil;
34 unsigned int classListCount;
37 if (subclassNames != nil) {
41 base = [SCTest class];
43 classList = objc_copyClassList(&classListCount);
44 subclassNames = [[NSMutableArray alloc] init];
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);
53 if (superClass == base) {
54 [subclassNames addObject:@(class_getName(classList[i]))];
60 [subclassNames sortUsingComparator: ^(id obj1, id obj2) {
61 NSString *className1 = obj1;
62 NSString *className2 = obj2;
63 return [className1 compare:className2 options:NSCaseInsensitiveSearch];
70 getUnitTestListForClass(Class base)
72 NSMutableArray<NSString *> *unitTestNames = nil;
73 unsigned int methodListCount = 0;
74 Method *methodList = NULL;
76 methodList = class_copyMethodList(base, &methodListCount);
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"]) {
83 } else if (![name hasPrefix:@"unitTest"]) {
87 [unitTestNames addObject:name];
96 getOptionsDictionary(int argc, const char **argv)
98 NSMutableDictionary *options;
99 NSNumberFormatter *numberFormatter;
102 struct option entries[] = {
106 options = [NSMutableDictionary dictionary];
109 numberFormatter = [[NSNumberFormatter alloc] init];
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.
123 // Fall back to NSData
124 // WARNING: Doesn't work if it contains '\0'
125 optVal = [NSData dataWithBytes:optarg length:strlen(optarg)];
127 // Use NSNumber if the argument is a number
128 NSNumber *number = [numberFormatter numberFromString:optVal];
137 // Handle multiple option instances
138 id existingValue = options[optKey];
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];
148 optVal = @[existingValue, optVal];
152 options[optKey] = optVal;
163 cpu_routine(CPUUsageInfoInner *usage)
165 host_name_port_t host;
166 host_cpu_load_info_data_t host_load;
167 mach_msg_type_number_t count;
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);
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;
188 cpuStart(CPUUsageInfo *cpu)
190 cpu_routine(&cpu->startCPU);
194 cpuEnd(CPUUsageInfo *cpu)
196 cpu_routine(&cpu->endCPU);
200 createUsageStringForCPU(CPUUsageInfo *cpu)
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;
210 return [NSString stringWithFormat:@"%1.02f%% user %1.02f%% sys %1.02f%% idle", u, s, i];
214 timer_routine(struct timespec *ts)
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();
227 if (0 == orwl_timebase_denom) {
228 orwl_timebase_denom = 1;
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));
236 timerStart(timerInfo *timer)
238 timer_routine(&timer->startTime);
242 timerEnd(timerInfo *timer)
244 timer_routine(&timer->endTime);
248 createUsageStringForTimer(timerInfo *timer)
251 int64_t nsecs = timer->endTime.tv_nsec - timer->startTime.tv_nsec;
252 uint64_t secs = timer->endTime.tv_sec - timer->startTime.tv_sec;
254 nsecs += NSEC_PER_SEC;
258 elapsed = (double)secs + (double)nsecs / NSEC_PER_SEC;
259 return [NSString stringWithFormat:@"%f", elapsed];