]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/libMicro/apple/getpwuid.c
c3314912582dc5455511ed0dbbbe825b90ca26fd
[apple/xnu.git] / tools / tests / libMicro / apple / getpwuid.c
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
66 extern int gL1CacheEnabled;
67
68 /*
69 * Your state variables should live in the tsd_t struct below
70 */
71 typedef struct {
72 } tsd_t;
73
74 // temporary buffer size
75 #define BUFSIZE 200
76 #define INVALID_ID -1
77
78 static uid_t uid_min = INVALID_ID;
79 static 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
82 static int optCachehit = 100; // specify cache hit rate (% of record re-lookup)
83
84 int
85 benchmark_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
102 int
103 parse_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 */
133 int
134 benchmark_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 //
168 int
169 benchmark_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
188 int
189 benchmark(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()
240 int
241 benchmark_finirun(void *tsd)
242 {
243 // tsd_t *ts = (tsd_t *)tsd;
244 debug("benchmark_finirun ");
245
246 return (0);
247 }
248
249 char *
250 benchmark_result()
251 {
252 static char result = '\0';
253 debug("benchmark_result");
254 return (&result);
255 }
256