text: /*
   * lat_pagefault.c - time a page fault in
   *
   * Usage: lat_pagefault [-C] [-P <parallel>] [-W <warmup>] [-N <repetitions>] 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 <parallel>] [-W <warmup>] [-N <repetitions>] 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);
  }
  
  