Last active
October 12, 2023 20:33
-
-
Save kklobe/e9ff3cb0d455c3ff659c5d3d5678be54 to your computer and use it in GitHub Desktop.
X86PageEntry microbenchmark
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
#include <cstdint> | |
#include <chrono> | |
#include <iostream> | |
#include <vector> | |
#ifdef _MSC_VER | |
#pragma pack (1) | |
#endif | |
struct X86_PageEntryBlock{ | |
#ifdef WORDS_BIGENDIAN | |
uint32_t base:20; | |
uint32_t avl:3; | |
uint32_t g:1; | |
uint32_t pat:1; | |
uint32_t d:1; | |
uint32_t a:1; | |
uint32_t pcd:1; | |
uint32_t pwt:1; | |
uint32_t us:1; | |
uint32_t wr:1; | |
uint32_t p:1; | |
#else | |
uint32_t p:1; | |
uint32_t wr:1; | |
uint32_t us:1; | |
uint32_t pwt:1; | |
uint32_t pcd:1; | |
uint32_t a:1; | |
uint32_t d:1; | |
uint32_t pat:1; | |
uint32_t g:1; | |
uint32_t avl:3; | |
uint32_t base:20; | |
#endif | |
} __attribute__((packed)); | |
#ifdef _MSC_VER | |
#pragma pack () | |
#endif | |
union X86PageEntry { | |
uint32_t load = 0; | |
X86_PageEntryBlock block; | |
}; | |
struct X86PageEntryNew { | |
#ifdef WORDS_BIGENDIAN | |
uint32_t base:20; | |
uint32_t avl:3; | |
uint32_t g:1; | |
uint32_t pat:1; | |
uint32_t d:1; | |
uint32_t a:1; | |
uint32_t pcd:1; | |
uint32_t pwt:1; | |
uint32_t us:1; | |
uint32_t wr:1; | |
uint32_t p:1; | |
#else | |
uint32_t p:1; | |
uint32_t wr:1; | |
uint32_t us:1; | |
uint32_t pwt:1; | |
uint32_t pcd:1; | |
uint32_t a:1; | |
uint32_t d:1; | |
uint32_t pat:1; | |
uint32_t g:1; | |
uint32_t avl:3; | |
uint32_t base:20; | |
#endif | |
constexpr void set(const uint32_t value) { | |
#ifdef WORDS_BIGENDIAN | |
base = (value >> 12) & 0xFFFFF; | |
avl = (value >> 9) & 0x7; | |
g = (value >> 8) & 0x1; | |
pat = (value >> 7) & 0x1; | |
d = (value >> 6) & 0x1; | |
a = (value >> 5) & 0x1; | |
pcd = (value >> 4) & 0x1; | |
pwt = (value >> 3) & 0x1; | |
us = (value >> 2) & 0x1; | |
wr = (value >> 1) & 0x1; | |
p = value & 0x1; | |
#else | |
p = value & 0x1; | |
wr = (value >> 1) & 0x1; | |
us = (value >> 2) & 0x1; | |
pwt = (value >> 3) & 0x1; | |
pcd = (value >> 4) & 0x1; | |
a = (value >> 5) & 0x1; | |
d = (value >> 6) & 0x1; | |
pat = (value >> 7) & 0x1; | |
g = (value >> 8) & 0x1; | |
avl = (value >> 9) & 0x7; | |
base = (value >> 12) & 0xFFFFF; | |
#endif | |
} | |
constexpr uint32_t get() const { | |
uint32_t value = 0; | |
#ifdef WORDS_BIGENDIAN | |
value |= (base << 12); | |
value |= (avl << 9); | |
value |= (g << 8); | |
value |= (pat << 7); | |
value |= (d << 6); | |
value |= (a << 5); | |
value |= (pcd << 4); | |
value |= (pwt << 3); | |
value |= (us << 2); | |
value |= (wr << 1); | |
value |= p; | |
#else | |
value |= p; | |
value |= (wr << 1); | |
value |= (us << 2); | |
value |= (pwt << 3); | |
value |= (pcd << 4); | |
value |= (a << 5); | |
value |= (d << 6); | |
value |= (pat << 7); | |
value |= (g << 8); | |
value |= (avl << 9); | |
value |= (base << 12); | |
#endif | |
return value; | |
} | |
}; | |
int main() { | |
const std::size_t numIterations = 100000000; | |
std::vector<uint32_t> values(numIterations); | |
for (std::size_t i = 0; i < numIterations; ++i) { | |
values[i] = static_cast<uint32_t>(i); | |
} | |
auto start = std::chrono::high_resolution_clock::now(); | |
// Test old union/struct | |
X86PageEntry oldEntry; | |
for (std::size_t i = 0; i < numIterations; ++i) { | |
oldEntry.load = values[i]; | |
volatile uint32_t tmp = oldEntry.load; // Prevent optimization | |
} | |
auto end = std::chrono::high_resolution_clock::now(); | |
auto durationOld = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); | |
std::cout << "Old struct/union duration: " << durationOld << " microseconds\n"; | |
start = std::chrono::high_resolution_clock::now(); | |
// Test new struct | |
X86PageEntryNew newEntry; | |
for (std::size_t i = 0; i < numIterations; ++i) { | |
newEntry.set(values[i]); | |
volatile uint32_t tmp = newEntry.get(); // Prevent optimization | |
} | |
end = std::chrono::high_resolution_clock::now(); | |
auto durationNew = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); | |
std::cout << "New struct duration: " << durationNew << " microseconds\n"; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment