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