Created
January 13, 2021 11:18
-
-
Save nthery/9a29836af0fea6dfb5403f9b5e0f360f to your computer and use it in GitHub Desktop.
quick-and-dirty program to compare performance of stdio and mmap reads
This file contains 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
/* | |
* Quick-and-dirty program to compare performance of stdio vs mmap i/o. | |
*/ | |
#ifdef NDEBUG | |
#undef NDEBUG // assert used for error handling | |
#endif | |
#ifdef __linux__ | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
#include <unistd.h> | |
#else | |
#include <windows.h> | |
#include <io.h> | |
#endif // __linux__ | |
#include <cerrno> | |
#include <cstdio> | |
#include <cassert> | |
#include <string> | |
#include <string_view> | |
#include <cstring> | |
#include <utility> | |
#include <algorithm> | |
#include <iterator> | |
using namespace std; | |
#ifdef __linux__ | |
string filepath(string_view path) { | |
return string(path.data(), path.size()); | |
} | |
struct Mapping { | |
explicit Mapping(int fd, size_t len) | |
: base_(static_cast<char *>(mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0))) | |
, len_(len) | |
{ | |
if (base_ == MAP_FAILED) { | |
fprintf(stderr, "mmap error: %s\n", strerror(errno)); | |
abort(); | |
} | |
} | |
~Mapping() { | |
int error = munmap(const_cast<char *>(base_), len_); | |
assert(!error); | |
} | |
const char *base() const { return base_; } | |
private: | |
const char *base_; | |
size_t len_; | |
}; | |
#else | |
string filepath(string_view path) { | |
string out; | |
transform(path.begin(), path.end(), back_inserter(out), [](auto ch) { | |
return (ch == '/') ? '\\' : ch; | |
}); | |
return out; | |
} | |
struct Mapping { | |
explicit Mapping(int fd, size_t len) : | |
base_(nullptr) | |
{ | |
// XXX assume len fits in single DWORD | |
mapping_ = CreateFileMappingA(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), nullptr, PAGE_READONLY, | |
0, len, nullptr); | |
if (mapping_ == NULL) { | |
fprintf(stderr, "CreateFileMappingA failed: %d\n", GetLastError()); | |
abort(); | |
} | |
base_ = static_cast<char*>(MapViewOfFile(mapping_, FILE_MAP_READ, 0, 0, len)); | |
assert(base_ != nullptr); | |
} | |
~Mapping() { | |
UnmapViewOfFile(base_); | |
CloseHandle(mapping_); | |
} | |
const char *base() const { return base_; } | |
private: | |
const char *base_; | |
HANDLE mapping_; | |
}; | |
#endif // __linux__ | |
enum Mode { | |
STDIO, | |
MMAP | |
}; | |
template<class F> | |
unsigned char checksum(F next_char) { | |
unsigned char sum = 0; | |
int ch; | |
while ((ch = next_char()) != EOF) { | |
sum += static_cast<unsigned char>(ch); | |
} | |
return sum; | |
} | |
unsigned char stdio_checksum(FILE* fp) { | |
return checksum([fp] { return getc(fp); }); | |
} | |
unsigned char mmap_checksum(FILE* fp, size_t len) { | |
int fd = fileno(fp); | |
assert(fd >= 0); | |
Mapping m(fd, len); | |
const char *base = m.base(); | |
const char *curr = base; | |
const char *end = base + len; | |
auto sum = checksum([curr, end] () mutable { return curr < end ? *curr++ : EOF; }); | |
return sum; | |
} | |
int main(int argc, char *argv[]) { | |
assert(argc >= 3); | |
const Mode mode = [argv] { | |
if (argv[1] == "stdio"s) { | |
return STDIO; | |
} else if (argv[1] == "mmap"s) { | |
return MMAP; | |
} else { | |
assert(false && "incorrect first argument"); | |
return STDIO; | |
} | |
}(); | |
for (int i = 2; i < argc; ++i) { | |
FILE* fp = fopen(filepath(argv[i]).c_str(), "r"); | |
if (fp == NULL) { | |
fprintf(stderr, "fopen(%s) failed: %s\n", argv[i], strerror(errno)); | |
} | |
unsigned char sum = 0; | |
switch (mode) { | |
case STDIO: | |
sum = stdio_checksum(fp); | |
break; | |
case MMAP: | |
{ | |
int fd = fileno(fp); | |
assert(fd >= 0); | |
struct stat sb; | |
int error = fstat(fd, &sb); | |
assert(!error); | |
if (sb.st_size == 0) { | |
sum = 0; | |
} else { | |
sum = mmap_checksum(fp, sb.st_size); | |
} | |
} | |
break; | |
} | |
printf("%s %u\n", argv[i], sum); | |
fclose(fp); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment