#include #include #include #include #include #include #include #include using namespace weaselab; double now() { return std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch()) .count() * 1e-9; } inline size_t getPageSize() { static size_t kPageSize = sysconf(_SC_PAGESIZE); return kPageSize; } /// Helper for rounding up to page size (or some other alignment) constexpr inline size_t rightAlign(size_t offset, size_t alignment) { return offset % alignment == 0 ? offset : ((offset / alignment) + 1) * alignment; } int main(int argc, const char **argv) { // Use with this dataset https://snap.stanford.edu/data/memetracker9.html // Preprocess the files with `sed -i'' '/^Q/d'` double checkTime = 0; double addTime = 0; double gcTime = 0; double checkBytes = 0; double addBytes = 0; ConflictSet cs{0}; int64_t version = 0; double timer = 0; int64_t peakMemory = 0; for (int i = 1; i < argc; ++i) { int fd = open(argv[i], O_RDONLY); struct stat st; if (fstat(fd, &st) == -1) { int err = errno; fprintf(stderr, "stat error %s - %s\n", argv[i], strerror(err)); fflush(stderr); abort(); } int64_t size = rightAlign(st.st_size, getPageSize()); const uint8_t *begin = (uint8_t *)mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); madvise((void *)begin, size, MADV_SEQUENTIAL); auto *const mapOriginal = begin; const auto sizeOriginal = size; using StringView = std::basic_string_view; StringView write; std::vector reads; std::vector readRanges; std::vector results; for (uint8_t *end = (uint8_t *)memchr(begin, '\n', size); end != nullptr;) { StringView line{begin, static_cast(end - begin)}; size -= end - begin + 1; begin = end + 1; end = (uint8_t *)memchr(begin, '\n', size); if (line.size() > 0 && line[0] == 'P') { write = line.substr(2, line.size()); } else if (line.size() > 0 && line[0] == 'L') { reads.push_back(line.substr(2, line.size())); } else if (line.empty()) { { readRanges.resize(reads.size()); auto iter = readRanges.begin(); for (const auto &read : reads) { iter->begin.p = (const uint8_t *)read.data(); iter->begin.len = read.size(); checkBytes += read.size(); iter->end.len = 0; iter->readVersion = version - 100; ++iter; } } results.resize(readRanges.size()); timer = now(); cs.check(readRanges.data(), results.data(), readRanges.size()); checkTime += now() - timer; // Add unconditionally so that the load doesn't actually depend on the // conflict rate ConflictSet::WriteRange w; w.begin.p = (const uint8_t *)write.data(); w.begin.len = write.size(); w.end.len = 0; addBytes += write.size(); timer = now(); cs.addWrites(&w, 1, ++version); addTime += now() - timer; write = {}; reads.clear(); if (cs.getBytes() > peakMemory) { peakMemory = cs.getBytes(); } timer = now(); cs.setOldestVersion(version - 10000); gcTime += now() - timer; } } munmap((void *)mapOriginal, sizeOriginal); close(fd); } printf("Check: %g seconds, %g MB/s, Add: %g seconds, %g MB/s, Gc ratio: " "%g%%, Peak idle memory: %g\n", checkTime, checkBytes / checkTime * 1e-6, addTime, addBytes / addTime * 1e-6, gcTime / (gcTime + addTime) * 1e2, double(peakMemory)); }