/* * Copyright (c) 2006 Apple Inc. All Rights Reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include // add additional headers needed here. #include "../libmicro.h" #include #include #include #if DEBUG # define debug(fmt, args...) (void) fprintf(stderr, fmt "\n" , ##args) #else # define debug(fmt, args...) #endif // Correct use case // // getpwnam -E -L -S -W -B 200 -C 10 -c 100 -r 300 -U test_user_ // // libMicro default benchmark run options are "-E -L -S -W -C 200" // // -B is batch size: loop iteration per each benchmark run. Needs to match # of // real lookups. This is total number of lookups to issue. // -C is min sample number: how many benchmark needs to run to get proper sample // 1 is mimumum, but you get at least 3 benchmark run // samples. Do not set to zero. Default is 200 for most // runs in libMicro. // -r is the number of total users // -c is the cache hit rate for lookup. set to 10%, you need -c 10. // ie. -B 100 -c 50 -r 1000 -C 200 (out of 1000 records, I want 50% // lookup, and batch size is 100. // To get 50% cache hit rate, you need 500 record lookups. // Batch size will be adjusted to 500 to get 500 record // lookup in each benchmark. If -r size is smaller than -B, // then -B will not be adjusted. // -u prefix: the user name prefix to use in front the user number as the // login name to lookup extern int gL1CacheEnabled; /* * Your state variables should live in the tsd_t struct below */ typedef struct { } tsd_t; // temporary buffer size #define BUFSIZE 200 // the number of record lookup to issue is covered by standard option optB static int optRecords = 100; // the number of total records static int optCachehit = 100; // specify cache hit rate (% of record re-lookup) // This will use local users (local_test_*) static char *default_uprefix = "local_test_"; #define USERNAME_LEN 20 static char *username_list; int benchmark_init() { debug("benchmark_init"); (void) sprintf(lm_optstr, "l:c:r:u:"); lm_tsdsize = sizeof (tsd_t); lm_defB = 100; (void) sprintf(lm_usage, "\n ------- getpwnam specific options (default: *)\n" " [-c hitrate%% (100%%*)]\n" " [-r total number of records (100*)]\n" " [-u username_prefix (local_test_)]\n" "\n" ); return (0); } /* * This is where you parse your lower-case arguments. */ int benchmark_optswitch(int opt, char *optarg) { debug("benchmark_optswitch"); switch (opt) { case 'c': // cache hit rate. 100% means lookup the same records over and over optCachehit = atoi(optarg); debug("optCachehit = %d\n", optCachehit); if (optCachehit > 100 || optCachehit < 0) { printf("cache hit rate should be in between 0%% and 100%%"); return (-1); } break; case 'l': gL1CacheEnabled = atoi(optarg); break; case 'r': // total number of records. default is 100 optRecords = atoi(optarg); debug("optRecords = %d\n", optRecords); break; case 'u': default_uprefix = strdup(optarg); debug("default_uprefix = %s\n", default_uprefix); break; default: return -1; } return 0; } // Initialize all structures that will be used in benchmark() // moved template init from benchmark_initworker -> benchmark_initrun // since username_list is static across threads and processes // int benchmark_initrun() { int i; debug("\nbenchmark_initrun"); // Adjust # of record lookups to reflect cache hit rate if (optCachehit < 100) { optRecords = (int) ((float) optRecords * ((float) optCachehit / 100)); debug("# of records adjusted to %d for cache hit rate %d%%\n", optRecords, optCachehit); } // if batch size (one benchmark run) is less than the number records, adjust // it to match the number record lookups in one batch run if (lm_optB < optRecords) { lm_optB = optRecords; debug("Adjusting batch size to %d to match the lookups required in benchmark run\n", lm_optB); } // create an array of usernames to use in benchmark before their use // realtime generation in benchmark effects performance measurements username_list = malloc( optRecords * USERNAME_LEN ); if (!username_list) { debug ("malloc error"); exit (1); } for (i = 0; i < optRecords; i++) { sprintf(&username_list[i*USERNAME_LEN], "%s%d", default_uprefix, i+1); // debug("creating username %s", &username_list[i*USERNAME_LEN]); } return (0); } int benchmark(void *tsd, result_t *res) { int i, err; struct passwd *passwd = NULL; res->re_errors = 0; debug("in to benchmark - optB = %i", lm_optB); for (i = 0; i < lm_optB; i++) { int index = (random() % optRecords) * USERNAME_LEN; if (lm_optT > 1) { struct passwd pd; struct passwd *pwd_ptr = &pd; struct passwd *tmp_ptr; char pbuf[BUFSIZE]; err = getpwnam_r( &username_list[index], pwd_ptr, pbuf, BUFSIZE, &tmp_ptr); if (err) { printf("error: %s -> %s", &username_list[index], strerror(err)); res->re_errors++; } else if (!tmp_ptr) { debug("not found: %s", &username_list[index]); res->re_errors++; } } else { errno = 0; passwd = getpwnam( &username_list[index] ); if (!passwd) { if (errno) { debug("error: %s -> %s", &username_list[index], strerror(errno)); res->re_errors++; } else { debug("not found: %s", &username_list[index]); res->re_errors++; } } } } res->re_count = i; return (0); } // We need to release all the structures we allocated in benchmark_initrun() int benchmark_finirun(void *tsd) { // tsd_t *ts = (tsd_t *)tsd; debug("benchmark_finirun: deallocating structures"); free (username_list); return (0); } char * benchmark_result() { static char result = '\0'; debug("benchmark_result"); return (&result); }