/* * lat_pagefault.c - time a page fault in * * Usage: lat_pagefault [-C] [-P ] [-W ] [-N ] file * * Copyright (c) 2000 Carl Staelin. * 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 CHK(x) if ((x) == -1) { perror("x"); exit(1); } typedef struct _state { int fd; int size; int npages; int clone; char* file; char* where; size_t* pages; } state_t; void initialize(iter_t iterations, void *cookie); void cleanup(iter_t iterations, void *cookie); void benchmark(iter_t iterations, void * cookie); void benchmark_mmap(iter_t iterations, void * cookie); int main(int ac, char **av) { int parallel = 1; int warmup = 0; int repetitions = -1; int c; double t_mmap; double t_combined; struct stat st; struct _state state; char buf[2048]; char* usage = "[-C] [-P ] [-W ] [-N ] file\n"; state.clone = 0; while (( c = getopt(ac, av, "P: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 'C': state.clone = 1; break; default: lmbench_usage(ac, av, usage); break; } } if (optind != ac - 1 ) { lmbench_usage(ac, av, usage); } state.file = av[optind]; CHK(stat(state.file, &st)); state.npages = st.st_size / (size_t)getpagesize(); #ifdef MS_INVALIDATE benchmp(initialize, benchmark_mmap, cleanup, 0, parallel, warmup, repetitions, &state); t_mmap = gettime() / (double)get_n(); benchmp(initialize, benchmark, cleanup, 0, parallel, warmup, repetitions, &state); t_combined = gettime() / (double)get_n(); settime(get_n() * (t_combined - t_mmap)); sprintf(buf, "Pagefaults on %s", state.file); micro(buf, state.npages * get_n()); #endif return(0); } void initialize(iter_t iterations, void* cookie) { int pagesize; struct stat sbuf; 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->file) + strlen(buf) + 1); if (!s) { perror("malloc"); exit(1); } sprintf(s, "%s%d", state->file, (int)getpid()); if (cp(state->file, s, S_IREAD|S_IWRITE) < 0) { perror("Could not copy file"); unlink(s); exit(1); } state->file = s; } CHK(state->fd = open(state->file, 0)); if (state->clone) unlink(state->file); CHK(fstat(state->fd, &sbuf)); srand(getpid()); pagesize = getpagesize(); state->size = sbuf.st_size; state->size -= state->size % pagesize; state->npages = state->size / pagesize; state->pages = permutation(state->npages, pagesize); if (state->size < 1024*1024) { fprintf(stderr, "lat_pagefault: %s too small\n", state->file); exit(1); } state->where = mmap(0, state->size, PROT_READ, MAP_SHARED, state->fd, 0); #ifdef MS_INVALIDATE if (msync(state->where, state->size, MS_INVALIDATE) != 0) { perror("msync"); exit(1); } #endif } void cleanup(iter_t iterations, void* cookie) { state_t *state = (state_t *) cookie; if (iterations) return; munmap(state->where, state->size); if (state->fd >= 0) close(state->fd); free(state->pages); } void benchmark(iter_t iterations, void* cookie) { int i; int sum = 0; state_t *state = (state_t *) cookie; while (iterations-- > 0) { for (i = 0; i < state->npages; ++i) { sum += *(state->where + state->pages[i]); } munmap(state->where, state->size); state->where = mmap(0, state->size, PROT_READ, MAP_SHARED, state->fd, 0); #ifdef MS_INVALIDATE if (msync(state->where, state->size, MS_INVALIDATE) != 0) { perror("msync"); exit(1); } #endif } use_int(sum); } void benchmark_mmap(iter_t iterations, void* cookie) { int sum = 0; state_t *state = (state_t *) cookie; while (iterations-- > 0) { munmap(state->where, state->size); state->where = mmap(0, state->size, PROT_READ, MAP_SHARED, state->fd, 0); #ifdef MS_INVALIDATE if (msync(state->where, state->size, MS_INVALIDATE) != 0) { perror("msync"); exit(1); } #endif } use_int(sum); }