/* * lat_mmap.c - time how fast a mapping can be made and broken down * * Usage: mmap [-r] [-C] [-P <parallelism>] [-W <warmup>] [-N <repetitions>] size file * * XXX - If an implementation did lazy address space mapping, this test * will make that system look very good. I haven't heard of such a system. * * Copyright (c) 1994 Larry McVoy. Distributed under the FSF GPL with * additional restriction that results may published only if * (1) the benchmark is unmodified, and * (2) the version in the sccsid below is included in the report. * Support for this development by Sun Microsystems is gratefully acknowledged. */ char *id = "$Id$\n"; #include "bench.h" #define PSIZE (16<<10) #define N 10 #define STRIDE (10*PSIZE) #define MINSIZE (STRIDE*2) #define CHK(x) if ((x) == -1) { perror("x"); exit(1); } typedef struct _state { size_t size; int fd; int random; int clone; char *name; } state_t; void init(iter_t iterations, void *cookie); void cleanup(iter_t iterations, void *cookie); void domapping(iter_t iterations, void * cookie); int main(int ac, char **av) { state_t state; int parallel = 1; int warmup = 0; int repetitions = -1; int c; char *usage = "[-r] [-C] [-P <parallelism>] [-W <warmup>] [-N <repetitions>] size file\n"; state.random = 0; state.clone = 0; while (( c = getopt(ac, av, "rP:W:N:C")) != EOF) { switch(c) { case 'P': parallel = atoi(optarg); if (parallel <= 0) lmbench_usage(ac, av, usage); break; case 'W': warmup = atoi(optarg); break; case 'N': repetitions = atoi(optarg); break; case 'r': state.random = 1; break; case 'C': state.clone = 1; break; default: lmbench_usage(ac, av, usage); break; } } if (optind + 2 != ac) { lmbench_usage(ac, av, usage); } state.size = bytes(av[optind]); if (state.size < MINSIZE) { return (1); } state.name = av[optind+1]; benchmp(init, domapping, cleanup, 0, parallel, warmup, repetitions, &state); if (gettime() > 0) { micromb(state.size, get_n()); } return (0); } void init(iter_t iterations, void* cookie) { state_t *state = (state_t *) cookie; if (iterations) return; if (state->clone) { char buf[128]; char* s; /* copy original file into a process-specific one */ sprintf(buf, "%d", (int)getpid()); s = (char*)malloc(strlen(state->name) + strlen(buf) + 1); if (!s) { perror("malloc"); exit(1); } sprintf(s, "%s%d", state->name, (int)getpid()); if (cp(state->name, s, S_IREAD|S_IWRITE) < 0) { perror("Could not copy file"); unlink(s); exit(1); } state->name = s; } CHK(state->fd = open(state->name, O_RDWR)); if (state->clone) unlink(state->name); if (seekto(state->fd, 0, SEEK_END) < state->size) { fprintf(stderr, "Input file too small\n"); exit(1); } } void cleanup(iter_t iterations, void* cookie) { state_t *state = (state_t *) cookie; if (iterations) return; close(state->fd); } /* * This alg due to Linus. The goal is to have both sparse and full * mappings reported. */ void domapping(iter_t iterations, void *cookie) { state_t *state = (state_t *) cookie; register int fd = state->fd; register size_t size = state->size; register int random = state->random; register char *p, *where, *end; register char c = size & 0xff; while (iterations-- > 0) { #ifdef MAP_FILE where = mmap(0, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0); #else where = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); #endif if ((long)where == -1) { perror("mmap"); exit(1); } if (random) { end = where + size; for (p = where; p < end; p += STRIDE) { *p = c; } } else { end = where + (size / N); for (p = where; p < end; p += PSIZE) { *p = c; } } munmap(where, size); } }