Skip to content

Instantly share code, notes, and snippets.

@afeinberg
Created June 24, 2010 20:07
Show Gist options
  • Select an option

  • Save afeinberg/451910 to your computer and use it in GitHub Desktop.

Select an option

Save afeinberg/451910 to your computer and use it in GitHub Desktop.
// This is probably a fairly stupid benchmark, but I was curious as to
// how madvise would change behaviour/performance with different
// madvise modes. Especially, I am curious as to performance
// differences on Linux vs. Solaris vs. OS X.
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <sstream>
#include <ctype.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
extern int errno;
class MmapTester {
protected:
int _fd;
long _numVals;
int _valSize;
int _numOps;
char *_map;
public:
MmapTester(const char* filename, long numVals, int valSize=512, int numOps=1000000):
_numVals(numVals),
_valSize(valSize),
_numOps(numOps),
_map(NULL)
{
std::cout << "numVals = " << _numVals << " valSize = " << _valSize << " numOps = " << _numOps
<< std::endl;
_fd = open(filename, O_RDWR | O_CREAT, (mode_t) 0644);
if (_fd == -1) {
std::stringstream ss;
ss << "open() " << strerror(errno);
throw std::runtime_error(ss.str());
}
}
virtual void mmapInit();
void populate();
void readTest();
virtual ~MmapTester() {
int rc;
if (_fd != -1) {
rc = close(_fd);
if (rc != 0)
perror("close()");
}
if (_map != NULL) {
rc = munmap(_map, _numVals);
if (rc != 0)
perror("munmap()");
}
}
};
void MmapTester::mmapInit() {
assert(_fd != -1);
_map = (char *) mmap(NULL, _numVals * _valSize, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
if (_map == MAP_FAILED) {
_map = NULL;
throw std::runtime_error("error with mmap()");
}
}
void MmapTester::readTest() {
char data[_valSize];
mmapInit();
srandomdev();
std::cout << "Starting read test" << std::endl;
struct timeval tv_start;
struct timeval tv_end;
gettimeofday(&tv_start, NULL);
for (int i = 0; i < _numOps; i++) {
long pos = (random() % _numVals) * _valSize;
memcpy(data, _map + pos, _valSize);
}
gettimeofday(&tv_end, NULL);
long elapsed = ( tv_end.tv_sec * 1000000 + tv_end.tv_usec ) -
( tv_start.tv_sec * 1000000 + tv_start.tv_usec );
long double throughput = ( _numOps / ( elapsed / 1000000.0 ) );
std::cout << "Read throughput: " << throughput << " ops/sec" << std::endl;
}
void MmapTester::populate() {
char data[_valSize];
for (char *c = data; c < data + _valSize; c++)
*c = (char) random() % 127;
for (int i = 0; i < _numVals; i++) {
int res = write(_fd, data, _valSize);
if (res != _valSize) {
_fd = -1;
std::stringstream ss;
ss << "write(): " << strerror(errno) << " at " << i;
throw std::runtime_error(ss.str());
}
}
}
static void doMadvise(void *map, size_t size, int mode, const char *explanation) {
int rc = madvise(map, size, mode);
if (rc != 0) {
std::stringstream ss;
ss << "madvise() " << strerror(errno);
throw std::runtime_error(ss.str());
}
std::cout << "Advising " << explanation << std::endl;
}
class RandomMadviseTester: public MmapTester {
public:
RandomMadviseTester(const char* filename, long numVals, int valSize=512, int numOps=1000000):
MmapTester(filename, numVals, valSize, numOps) {
}
virtual void mmapInit() {
MmapTester::mmapInit();
doMadvise(_map, _numVals * _valSize, MADV_RANDOM, "MADV_RANDOM");
}
};
class WillNeedMadviseTester: public MmapTester {
public:
WillNeedMadviseTester(const char* filename, long numVals, int valSize=512, int numOps=1000000):
MmapTester(filename, numVals, valSize, numOps) {
}
virtual void mmapInit() {
MmapTester::mmapInit();
doMadvise(_map, _numVals * _valSize, MADV_WILLNEED, "MADV_WILLNEED");
}
};
#define PERFORM_READ 0x1
#define PERFORM_WRITE 0x2
#define ADVISE 0x4
int main(int argc, char **argv) {
unsigned int flags = 0;
std::string fileName("./mmap_test.bin");
int numVals = 2000000;
int numOps = 1000000;
int valSize = 512;
char adv = 'r';
char c;
while ((c = getopt(argc, argv, "rwf:v:s:a:o:")) != -1) {
switch(c) {
case 'a':
flags |= ADVISE;
adv = tolower(*optarg);
break;
case 'r':
flags |= PERFORM_READ;
break;
case 'w':
flags |= PERFORM_WRITE;
break;
case 'f':
fileName = optarg;
break;
case 'o':
numOps = atoi(optarg);
break;
case 'v':
numVals = atoi(optarg);
break;
case 's':
valSize = atoi(optarg);
break;
case '?':
std::cerr << "Unrecognized option" << std::endl;
break;
}
}
MmapTester *mmapTest = NULL;
try {
if (flags & ADVISE) {
switch(adv) {
case 'r':
mmapTest = new RandomMadviseTester(fileName.c_str(), numVals, valSize, numOps);
break;
case 'w':
mmapTest = new WillNeedMadviseTester(fileName.c_str(), numVals, valSize, numOps);
break;
default:
mmapTest = new RandomMadviseTester(fileName.c_str(), numVals, valSize, numOps);
break;
}
}
else
mmapTest = new MmapTester(fileName.c_str(), numVals, valSize, numOps);
if (flags & PERFORM_WRITE)
mmapTest->populate();
if (flags & PERFORM_READ)
mmapTest->readTest();
} catch (std::exception& e) {
std::cerr << "Exception during test: " << e.what() << std::endl;
}
if (mmapTest != NULL)
delete mmapTest;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment