Last active
January 23, 2026 01:15
-
-
Save jweinst1/e0119aabc6fcee3ee9d1134154f3d1ea to your computer and use it in GitHub Desktop.
Shows performance of TLB mmap writes across 1, 100, and 1024 pages
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
| #include <iostream> | |
| #include <vector> | |
| #include <unordered_map> | |
| #include <random> | |
| #include <chrono> | |
| #include <cstdint> | |
| #include <limits> | |
| #include <cstring> | |
| #include <cstdlib> | |
| #include <filesystem> | |
| #include <regex> | |
| #include <optional> | |
| #include <string> | |
| #include <sys/mman.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <fcntl.h> | |
| #include <unistd.h> | |
| struct IdGen { | |
| std::random_device rd; | |
| std::mt19937 gen; | |
| std::uniform_int_distribution<uint64_t> distrib; | |
| IdGen(): rd(), gen(rd()), distrib(std::numeric_limits<uint64_t>::min(), | |
| std::numeric_limits<uint64_t>::max()) {} | |
| uint64_t next() { | |
| return static_cast<uint64_t>(distrib(gen)); | |
| } | |
| }; | |
| // page_size = sysconf(_SC_PAGESIZE); | |
| // file backed void* mapResult = mmap(nullptr, hf.file_size, PROT_READ | PROT_WRITE, MAP_SHARED, hf.fd, 0); | |
| // memory ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
| /** | |
| * static bool byteVectorToFile(const std::vector<unsigned char>& bytes, const std::string& path) { | |
| FILE* fp = std::fopen(path.c_str(), "wb+"); | |
| if (fp == nullptr) { | |
| return false; | |
| } | |
| std::fwrite(bytes.data(), bytes.size(), 1, fp); | |
| std::fclose(fp); | |
| return true; | |
| } | |
| //int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); | |
| // 2. Set the file size to the desired length using ftruncate. | |
| // This efficiently creates a file with a "hole" filled with implicit null bytes. | |
| if (ftruncate(fd, filesize) == -1) { | |
| perror("ftruncate"); | |
| close(fd); | |
| exit(EXIT_FAILURE); | |
| } | |
| if (lseek(fd, 0, SEEK_SET) == -1) { | |
| perror("lseek (rewind)"); | |
| close(fd); | |
| exit(EXIT_FAILURE); | |
| } | |
| * */ | |
| static size_t getTlbEntryCount() { | |
| long page_size = sysconf(_SC_PAGESIZE); | |
| size_t perPageSize = page_size / 8192; | |
| if (perPageSize == 4) | |
| return 2048; | |
| if (perPageSize == 1) | |
| return 8192; | |
| if (perPageSize == 2) | |
| return 4096; | |
| return (size_t)-1; | |
| } | |
| static void* allocateTestPage(size_t pageCount) { | |
| long page_size = sysconf(_SC_PAGESIZE); | |
| size_t totalSize = page_size * pageCount; | |
| void* ptr = mmap(NULL, totalSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
| if (ptr == MAP_FAILED) { | |
| abort(); | |
| } | |
| madvise(ptr, totalSize, MADV_RANDOM); | |
| return ptr; | |
| } | |
| static void writeMappedTest_1() { | |
| long page_size = sysconf(_SC_PAGESIZE); | |
| static constexpr size_t testPageSize = 1; | |
| static constexpr size_t testSize = 10000000; | |
| const size_t entryCount = (page_size * testPageSize) / sizeof(uint64_t); | |
| printf("Using page size %ld, entry count %zu\n", page_size, entryCount); | |
| IdGen gens; | |
| std::vector<uint64_t> nums; | |
| for (int i = 0; i < testSize; ++i) | |
| { | |
| nums.push_back(gens.next() % entryCount); | |
| } | |
| void* myPage = allocateTestPage(testPageSize); | |
| uint64_t* myWriter = (uint64_t*)myPage; | |
| auto start = std::chrono::high_resolution_clock::now(); | |
| for (int i = 0; i < testSize; ++i) | |
| { | |
| myWriter[nums[i]] = i; | |
| } | |
| auto end = std::chrono::high_resolution_clock::now(); | |
| std::cout << " 1 page test " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us\n"; | |
| } | |
| static void writeMappedTest_2() { | |
| long page_size = sysconf(_SC_PAGESIZE); | |
| static constexpr size_t testPageSize = 100; | |
| static constexpr size_t testSize = 10000000; | |
| const size_t entryCount = (page_size * testPageSize) / sizeof(uint64_t); | |
| printf("Using page size %ld, entry count %zu\n", page_size, entryCount); | |
| IdGen gens; | |
| std::vector<uint64_t> nums; | |
| for (int i = 0; i < testSize; ++i) | |
| { | |
| nums.push_back(gens.next() % entryCount); | |
| } | |
| void* myPage = allocateTestPage(testPageSize); | |
| uint64_t* myWriter = (uint64_t*)myPage; | |
| auto start = std::chrono::high_resolution_clock::now(); | |
| for (int i = 0; i < testSize; ++i) | |
| { | |
| myWriter[nums[i]] = i; | |
| } | |
| auto end = std::chrono::high_resolution_clock::now(); | |
| std::cout << " 100 page test " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us\n"; | |
| } | |
| static void writeMappedTest_3() { | |
| long page_size = sysconf(_SC_PAGESIZE); | |
| static constexpr size_t testPageSize = 1024; | |
| static constexpr size_t testSize = 10000000; | |
| const size_t entryCount = (page_size * testPageSize) / sizeof(uint64_t); | |
| printf("Using page size %ld, entry count %zu\n", page_size, entryCount); | |
| IdGen gens; | |
| std::vector<uint64_t> nums; | |
| for (int i = 0; i < testSize; ++i) | |
| { | |
| nums.push_back(gens.next() % entryCount); | |
| } | |
| void* myPage = allocateTestPage(testPageSize); | |
| uint64_t* myWriter = (uint64_t*)myPage; | |
| auto start = std::chrono::high_resolution_clock::now(); | |
| for (int i = 0; i < testSize; ++i) | |
| { | |
| myWriter[nums[i]] = i; | |
| } | |
| auto end = std::chrono::high_resolution_clock::now(); | |
| std::cout << " 1024 page test " << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "us\n"; | |
| } | |
| int main(int argc, char const *argv[]) | |
| { | |
| long page_size = sysconf(_SC_PAGESIZE); | |
| std::printf("%ld\n", page_size); | |
| writeMappedTest_1(); | |
| writeMappedTest_2(); | |
| writeMappedTest_3(); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment