1/* 2 * Copyright (c) 2006 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <unistd.h> 30#include <stdlib.h> 31#include <stdio.h> 32#include <stdbool.h> 33#include <errno.h> 34#include <string.h> 35 36// add additional headers needed here. 37 38#include "../libmicro.h" 39#include <pwd.h> 40 41#if DEBUG 42# define debug(fmt, args...) (void) fprintf(stderr, fmt "\n" , ##args) 43#else 44# define debug(fmt, args...) 45#endif 46 47 48// Correct use case 49// 50// getpwuid -E -L -S -W -B 200 -C 10 -c 100 -u 5000-5200 51// 52// libMicro default benchmark run options are "-E -L -S -W -C 200" 53// 54// -B is batch size: loop iteration per each benchmark run. Needs to match # of 55// real lookups. This is total number of lookups to issue. 56// -C is min sample number: how many benchmark needs to run to get proper sample 57// 1 is mimumum, but you get at least 3 benchmark run 58// samples. Do not set to zero. Default is 200 for most 59// runs in libMicro. 60// -c is the cache hit rate for lookup. set to 10%, you need -c 10. 61// ie. -B 100 -c 50 -u 5000-5199 62// out of 200 UIDs, I want 50% cache hit, and batch size is 100. 63// -u uid range in the form of "min-max". For example, -u 5000-5200 64// 65 66extern int gL1CacheEnabled; 67 68/* 69 * Your state variables should live in the tsd_t struct below 70 */ 71typedef struct { 72} tsd_t; 73 74// temporary buffer size 75#define BUFSIZE 200 76#define INVALID_ID -1 77 78static uid_t uid_min = INVALID_ID; 79static int uid_range = 0; // uid_max = uid_min + uid_range 80 81// the number of record lookup to issue is covered by standard option optB 82static int optCachehit = 100; // specify cache hit rate (% of record re-lookup) 83 84int 85benchmark_init() 86{ 87 debug("benchmark_init"); 88 (void) sprintf(lm_optstr, "l:c:u:"); 89 90 lm_tsdsize = sizeof (tsd_t); 91 lm_defB = 100; 92 93 (void) sprintf(lm_usage, 94 "\n ------- getpwuid specific options (default: *)\n" 95 " [-c hitrate%% (100%%*)]\n" 96 " [-u UID range (min-max)]\n" 97 " [-l]\n" 98 "\n" ); 99 return (0); 100} 101 102int 103parse_range(uid_t *min, int *offset, char *buf) 104{ 105 char *value, *tmp_ptr = strdup(buf); 106 int range=0; 107 debug("parse_range"); 108 109 value = strsep(&tmp_ptr, "-"); 110 *min = atoi(value); 111 debug("min = %d", *min); 112 if (tmp_ptr) { 113 value = strsep(&tmp_ptr, "-"); 114 range = atoi(value); 115 if (range < *min) { 116 printf("max id should be larger than min id\n"); 117 return -1; 118 } 119 *offset = range - *min + 1; 120 debug("range = %d", *offset); 121 } 122 else { 123 printf("argument should be in the form of min-max\n"); 124 return -1; 125 } 126 127 return 0; 128} 129 130/* 131 * This is where you parse your lower-case arguments. 132 */ 133int 134benchmark_optswitch(int opt, char *optarg) 135{ 136 debug("benchmark_optswitch"); 137 138 switch (opt) { 139 case 'c': // cache hit rate. 100% means lookup the same records over and over 140 optCachehit = atoi(optarg); 141 debug("optCachehit = %d\n", optCachehit); 142 if (optCachehit > 100 || optCachehit < 0) { 143 printf("cache hit rate should be in between 0%% and 100%%"); 144 return (-1); 145 } 146 break; 147 148 case 'l': 149 gL1CacheEnabled = atoi(optarg); 150 break; 151 152 case 'u': // UID range 153 return parse_range( &uid_min, &uid_range, optarg); 154 break; 155 156 default: 157 return -1; 158 } 159 160 return 0; 161} 162 163 164// Initialize all structures that will be used in benchmark() 165// moved template init from benchmark_initworker -> benchmark_initrun 166// since username_list is static across threads and processes 167// 168int 169benchmark_initrun() 170{ 171 uid_t i, range; 172 struct passwd *passwd = NULL; 173 174 debug("\nbenchmark_initrun"); 175 176 // To satisfy cache hit rate, lookup cachehit percentage of the UIDs here 177 if (optCachehit < 100) { 178 179 range = (int) ((float) uid_range * ((float) optCachehit / 100)); 180 for (i = uid_min; i < uid_min+range; i++) 181 passwd = getpwuid( i ); 182 } 183 184 return (0); 185} 186 187 188int 189benchmark(void *tsd, result_t *res) 190{ 191 int i, err; 192 struct passwd *passwd = NULL; 193 194 res->re_errors = 0; 195 196 debug("in to benchmark - optB = %i", lm_optB); 197 for (i = 0; i < lm_optB; i++) { 198 uid_t uid = uid_min + random() % uid_range ; 199 200 // XXX No need to use getpwuid_r() since getpwuid() is already thread-safe 201 // so it depends on what you want to exercise 202 if (lm_optT > 1) { 203 struct passwd pd; 204 struct passwd *pwd_ptr = &pd; 205 struct passwd *tmp_ptr; 206 char pbuf[BUFSIZE]; 207 208 err = getpwuid_r( uid, pwd_ptr, pbuf, BUFSIZE, &tmp_ptr ); 209 if (err) { 210 debug("error: %s", strerror(err)); 211 res->re_errors++; 212 } 213 else if (!tmp_ptr) { 214 debug("not found: UID %d", uid); 215 res->re_errors++; 216 } 217 } 218 else { 219 errno = 0; 220 passwd = getpwuid( uid ); 221 222 if (!passwd) { 223 if (errno) { 224 debug("error: %s", strerror(errno)); 225 res->re_errors++; 226 } 227 else { 228 debug("not found: UID %d", uid); 229 res->re_errors++; 230 } 231 } 232 } 233 } 234 res->re_count = i; 235 236 return (0); 237} 238 239// We need to release all the structures we allocated in benchmark_initrun() 240int 241benchmark_finirun(void *tsd) 242{ 243 // tsd_t *ts = (tsd_t *)tsd; 244 debug("benchmark_finirun "); 245 246 return (0); 247} 248 249char * 250benchmark_result() 251{ 252 static char result = '\0'; 253 debug("benchmark_result"); 254 return (&result); 255} 256 257