Created
June 24, 2010 20:07
-
-
Save afeinberg/451910 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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