Skip to content

Commit e6118ed

Browse files
authored
Fix memory performance issue related to aligned_alloc (#149)
I was profiling `wtf` and found a behavior that I wasn't aware of. Basically, every calls we make to `aligned_alloc` allocates 8kish instead of 4kish. For whatever reason, I made an assumption that it would use a special allocator; it isn't a special allocator it just wraps a call to `malloc` with that math: `v5 = malloc(Alignment - 1 + Size + 8);`. In our case, both `Alignment` & `Size` are `0x1000`. I switched the calls to `aligned_alloc` to `VirtualAlloc` / `mmap` to match the behavior that I wanted in the first place. We also don't need page aligned chunks in the `Ram_t` object, so I turned this one into a `malloc` call.
1 parent af9730a commit e6118ed

File tree

3 files changed

+42
-7
lines changed

3 files changed

+42
-7
lines changed

src/wtf/bochscpu_backend.cc

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,45 @@ void StaticGpaMissingHandler(const uint64_t Gpa) {
7070
// (0000022ed2ae7000 + 00000738).
7171
//
7272

73-
uint8_t *Page = (uint8_t *)aligned_alloc(Page::Size, Page::Size);
73+
#if defined WINDOWS
74+
75+
//
76+
// VirtualAlloc is able to give us back page-aligned allocation, but every
77+
// time we allocate 1 page, the allocator actually reserve a 64KB region of VA
78+
// and we'll use the first page of that. This basically fragment the
79+
// address-space, so what we do is we actually reserve a 64KB region, and
80+
// we'll commit pages as we need them.
81+
//
82+
83+
static size_t Left = 0;
84+
static uint8_t *Current = nullptr;
85+
if (Left == 0) {
86+
87+
//
88+
// It's time to reserve a 64KB region.
89+
//
90+
91+
const uint64_t _64KB = 1024 * 64;
92+
Left = _64KB;
93+
Current =
94+
(uint8_t *)VirtualAlloc(nullptr, Left, MEM_RESERVE, PAGE_READWRITE);
95+
}
96+
97+
//
98+
// Commit a page off the reserved region.
99+
//
100+
101+
uint8_t *Page =
102+
(uint8_t *)VirtualAlloc(Current, Page::Size, MEM_COMMIT, PAGE_READWRITE);
103+
104+
Left -= Page::Size;
105+
Current += Page::Size;
74106
if (Page == nullptr) {
107+
#elif defined LINUX
108+
uint8_t *Page = (uint8_t *)mmap(nullptr, Page::Size, PROT_READ | PROT_WRITE,
109+
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
110+
if (Page == (void *)-1) {
111+
#endif
75112
fmt::print("Failed to allocate memory in GpaMissingHandler.\n");
76113
__debugbreak();
77114
}

src/wtf/platform.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ using ssize_t = SSIZE_T;
1818
#define __builtin_bswap16 _byteswap_ushort
1919
#define __builtin_bswap32 _byteswap_ulong
2020
#define __builtin_bswap64 _byteswap_uint64
21-
#define aligned_alloc(a, b) _aligned_malloc(a, b)
22-
#define aligned_free(x) _aligned_free(x)
2321
#if defined ARCH_X86
2422
#define WINDOWS_X86
2523
#elif defined ARCH_X64

src/wtf/ram.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class Ram_t {
7474

7575
~Ram_t() {
7676
for (const auto &[_, Page] : Cache_) {
77-
aligned_free(Page);
77+
free(Page);
7878
}
7979

8080
if (Ram_ != nullptr) {
@@ -172,9 +172,9 @@ class Ram_t {
172172
//
173173

174174
else {
175-
Page = (uint8_t *)aligned_alloc(Page::Size, Page::Size);
175+
Page = (uint8_t *)malloc(Page::Size);
176176
if (Page == nullptr) {
177-
fmt::print("Failed to call aligned_alloc.\n");
177+
fmt::print("Failed to allocate memory.\n");
178178
return nullptr;
179179
}
180180

@@ -302,7 +302,7 @@ class Ram_t {
302302

303303
private:
304304
//
305-
// Get an HVA fora GPA by looking at our cache.
305+
// Get an HVA for a GPA by looking at our cache.
306306
//
307307

308308
[[nodiscard]] uint8_t *GetHvaFromCache(const Gpa_t Gpa) {

0 commit comments

Comments
 (0)