1// 2// PITest.m 3// PerfIndex 4// 5// Created by Mark Hamilton on 8/21/13. 6// 7// 8 9#import "PITest.h" 10#include <dlfcn.h> 11#include <pthread.h> 12 13@implementation PITest 14 15+ (id)testWithOptions:(NSDictionary *)options 16{ 17 PITest *instance = nil; 18 if(instance == nil) 19 instance = [[PITest alloc] init]; 20 [instance setTestName:[options objectForKey:@"name"]]; 21 return instance; 22} 23 24- (BOOL)loadPITestAtPath:(NSString*) path 25{ 26 void* handle; 27 void* f; 28 29 handle = dlopen([path UTF8String], RTLD_NOW | RTLD_LOCAL); 30 if(!handle) { 31 return NO; 32 } 33 34 35 f = dlsym(handle, "setup"); 36 self->setup_func = (int (*)(int, long long, int, void **))f; 37 38 f = dlsym(handle, "execute"); 39 self->execute_func = (int (*)(int, int, long long, int, void **))f; 40 if(!self->execute_func) 41 return NO; 42 43 f = dlsym(handle, "cleanup"); 44 self->cleanup_func = (void (*)(int, long long))f; 45 return YES; 46} 47 48- (long long)lengthForTest:(NSString*) testName 49{ 50 NSNumber* number; 51 long long myLength; 52 NSDictionary* lengths = [NSDictionary dictionaryWithObjectsAndKeys: 53 @"cpu", [NSNumber numberWithLongLong:2000], 54 @"syscall", [NSNumber numberWithLongLong:2500], 55 @"memory", [NSNumber numberWithLongLong:1000000], 56 @"fault", [NSNumber numberWithLongLong:500], 57 @"zfod", [NSNumber numberWithLongLong:500], 58 @"file_create", [NSNumber numberWithLongLong:10], 59 @"file_read", [NSNumber numberWithLongLong:1000000], 60 @"file_write", [NSNumber numberWithLongLong:1000000], 61 nil]; 62 63 number = (NSNumber*)[lengths objectForKey:testName]; 64 if(!number) { 65 myLength = 10; 66 } else { 67 myLength = [number longLongValue]; 68 } 69 70 return myLength; 71} 72 73- (BOOL)setup 74{ 75 BOOL success = NO; 76 int retval; 77 78 NSString* testPath = [NSString stringWithFormat:@"/AppleInternal/CoreOS/perf_index/%@.dylib", [self testName]]; 79 success = [self loadPITestAtPath:testPath]; 80 if(!success) { 81 NSLog(@"Failed to load test %@", [self testName]); 82 return NO; 83 } 84 85 self->length = [self lengthForTest:[self testName]]; 86 self->numThreads = 1; 87 self->testArgc = 0; 88 self->testArgv = NULL; 89 90 pthread_cond_init(&self->threadsReadyCvar, NULL); 91 pthread_cond_init(&self->startCvar, NULL); 92 pthread_mutex_init(&self->readyThreadCountLock, NULL); 93 self->readyThreadCount = 0; 94 95 if(self->setup_func) { 96 retval = self->setup_func(1, self->length, 0, NULL); 97 if(retval != 0) { 98 NSLog(@"setup_func failed"); 99 return NO; 100 } 101 } 102 103 self->threads = (pthread_t*)malloc(sizeof(pthread_t)*self->numThreads); 104 105 for(int thread_index = 0; thread_index < self->numThreads; thread_index++) { 106 NSNumber* my_thread_index = [NSNumber numberWithInt:thread_index]; 107 NSArray *arg = [NSArray arrayWithObjects:my_thread_index, self, nil]; 108 retval = pthread_create(&threads[thread_index], NULL, thread_setup, (__bridge void*)arg); 109 if(retval != 0) { 110 NSLog(@"pthread_create failed"); 111 free(self->threads); 112 return NO; 113 } 114 } 115 116 pthread_mutex_lock(&self->readyThreadCountLock); 117 if(self->readyThreadCount != self->numThreads) { 118 pthread_cond_wait(&self->threadsReadyCvar, &self->readyThreadCountLock); 119 } 120 pthread_mutex_unlock(&self->readyThreadCountLock); 121 return YES; 122} 123 124- (BOOL)execute 125{ 126 pthread_cond_broadcast(&self->startCvar); 127 for(int thread_index = 0; thread_index < self->numThreads; thread_index++) { 128 pthread_join(self->threads[thread_index], NULL); 129 } 130 return YES; 131} 132 133- (void)cleanup 134{ 135 free(self->threads); 136 if(self->cleanup_func) 137 self->cleanup_func(0, self->length); 138} 139 140void* thread_setup(void* arg) 141{ 142 int my_index = (int)[(NSNumber*)[(__bridge NSArray*)arg objectAtIndex:0] integerValue]; 143 PITest* test = (PITest*)[(__bridge NSArray*)arg objectAtIndex:1]; 144 145 long long work_size = test->length / test->numThreads; 146 int work_remainder = test->length % test->numThreads; 147 148 if(work_remainder > my_index) { 149 work_size++; 150 } 151 152 pthread_mutex_lock(&test->readyThreadCountLock); 153 test->readyThreadCount++; 154 155 if(test->readyThreadCount == test->numThreads) 156 pthread_cond_signal(&test->threadsReadyCvar); 157 pthread_cond_wait(&test->startCvar, &test->readyThreadCountLock); 158 pthread_mutex_unlock(&test->readyThreadCountLock); 159 test->execute_func(my_index, test->numThreads, work_size, test->testArgc, test->testArgv); 160 161 return NULL; 162} 163 164@end 165