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#include <netdb.h>
36
37// add additional headers needed here.
38
39#include "../libmicro.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//
49// Correct use case
50//
51//    getaddrinfo_host -E  -L -S -W -B 200 -C 100 -s "server%d"
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// -h is hostname format: for example, "server-%d.performance.rack"
62//                        this is C language string format that can include %d
63// -r hostname digit range in the form of "min-max". For example, -r 100-112
64//    With -h and -r, resulting hostnames are
65//      server-100.performance.rack - server-112.performance.rack
66//
67
68extern int gL1CacheEnabled;
69
70/*
71 *    Your state variables should live in the tsd_t struct below
72 */
73typedef struct {
74} tsd_t;
75
76#define HOSTNAME_LEN    125
77static int host_min=-1, host_range=0;
78static char *hostname_format=NULL;
79static char *hostname_list=NULL;
80
81int
82benchmark_init()
83{
84    debug("benchmark_init");
85    (void) sprintf(lm_optstr,  "l:h:r:");
86
87    lm_tsdsize = sizeof (tsd_t);
88    lm_defB = 100;
89
90    (void) sprintf(lm_usage,
91                "\n       ------- getaddrinfo_host specific options (default: *)\n"
92                "       [-h \"hostname format\"]. ie. \"server-%%d.perf\"\n"
93                "       [-r min-max]\n"
94                "\n" );
95
96    return (0);
97}
98
99
100int
101parse_range(int *min, int *offset, char *buf)
102{
103    char *value, *tmp_ptr = strdup(buf);
104    int range=0;
105    debug("parse_range");
106
107    value = strsep(&tmp_ptr, "-");
108    *min = atoi(value);
109    debug("min = %d", *min);
110    if (tmp_ptr) {
111        value = strsep(&tmp_ptr, "-");
112        range = atoi(value);
113        if (range < *min) {
114            printf("max id should be larger than min id\n");
115            return -1;
116        }
117        *offset = range - *min + 1; // 1-based
118        debug("range = %d", *offset);
119    }
120    else {
121        printf("argument should be in the form of min-max\n");
122        return -1;
123    }
124
125    return 0;
126
127}
128
129/*
130 * This is where you parse your lower-case arguments.
131 */
132int
133benchmark_optswitch(int opt, char *optarg)
134{
135    debug("benchmark_optswitch");
136
137    switch (opt) {
138    case 'h':   // hostname string format
139        hostname_format = strdup(optarg);
140        debug ("hostname format: %s", hostname_format);
141        break;
142
143	case 'l':
144		gL1CacheEnabled = atoi(optarg);
145		break;
146
147    case 'r':    // UID range
148        return parse_range( &host_min, &host_range, optarg);
149        break;
150
151    default:
152        return -1;
153    }
154
155
156
157    return 0;
158}
159
160
161// Initialize all structures that will be used in benchmark()
162//
163int
164benchmark_initrun()
165{
166    int i;
167
168    debug("\nbenchmark_initrun");
169
170    if (host_min == -1) {
171        printf("-r min-max needs to be specified\n");
172        exit (1);
173    }
174
175    if (!hostname_format) {
176        printf("-h hostname_format needs to be specified\n");
177        exit (1);
178    }
179
180    hostname_list = malloc ( host_range * HOSTNAME_LEN );
181    if (!hostname_list) {
182        debug("malloc error");
183        exit (1);
184    }
185
186    for (i = 0; i < host_range; i++) {
187        sprintf( &hostname_list[i*HOSTNAME_LEN], hostname_format, i+host_min);
188        // debug("hostname: %s", &hostname_list[i*HOSTNAME_LEN]);
189    }
190    return (0);
191}
192
193
194int
195benchmark(void *tsd, result_t *res)
196{
197    int         i, index, err;
198    struct addrinfo *addi;
199
200    res->re_errors = 0;
201
202    debug("in to benchmark - optB = %i", lm_optB);
203    srandom(getpid());
204
205    for (i = 0; i < lm_optB; i++) {
206        index = HOSTNAME_LEN * (random() % host_range);
207
208        err = getaddrinfo( &hostname_list[index], NULL, NULL, &addi);
209
210        if (err) {
211            debug("%s: error: %s", &hostname_list[index], gai_strerror(err));
212            res->re_errors++;
213        }
214        else {
215            debug("host %s done", &hostname_list[index]);
216        }
217
218        freeaddrinfo (addi);
219    }
220    res->re_count = i;
221
222    return (0);
223}
224
225// We need to release all the structures we allocated in benchmark_initrun()
226int
227benchmark_finirun(void *tsd)
228{
229    // tsd_t    *ts = (tsd_t *)tsd;
230    debug("benchmark_finirun ");
231
232    free(hostname_list);
233
234    return (0);
235}
236
237char *
238benchmark_result()
239{
240    static char    result = '\0';
241    debug("benchmark_result");
242    return (&result);
243}
244
245