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 30/* 31 * Order of Execution 32 * 33 * benchmark_init 34 * 35 * benchmark_optswitch 36 * 37 * benchmark_initrun 38 * 39 * benchmark_initworker 40 * benchmark_initbatch 41 * benchmark 42 * benchmark_finibatch 43 * benchmark_initbatch 44 * benchmark 45 * benchmark_finibatch, etc. 46 * benchmark_finiworker 47 * 48 * benchmark_result 49 * 50 * benchmark_finirun 51 * 52 * benchmark_fini 53 */ 54 55 56 57#ifdef __sun 58#pragma ident "@(#)lmbench_bw_mmap_rd.c 1.0 08/17/06 Apple Inc." 59#endif 60 61 62 63#include <unistd.h> 64#include <stdlib.h> 65#include <stdio.h> 66#include <stdbool.h> 67#include <string.h> 68// add additional headers needed here. 69#include <fcntl.h> 70#include <limits.h> 71#include <sys/mman.h> 72 73#include "../libmicro.h" 74 75#if DEBUG 76# define debug(fmt, args...) (void) fprintf(stderr, fmt "\n" , ##args) 77#else 78# define debug(fmt, args...) 79#endif 80 81/* 82 * Your state variables should live in the tsd_t struct below 83 */ 84typedef struct { 85 size_t nbytes; 86 char filename[_POSIX_PATH_MAX]; 87 int fd; 88 int clone; 89 void *buf; 90 bool open_read_close; 91} tsd_t; 92 93/* 94 * You can have any lower-case option you want to define. 95 * options are specified in the lm_optstr as either a 96 * single lower-case letter, or a single lower case letter 97 * with a colon after it. In this example, you can optionally 98 * specify -c {str} -e or -t {number} 99 * -c takes a string (quote the string if blanks) 100 * -e is a boolean 101 * -t takes a numeric 102 * argument. 103 */ 104static char optf[_POSIX_PATH_MAX]; 105static int opts = 1024; 106static bool opti = false; // io_only or read and i/o (default read and i/o) 107 108#ifdef MAP_FILE 109# define MMAP_FLAGS MAP_FILE|MAP_SHARED 110#else 111# define MMAP_FLAGS MAP_SHARED 112#endif 113 114#define CHK(x) if ((int)(x) == -1) { perror(#x); exit(1); } 115#ifndef MIN 116#define MIN(a, b) ((a) < (b) ? (a) : (b)) 117#endif 118 119#define TYPE int 120#define MINSZ (sizeof(TYPE) * 128) 121 122void *buf; /* do the I/O here */ 123size_t xfersize; /* do it in units of this */ 124size_t count; /* bytes to move (can't be modified) */ 125 126/* analogous to bzero, bcopy, etc., except that it just reads 127 * data into the processor 128 */ 129long 130bread(void* buf, long nbytes) 131{ 132 long sum = 0; 133 register long *p, *next; 134 register char *end; 135 136 p = (long*)buf; 137 end = (char*)buf + nbytes; 138 for (next = p + 128; (void*)next <= (void*)end; p = next, next += 128) { 139 sum += 140 p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]+ 141 p[8]+p[9]+p[10]+p[11]+p[12]+p[13]+p[14]+ 142 p[15]+p[16]+p[17]+p[18]+p[19]+p[20]+p[21]+ 143 p[22]+p[23]+p[24]+p[25]+p[26]+p[27]+p[28]+ 144 p[29]+p[30]+p[31]+p[32]+p[33]+p[34]+p[35]+ 145 p[36]+p[37]+p[38]+p[39]+p[40]+p[41]+p[42]+ 146 p[43]+p[44]+p[45]+p[46]+p[47]+p[48]+p[49]+ 147 p[50]+p[51]+p[52]+p[53]+p[54]+p[55]+p[56]+ 148 p[57]+p[58]+p[59]+p[60]+p[61]+p[62]+p[63]+ 149 p[64]+p[65]+p[66]+p[67]+p[68]+p[69]+p[70]+ 150 p[71]+p[72]+p[73]+p[74]+p[75]+p[76]+p[77]+ 151 p[78]+p[79]+p[80]+p[81]+p[82]+p[83]+p[84]+ 152 p[85]+p[86]+p[87]+p[88]+p[89]+p[90]+p[91]+ 153 p[92]+p[93]+p[94]+p[95]+p[96]+p[97]+p[98]+ 154 p[99]+p[100]+p[101]+p[102]+p[103]+p[104]+ 155 p[105]+p[106]+p[107]+p[108]+p[109]+p[110]+ 156 p[111]+p[112]+p[113]+p[114]+p[115]+p[116]+ 157 p[117]+p[118]+p[119]+p[120]+p[121]+p[122]+ 158 p[123]+p[124]+p[125]+p[126]+p[127]; 159 } 160 for (next = p + 16; (void*)next <= (void*)end; p = next, next += 16) { 161 sum += 162 p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]+ 163 p[8]+p[9]+p[10]+p[11]+p[12]+p[13]+p[14]+ 164 p[15]; 165 } 166 for (next = p + 1; (void*)next <= (void*)end; p = next, next++) { 167 sum += *p; 168 } 169 return sum; 170} 171 172int 173cp(char* src, char* dst, mode_t mode) 174{ 175 int sfd, dfd; 176 char buf[8192]; 177 ssize_t size; 178 179 if ((sfd = open(src, O_RDONLY)) < 0) { 180 return -1; 181 } 182 if ((dfd = open(dst, O_CREAT|O_TRUNC|O_RDWR, mode)) < 0) { 183 return -1; 184 } 185 while ((size = read(sfd, buf, 8192)) > 0) { 186 if (write(dfd, buf, size) < size) return -1; 187 } 188 fsync(dfd); 189 close(sfd); 190 close(dfd); 191 return 0; 192} 193 194 195int 196benchmark_init() 197{ 198 debug("benchmark_init"); 199 /* 200 * the lm_optstr must be defined here or no options for you 201 * 202 * ...and the framework will throw an error 203 * 204 */ 205 (void) sprintf(lm_optstr, "f:is:"); 206 /* 207 * tsd_t is the state info struct that we pass around 208 * 209 * lm_tsdsize will allocate the space we need for this 210 * structure throughout the rest of the framework 211 */ 212 lm_tsdsize = sizeof (tsd_t); 213 214 (void) sprintf(lm_usage, 215 " -f filename\n" 216 " -s size\n" 217 " [-i] io_only (no open/close)\n" 218 "notes: read and sum file via memory mapping mmap(2) interface"); 219 sprintf(optf, "/tmp/%d", (int)getpid()); 220 opts = 1024; 221 return (0); 222} 223 224/* 225 * This is where you parse your lower-case arguments. 226 * the format was defined in the lm_optstr assignment 227 * in benchmark_init 228 */ 229int 230benchmark_optswitch(int opt, char *optarg) 231{ 232 debug("benchmark_optswitch"); 233 234 switch (opt) { 235 case 'f': 236 strncpy(optf, optarg, 255); 237 debug("optf = %s\n", optf); 238 break; 239 case 'i': 240 opti = true; 241 debug("opti = %s\n", opti? "true": "false"); 242 break; 243 case 's': 244 opts = sizetoint(optarg); 245 debug("opts = %d\n", opts); 246 break; 247 default: 248 return (-1); 249 } 250 return (0); 251} 252 253int 254benchmark_initrun() 255{ 256 debug("benchmark_initrun"); 257 return (0); 258} 259 260int 261benchmark_initworker(void *tsd) 262{ 263 /* 264 * initialize your state variables here first 265 */ 266 tsd_t *state = (tsd_t *)tsd; 267 268 strncpy(state->filename, optf, 255); 269 state->nbytes = opts; 270 state->open_read_close = opti; 271 272 debug("benchmark_initworker\n"); 273 return (0); 274} 275 276/*ARGSUSED*/ 277int 278benchmark_initbatch(void *tsd) 279{ 280 tsd_t *state = (tsd_t *)tsd; 281 state->fd = -1; 282 state->buf = NULL; 283 284 if (state->clone) { 285 char buf[8192]; 286 char* s; 287 288 /* copy original file into a process-specific one */ 289 sprintf(buf, "/tmp/%d", (int)getpid()); 290 s = (char*)malloc(strlen(state->filename) + strlen(buf) + 1); 291 sprintf(s, "/tmp/%s%d", state->filename, (int)getpid()); 292 if (cp(state->filename, s, S_IREAD|S_IWRITE) < 0) { 293 perror("creating private tempfile"); 294 unlink(s); 295 exit(1); 296 } 297 strcpy(state->filename, s); 298 } 299 300 CHK(state->fd = open(state->filename, 0)); 301 CHK(state->buf = mmap(0, state->nbytes, PROT_READ, 302 MMAP_FLAGS, state->fd, 0)); 303 debug("benchmark_initbatch"); 304 return (0); 305} 306 307int 308benchmark(void *tsd, result_t *res) 309{ 310 /* 311 * try not to initialize things here. This is the main 312 * loop of things to get timed. Start a server in 313 * benchmark_initbatch 314 */ 315 tsd_t *state = (tsd_t *)tsd; 316 int i; 317 int fd; 318 void *p; 319 320 debug("in to benchmark - optB = %i", lm_optB); 321 for (i = 0; i < lm_optB; i++) { 322 if (state->open_read_close) { 323 CHK(fd = open(state->filename, 0)); 324 CHK(p = mmap(0, state->nbytes, PROT_READ, MMAP_FLAGS, fd, 0)); 325 bread(p, state->nbytes); 326 close(fd); 327 munmap(p, state->nbytes); 328 } else { 329 bread(state->buf, state->nbytes); 330 } 331 } 332 res->re_count = i; 333 debug("out of benchmark - optB = %i", lm_optB); 334 335 return (0); 336} 337 338int 339benchmark_finibatch(void *tsd) 340{ 341 tsd_t *state = (tsd_t *)tsd; 342 if (state->buf) munmap(state->buf, state->nbytes); 343 if (state->fd >= 0) close(state->fd); 344 if (state->clone) unlink(state->filename); 345 debug("benchmark_finibatch"); 346 return (0); 347} 348 349int 350benchmark_finiworker(void *tsd) 351{ 352 debug("benchmark_finiworker"); 353 return (0); 354} 355 356char * 357benchmark_result() 358{ 359 static char result = '\0'; 360 debug("benchmark_result"); 361 return (&result); 362} 363 364int 365benchmark_finirun() 366{ 367 debug("benchmark_finirun"); 368 return (0); 369} 370 371 372int 373benchmark_fini() 374{ 375 debug("benchmark_fini"); 376 return (0); 377} 378 379