#include #include #include #include #include #include #include /* DAPM 9 May 99 * do some benchmarks to compare mmap() and write() speeds. * Use a SIGALARM to stop the test after PERIOD seconds. * * Some approx results: * A sparcstation 4 70Mhz, 48Mb, running Solaris 2.4 * B sparcstation 4 110Mhz, 128Mb, running Solaris 2.7 * C Ultra 2 1 x 167Mhz, 768Mb, running Solaris 2.5.1 * * A B C * 64K USEMM 2.5ms 2.2-2.6ms 0.3ms * 64K USEMM UNMAP 4.2ms 3-4ms 0.6ms * 64K USEMM UNMAP DOTRUNC 13ms 13ms 2.3ms * 64K using write() 24ms 10ms 9.2ms * * Note that the ultra was an order of magnitude faster than the others * on the mmap-related stuff - not sure whether this is due to the large * amount of RAM, the faster processor, or a different MMU architecture. * * NB I checked, and Solaris 2.7 *doesnt* allow a file to grow by * accessing pages mapped belond the length of the file * * Under the terms of the Mitchell-Allison treaty, the second-best * programmer dedicates this code to the second-best system administrator. * */ #define USEMM /* if defined, use mmap() rather than write() */ #define UNMAP /* if defined, do munmap() after each memcpy() */ #define DOTRUNC /* truncate file before each memcpy() */ #define SOL_TRUNC /* use the syscall directly that solaris uses for ftruncate */ #define PERIOD 2 /* how many seconds to run the test for */ /* file to write to. NB need to do an 'mkfile 14M' before using * one the permutations that doesnt automatically grow the file */ /*#define TFILE "/tmp/tfile"*/ #define TFILE "tfile" /* block size, and number of blocks that make up the file */ #define BUFSIZE 65536 #define NBLOCKS 200 char buf[BUFSIZE]; int count; struct timeval starttp; /* our signal handler - called when the time is up */ void alrm(int n) { float f; struct timeval tp2; float period; gettimeofday(&tp2, (void *) 0); period = (tp2.tv_sec - starttp.tv_sec) + (tp2.tv_usec - starttp.tv_usec)/1E6; f = 1E6 / (count/ period ); printf("single op took %6.2fus period=%6.2fs count=%d\n", f,period,count); exit(0); } /* wrapper for mmap - offset is in units of blocks */ char * mymmap(fd,offset,nblocks) { char *a; a = mmap((char *) 0,BUFSIZE*nblocks, PROT_READ|PROT_WRITE, MAP_SHARED, fd, BUFSIZE*offset); if (a == MAP_FAILED) { perror("mmap failed"); exit(1); } return a; } main() { buf[0] = 'A'; buf[1] = 'B'; buf[2] = 'C'; buf[3] = 'D'; signal(SIGALRM, alrm); alarm(PERIOD); gettimeofday(&starttp, (void *) 0); timeit(); } int timeit() { int fd,offset; char *addr; #ifdef SOL_TRUNC struct flock fl; fl.l_whence = 0; fl.l_len = 0; fl.l_type = F_UNLCK; #endif fd = open(TFILE, O_RDWR|O_CREAT, 0644); if (fd==-1) { perror("failed to open file"); exit(1); } #ifndef UNMAP addr = mymmap(fd,0,NBLOCKS); #endif offset=0; for(;;) { (int) *buf = count; #ifdef USEMM #ifdef DOTRUNC #ifdef SOL_TRUNC fl.l_start = (offset+1)*BUFSIZE; if (fcntl(fd,F_FREESP,&fl) == -1) { perror("fcntl"); exit(1); } #else ftruncate(fd,(offset+1)*BUFSIZE); #endif #endif #ifdef UNMAP addr = mymmap(fd,offset,1); memcpy(addr,buf,BUFSIZE); munmap(addr,BUFSIZE); #else memcpy(addr+BUFSIZE*offset,buf,BUFSIZE); #endif #else write(fd,buf,BUFSIZE); #endif count++; offset++; if (offset >= NBLOCKS) offset=0; } }