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 <grp.h>
40#include <uuid/uuid.h>
41
42#if DEBUG
43# define debug(fmt, args...)    (void) fprintf(stderr, fmt "\n" , ##args)
44#else
45# define debug(fmt, args...)
46#endif
47
48
49// Correct use case
50//
51//    getgrnam -E  -L -S -W -B 200 -C 10 -r 10
52//
53//      libMicro default benchmark run options are "-E -L -S -W -C 200"
54//
55// -B is batch size: loop iteration per each benchmark run. Needs to match # of
56//                   real lookups. This is total number of lookups to issue.
57// -C is min sample number: how many benchmark needs to run to get proper sample
58//                          1 is mimumum, but you get at least 3 benchmark run
59//                          samples. Do not set to zero. Default is 200 for most
60//                          runs in libMicro.
61// -r is the number of total groups (from "local_test_group1" to "local_test_group#")
62
63extern int gL1CacheEnabled;
64
65/*
66 *    Your state variables should live in the tsd_t struct below
67 */
68typedef struct {
69} tsd_t;
70
71// temporary buffer size
72#define BUFSIZE 200
73
74// the number of record lookup to issue is covered by standard option optB
75static int  optRecords =    10;  // the number of total records
76
77// This will use local users (local_test_*)
78static char *default_gprefix = "ds_test_group";
79
80#define GROUPNAME_LEN	30
81static char *grpname_list;
82
83int
84benchmark_init()
85{
86    debug("benchmark_init");
87    (void) sprintf(lm_optstr,  "l:r:g:");
88
89    lm_tsdsize = sizeof (tsd_t);
90    lm_defB = 100;
91
92    (void) sprintf(lm_usage,
93                "\n     ------- getgrnam specific options (default: *)\n"
94                "       [-r total number of group records (10*)]\n"
95                "       [-g group prefix(ds_test_group)]\n"
96                "\n" );
97    return (0);
98}
99
100/*
101 * This is where you parse your lower-case arguments.
102 */
103int
104benchmark_optswitch(int opt, char *optarg)
105{
106    debug("benchmark_optswitch");
107
108    switch (opt) {
109    case 'r':    // total number of records. default is 100
110        optRecords = atoi(optarg);
111        debug("optRecords = %d\n", optRecords);
112        break;
113
114    case 'l':
115        gL1CacheEnabled = atoi(optarg);
116        break;
117
118    case 'g':	// base name for the groups to use
119	default_gprefix = strdup(optarg);
120	debug("default_gprefix = %s\n", default_gprefix);
121	break;
122
123    default:
124        return -1;
125    }
126
127    return 0;
128}
129
130
131// Initialize all structures that will be used in benchmark()
132// moved template init from benchmark_initworker -> benchmark_initrun
133//  since username_list is static across threads and processes
134//
135int
136benchmark_initrun()
137{
138    int i;
139
140    debug("\nbenchmark_initrun");
141
142    // create an array of usernames to use in benchmark before their use
143    // realtime generation in benchmark effects performance measurements
144    grpname_list = malloc( optRecords * GROUPNAME_LEN );
145    if (!grpname_list) {
146        debug ("malloc error");
147        exit (1);
148    }
149
150    for (i = 0; i < optRecords; i++) {
151        sprintf(&grpname_list[i*GROUPNAME_LEN], "%s%d", default_gprefix, i+1);
152        debug("creating group name %s", &grpname_list[i*GROUPNAME_LEN]);
153    }
154
155    return (0);
156}
157
158
159int
160benchmark(void *tsd, result_t *res)
161{
162    int          i, err;
163    struct group *grp = NULL;
164
165    res->re_errors = 0;
166
167    debug("in to benchmark - optB = %i", lm_optB);
168    srandom(getpid());
169
170    for (i = 0; i < lm_optB; i++) {
171        int index = (random() % optRecords) * GROUPNAME_LEN;
172
173        if (lm_optT > 1) {
174            struct group gd;
175            struct group *grp_ptr = &gd;
176            struct group *tmp_ptr;
177            char gbuf[BUFSIZE];
178
179            err = getgrnam_r( &grpname_list[index], grp_ptr, gbuf, BUFSIZE, &tmp_ptr);
180            // non-NULL err means failure and NULL result ptr means no matching
181            // entry
182            if (err) {
183                debug("error: %s -> %s",  &grpname_list[index], strerror(err));
184                res->re_errors++;
185            }
186            else if ( !tmp_ptr) {
187                debug("not found: %s",  &grpname_list[index] );
188                res->re_errors++;
189            }
190        }
191        else {
192            errno = 0;
193            grp = getgrnam( &grpname_list[index] );
194
195            if (!grp) {
196                if (errno) {
197                    debug("error: %s -> %s", &grpname_list[index], strerror(errno));
198                    res->re_errors++;
199                }
200                else {
201                    debug("not found: %s",  &grpname_list[index] );
202                    res->re_errors++;
203                }
204            }
205        }
206    }
207    res->re_count = i;
208
209    return (0);
210}
211
212// We need to release all the structures we allocated in benchmark_initrun()
213int
214benchmark_finirun(void *tsd)
215{
216    // tsd_t    *ts = (tsd_t *)tsd;
217    debug("benchmark_finiworker: deallocating structures");
218
219    free (grpname_list);
220
221    return (0);
222}
223
224char *
225benchmark_result()
226{
227    static char    result = '\0';
228    debug("benchmark_result");
229    return (&result);
230}
231
232