1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20/* 21 auto_perf.c 22 Performance utilities. 23 Copyright (c) 2010-2011 Apple Inc. All rights reserved. 24 */ 25 26#include <stdio.h> 27#include "auto_zone.h" 28#include <mach/mach_time.h> 29#include <mach/clock_types.h> 30#include <time.h> 31 32auto_zone_t *azone; 33mach_timebase_info_data_t timebase; 34 35uint64_t duration(uint64_t start, uint64_t end) { 36 return (end - start) * timebase.numer / timebase.denom; 37} 38 39char *duration_description(uint64_t time, char *buf, int bufsz) { 40 static char *suffixes[] = { "ns", "us", "ms", "s"}; 41 int divisor = 1; 42 int suffix = 0; 43 44 while (time/divisor > 1000 && suffix < sizeof(suffixes)/sizeof(void *)) { 45 divisor *= 1000; 46 suffix++; 47 } 48 49 snprintf(buf, bufsz, "%3.3g %s", (float)time/divisor, suffixes[suffix]); 50 return buf; 51} 52 53void test_duration_description() { 54 char buf[32]; 55 int d=1; 56 uint64_t start, end; 57 struct timespec sleep_time; 58 59 for (int i=0; i<10; i++) { 60 sleep_time.tv_sec = d/NSEC_PER_SEC; 61 sleep_time.tv_nsec = d % NSEC_PER_SEC; 62 start = mach_absolute_time(); 63 nanosleep(&sleep_time, NULL); 64 end = mach_absolute_time(); 65 printf("sleep of %d ns ==> %s\n", d, duration_description(duration(start, end), buf, sizeof(buf))); 66 d *= 10; 67 } 68} 69 70void initialize() { 71 azone = auto_zone_create("perf test zone"); 72 mach_timebase_info(&timebase); 73} 74 75// executes test many times and returns the speed in iterations per second 76void measure(uint64_t *reps, uint64_t *time, void (^test)()) { 77 const uint64_t MIN_MEASURE_TIME = ((uint64_t)NSEC_PER_SEC); 78 uint64_t start, end; 79 uint64_t repetitions = 1, d, new_reps; 80 81 do { 82 start = mach_absolute_time(); 83 for (uint64_t i=0; i<repetitions; i++) { 84 test(); 85 } 86 end = mach_absolute_time(); 87 d = duration(start, end); 88 if (d < MIN_MEASURE_TIME) { 89 if (d < MIN_MEASURE_TIME/1000) { 90 new_reps = repetitions * 10; 91 } else { 92 new_reps = (MIN_MEASURE_TIME+MIN_MEASURE_TIME/100) * repetitions / d; 93 } 94 //printf("d = %llu, reps = %llu, new_reps = %llu\n", d, repetitions, new_reps); 95 repetitions = new_reps; 96 } 97 } while (d < MIN_MEASURE_TIME); 98 *reps = repetitions; 99 *time = d; 100} 101 102void log_result(char *name, uint64_t repetitions, uint64_t time) { 103 char buf[32]; 104 printf("%s: %ld repetitions in %s = %ld per second\n", name, (long)repetitions, duration_description(time, buf, sizeof(buf)), (long)(repetitions * NSEC_PER_SEC / time)); 105} 106 107void measure_auto_zone_set_write_barrier() { 108 void *object1 = auto_zone_allocate_object(azone, sizeof(void *), AUTO_MEMORY_SCANNED, 0, 0); 109 void *object2 = auto_zone_allocate_object(azone, sizeof(void *), AUTO_MEMORY_SCANNED, 0, 0); 110 uint64_t reps, time; 111 measure(&reps, &time, ^{ 112 auto_zone_set_write_barrier(azone, object1, object2); 113 }); 114 log_result("auto_zone_set_write_barrier", reps, time); 115} 116 117void measure_subzone_refcounting() { 118 void *o = auto_zone_allocate_object(azone, sizeof(void *), AUTO_MEMORY_SCANNED, 0, 0); 119 uint64_t reps, time; 120 121 measure(&reps, &time, ^{ 122 auto_zone_retain(azone, o); 123 }); 124 log_result("auto_zone_retain(subzone)", reps, time); 125 126 // retain a lot so we can do the release test without underflow 127 for (int i=0; i<reps; i++) 128 auto_zone_retain(azone, 0); 129 130 measure(&reps, &time, ^{ 131 auto_zone_retain_count(azone, o); 132 }); 133 log_result("auto_zone_retain_count(subzone)", reps, time); 134 135 measure(&reps, &time, ^{ 136 auto_zone_release(azone, o); 137 }); 138 log_result("auto_zone_release(subzone)", reps, time); 139} 140 141int main(int argc, char *argv[]) 142{ 143 initialize(); 144 145 //test_duration_description(); 146 measure_auto_zone_set_write_barrier(); 147 measure_subzone_refcounting(); 148 149 return 0; 150}