Skip to content

Instantly share code, notes, and snippets.

@nthery
Created January 13, 2021 11:18
Show Gist options
  • Save nthery/9a29836af0fea6dfb5403f9b5e0f360f to your computer and use it in GitHub Desktop.
Save nthery/9a29836af0fea6dfb5403f9b5e0f360f to your computer and use it in GitHub Desktop.
quick-and-dirty program to compare performance of stdio and mmap reads
/*
* 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