#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
static double now_ms(void){struct timespec ts;clock_gettime(CLOCK_MONOTONIC,&ts);return ts.tv_sec*1000.0+ts.tv_nsec/1e6;}
int main(int argc,char**argv){
  const char*mode=argv[1]; const char*path=argv[2];
  int fd=open(path,O_RDONLY); struct stat st; fstat(fd,&st);
  size_t n=(st.st_size+16383)&~16383UL;
  double t0=now_ms();
  void*p;
  if(!strcmp(mode,"rx")) p=mmap(NULL,n,PROT_READ|PROT_EXEC,MAP_PRIVATE,fd,0);
  else if(!strcmp(mode,"rwx")) p=mmap(NULL,n,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd,0);
  else p=mmap(NULL,n,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0);
  double t1=now_ms();
  printf("mmap %s %.1f ms %p errno=%d\n",mode,t1-t0,p,errno);
  if(!strcmp(mode,"rw_mprotect_rx")){
    memcpy(p, NULL, 0);
    double t2=now_ms();
    int r=mprotect(p,n,PROT_READ|PROT_EXEC);
    double t3=now_ms();
    printf("mprotect rx %.1f ms r=%d errno=%d\n",t3-t2,r,errno);
  }
  /* fault in pages by reading */
  double t4=now_ms(); volatile unsigned char s=0; for(size_t i=0;i<n;i+=4096) s+=((unsigned char*)p)[i]; double t5=now_ms();
  printf("read fault %.1f ms sum=%d\n",t5-t4,s);
  return 0;
}
