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 <membership.h>
40#include <grp.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//    getgrgid -E  -L -S -W -B 200 -C 10 -g 1211-1213
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// -g gid range in the form of "min-max". For example, -g 1211-1213
62//
63
64extern int gL1CacheEnabled;
65
66/*
67 *    Your state variables should live in the tsd_t struct below
68 */
69typedef struct {
70} tsd_t;
71
72// temporary buffer size
73#define BUFSIZE 200
74#define INVALID_ID  -1
75
76static gid_t  gid_min = INVALID_ID;
77static int    gid_range = 0;  // gid_max = gid_min + gid_range
78
79int
80benchmark_init()
81{
82    debug("benchmark_init");
83    (void) sprintf(lm_optstr,  "l:g:");
84
85    lm_tsdsize = sizeof (tsd_t);
86    lm_defB = 100;
87
88    (void) sprintf(lm_usage,
89                "\n     ------- getgrgid specific options (default: *)\n"
90                "       [-g GID range (min-max)]\n"
91                "\n" );
92    return (0);
93}
94
95
96int
97parse_range(gid_t *min, int *offset, char *buf)
98{
99    char *value, *tmp_ptr = strdup(buf);
100    int range=0;
101    debug("parse_range");
102
103    value = strsep(&tmp_ptr, "-");
104    *min = atoi(value);
105    debug("min = %d", *min);
106    if (tmp_ptr) {
107        value = strsep(&tmp_ptr, "-");
108        range = atoi(value);
109        if (range < *min) {
110            printf("max id should be larger than min id\n");
111            return -1;
112        }
113        *offset = range - *min + 1;
114        debug("range = %d", *offset);
115    }
116    else {
117        printf("argument should be in the form of min-max\n");
118        return -1;
119    }
120
121    return 0;
122
123}
124
125/*
126 * This is where you parse your lower-case arguments.
127 */
128int
129benchmark_optswitch(int opt, char *optarg)
130{
131    debug("benchmark_optswitch");
132
133    switch (opt) {
134    case 'l':
135        gL1CacheEnabled = atoi(optarg);
136        break;
137
138    case 'g':    // GID range
139        return parse_range( &gid_min, &gid_range, optarg);
140        break;
141
142    default:
143        return -1;
144    }
145
146    return 0;
147}
148
149
150// Initialize all structures that will be used in benchmark()
151// moved template init from benchmark_initworker -> benchmark_initrun
152//
153int
154benchmark_initrun()
155{
156    debug("\nbenchmark_initrun");
157
158    return (0);
159}
160
161
162int
163benchmark(void *tsd, result_t *res)
164{
165    int         i, err;
166    struct group *grp = NULL;
167
168    res->re_errors = 0;
169
170    debug("in to benchmark - optB = %i", lm_optB);
171    for (i = 0; i < lm_optB; i++) {
172        gid_t gid = gid_min + random() % gid_range ;
173
174        if (lm_optT > 1) {
175            struct group gd;
176            struct group *grp_ptr = &gd;
177            struct group *tmp_ptr;
178            char gbuf[BUFSIZE];
179
180            err = getgrgid_r( gid, grp_ptr, gbuf, BUFSIZE, &tmp_ptr);
181            if (err) {
182                debug("error: GID %d -> %s", gid, strerror(err));
183                res->re_errors++;
184            }
185            else if (!tmp_ptr) {
186                debug("not found: GID %d", gid);
187                res->re_errors++;
188            }
189        }
190        else {
191            errno = 0;
192            grp = getgrgid( gid );
193
194            if (!grp) {
195                if (errno) {
196                    debug("error: GID %d -> %s", gid, strerror(errno));
197                    res->re_errors++;
198                }
199                else {
200                    debug("not found: GID %d", gid);
201                    res->re_errors++;
202                }
203            }
204        }
205    }
206    res->re_count = i;
207
208    return (0);
209}
210
211// We need to release all the structures we allocated in benchmark_initrun()
212int
213benchmark_finirun(void *tsd)
214{
215    // tsd_t    *ts = (tsd_t *)tsd;
216    debug("benchmark_finirun ");
217
218    return (0);
219}
220
221char *
222benchmark_result()
223{
224    static char    result = '\0';
225    debug("benchmark_result");
226    return (&result);
227}
228
229