Skip to content

Commit 2d12e79

Browse files
committed
runtime: allow "huge objects" to be allocated with malloc
This enables the runtime to operate at the same time as malloc without trouble.
1 parent a544adf commit 2d12e79

10 files changed

+122
-54
lines changed

runtime/core/Heap.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <alaska/Logger.hpp>
1515
#include <alaska/Heap.hpp>
1616
#include "alaska/HeapPage.hpp"
17+
#include "alaska/HugeObjectAllocator.hpp"
1718
#include "alaska/LocalityPage.hpp"
1819
#include "alaska/SizeClass.hpp"
1920
#include "alaska/utils.h"
@@ -156,9 +157,10 @@ namespace alaska {
156157

157158

158159
////////////////////////////////////
159-
Heap::Heap(void)
160+
Heap::Heap(alaska::Configuration &config)
160161
: pm()
161-
, pt(pm.get_start()) {
162+
, pt(pm.get_start())
163+
, huge_allocator(config.huge_strategy) {
162164
log_debug("Heap: Initialized heap");
163165
}
164166

runtime/core/HugeObjectAllocator.cpp

+23-2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@
1010
*/
1111

1212

13+
#include <malloc.h>
14+
#include <stdlib.h>
15+
1316
#include <alaska/Heap.hpp>
1417
#include <alaska/HugeObjectAllocator.hpp>
18+
#include <alaska/liballoc.h>
1519
#include <alaska/list_head.h>
1620

1721
namespace alaska {
18-
HugeObjectAllocator::HugeObjectAllocator() { INIT_LIST_HEAD(&this->allocations); }
22+
HugeObjectAllocator::HugeObjectAllocator(HugeAllocationStrategy strat)
23+
: strat(strat) {
24+
INIT_LIST_HEAD(&this->allocations);
25+
}
1926

2027
HugeObjectAllocator::~HugeObjectAllocator() {
2128
HugeHeader *entry, *temp;
@@ -30,6 +37,11 @@ namespace alaska {
3037

3138

3239
void* HugeObjectAllocator::allocate(size_t size) {
40+
if (strat == HugeAllocationStrategy::MALLOC_BACKED) {
41+
return ::malloc(size);
42+
}
43+
ALASKA_ASSERT(strat == HugeAllocationStrategy::CUSTOM_MMAP_BACKED, "Invalid huge strat");
44+
3345
ck::scoped_lock l(m_lock);
3446

3547
size_t mapping_size = ((size + sizeof(HugeHeader)) + 4095) & ~4095;
@@ -54,6 +66,11 @@ namespace alaska {
5466

5567

5668
bool HugeObjectAllocator::free(void* ptr) {
69+
if (strat == HugeAllocationStrategy::MALLOC_BACKED) {
70+
::free(ptr);
71+
return true;
72+
}
73+
ALASKA_ASSERT(strat == HugeAllocationStrategy::CUSTOM_MMAP_BACKED, "Invalid huge strat");
5774
ck::scoped_lock l(m_lock);
5875

5976
// Get the HugeHeader object from the user pointer
@@ -70,6 +87,8 @@ namespace alaska {
7087

7188

7289
size_t HugeObjectAllocator::size_of(void* ptr) {
90+
if (strat == HugeAllocationStrategy::MALLOC_BACKED) return ::malloc_usable_size(ptr);
91+
7392
ck::scoped_lock l(m_lock);
7493
HugeHeader* header = find_header(ptr);
7594
if (header != nullptr) {
@@ -80,6 +99,8 @@ namespace alaska {
8099

81100

82101
bool HugeObjectAllocator::owns(void* ptr) {
102+
if (strat == HugeAllocationStrategy::MALLOC_BACKED) return true;
103+
83104
ck::scoped_lock l(m_lock);
84105
// If the header is null, this allocator doesn't own it.
85106
return find_header(ptr) != nullptr;
@@ -97,4 +118,4 @@ namespace alaska {
97118
// If no matching header is found, return nullptr
98119
return nullptr;
99120
}
100-
} // namespace alaska} // namespace alaska
121+
} // namespace alaska

runtime/core/Logger.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,14 @@ namespace alaska {
100100

101101

102102
// Grab the lock
103-
pthread_mutex_lock(&log_mutex);
103+
// pthread_mutex_lock(&log_mutex);
104104

105-
time_t t = time(NULL);
106-
auto time = localtime(&t);
105+
// time_t t = time(NULL);
106+
// auto time = localtime(&t);
107107

108108
char buf[16];
109-
buf[strftime(buf, sizeof(buf), "%H:%M:%S", time)] = '\0';
109+
buf[0] = '\0';
110+
// buf[strftime(buf, sizeof(buf), "%H:%M:%S", time)] = '\0';
110111

111112
if (enable_colors) {
112113
log_emitf("%s %s%-5s\x1b[0m \x1b[90m%s:%d\x1b[0m | ", buf, level_colors[level],
@@ -119,7 +120,7 @@ namespace alaska {
119120
log_emitf("\n");
120121

121122
// release the lock
122-
pthread_mutex_unlock(&log_mutex);
123+
// pthread_mutex_unlock(&log_mutex);
123124
va_end(args);
124125
}
125126
}

runtime/core/Runtime.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ namespace alaska {
2727

2828

2929
Runtime::Runtime(alaska::Configuration config)
30-
: handle_table(config) {
30+
: handle_table(config)
31+
, heap(config) {
3132
// Validate that there is not already a runtime (TODO: atomics?)
3233
ALASKA_ASSERT(g_runtime == nullptr, "Cannot create more than one runtime");
3334

runtime/include/alaska/Configuration.hpp

+4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,16 @@
1212
#pragma once
1313

1414
#include <stdint.h>
15+
#include <alaska/HugeObjectAllocator.hpp>
1516

1617
namespace alaska {
1718
// This structure is threaded through the creation of the runtime to
1819
// allow configuration of various features.
1920
struct Configuration {
2021
uintptr_t handle_table_location =
2122
(0x8000000000000000LLU >> (ALASKA_SIZE_BITS - ALASKA_SQUEEZE_BITS));
23+
24+
// Allocate using a custom mmap backend by default for large objects.
25+
HugeAllocationStrategy huge_strategy = HugeAllocationStrategy::CUSTOM_MMAP_BACKED;
2226
};
2327
} // namespace alaska

runtime/include/alaska/Heap.hpp

+2-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <alaska/Magazine.hpp>
1919
#include <alaska/HugeObjectAllocator.hpp>
2020
#include <alaska/track.hpp>
21+
#include "alaska/Configuration.hpp"
2122
#include "alaska/LocalityPage.hpp"
2223
#include <ck/vec.h>
2324
#include <stdlib.h>
@@ -137,7 +138,7 @@ namespace alaska {
137138

138139
HugeObjectAllocator huge_allocator;
139140

140-
Heap(void);
141+
Heap(alaska::Configuration &config);
141142
~Heap(void);
142143

143144
// Get an unowned sized page given a certain size request.
@@ -175,17 +176,6 @@ namespace alaska {
175176
ck::mutex lock;
176177
alaska::Magazine<alaska::SizedPage> size_classes[alaska::num_size_classes];
177178
alaska::Magazine<alaska::LocalityPage> locality_pages;
178-
179-
180-
// Huge objects are managed independently of the size classes. They are allocated
181-
// directly from the kernel and are *not handles*
182-
ck::mutex huge_lock;
183-
struct list_head huge_allocations;
184-
185-
struct HugeHeader {
186-
struct list_head list;
187-
size_t size;
188-
};
189179
};
190180

191181

runtime/include/alaska/HugeObjectAllocator.hpp

+12-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,18 @@
1616
#include <ck/lock.h>
1717

1818
namespace alaska {
19+
20+
21+
// The HugeObjectAllocator can be configured with different strategies. The main one
22+
// uses a custom mmap based strategy to track large objects. The other option is one
23+
// which is backed by libc's malloc, instead
24+
enum class HugeAllocationStrategy {
25+
CUSTOM_MMAP_BACKED,
26+
MALLOC_BACKED,
27+
};
1928
class HugeObjectAllocator final {
2029
public:
21-
HugeObjectAllocator();
30+
HugeObjectAllocator(HugeAllocationStrategy strat);
2231
~HugeObjectAllocator();
2332

2433
void* allocate(size_t size);
@@ -32,6 +41,7 @@ namespace alaska {
3241
bool owns(void* ptr);
3342

3443
private:
44+
HugeAllocationStrategy strat;
3545
ck::mutex m_lock;
3646
struct list_head allocations = LIST_HEAD_INIT(allocations);
3747

@@ -50,4 +60,4 @@ namespace alaska {
5060

5161
HugeHeader* find_header(void* ptr);
5262
};
53-
} // namespace alaska
63+
} // namespace alaska

runtime/test/heap_test.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <gtest/gtest.h>
22
#include <alaska.h>
3+
#include "alaska/Configuration.hpp"
34
#include "alaska/Logger.hpp"
45
#include "alaska/SizeClass.hpp"
56
#include "gtest/gtest.h"
@@ -8,6 +9,8 @@
89

910
#include <alaska/Runtime.hpp>
1011

12+
13+
static alaska::Configuration g_config;
1114
class HeapTest : public ::testing::Test {
1215
public:
1316
void SetUp() override {
@@ -16,7 +19,7 @@ class HeapTest : public ::testing::Test {
1619
}
1720
void TearDown() override {}
1821

19-
alaska::Heap heap;
22+
alaska::Heap heap {g_config};
2023
};
2124

2225

runtime/test/hugeobject_test.cpp

+51-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@
88

99
class HugeObjectTest : public ::testing::Test {
1010
public:
11-
alaska::HugeObjectAllocator allocator;
11+
alaska::HugeObjectAllocator allocator{alaska::HugeAllocationStrategy::CUSTOM_MMAP_BACKED};
12+
};
13+
14+
15+
class HugeObjectMallocTest : public ::testing::Test {
16+
public:
17+
alaska::HugeObjectAllocator allocator{alaska::HugeAllocationStrategy::MALLOC_BACKED};
1218
};
1319

1420
TEST_F(HugeObjectTest, AllocateAndDeallocate) {
@@ -97,3 +103,47 @@ TEST_F(HugeObjectTest, FreeNonOwnedPointer) {
97103
// Deallocate the owned pointer
98104
allocator.free(ptr);
99105
}
106+
107+
108+
109+
TEST_F(HugeObjectMallocTest, ValidMalloc) {
110+
// Allocate a huge object
111+
void* ptr = allocator.allocate(1024);
112+
113+
// Verify that the allocation was successful
114+
ASSERT_NE(ptr, nullptr);
115+
116+
EXPECT_EXIT(
117+
{
118+
// Code that might crash.
119+
::free(ptr);
120+
fprintf(stderr, "Free worked!\n");
121+
exit(0); // Prevents the test from failing due to lack of exit
122+
},
123+
::testing::ExitedWithCode(0), "Free worked");
124+
}
125+
126+
TEST_F(HugeObjectMallocTest, FreeWorks) {
127+
// Allocate a huge object
128+
void* ptr = ::malloc(1024);
129+
130+
// Verify that the allocation was successful
131+
ASSERT_NE(ptr, nullptr);
132+
133+
EXPECT_EXIT(
134+
{
135+
// Code that might crash.
136+
ASSERT_TRUE(allocator.free(ptr));
137+
fprintf(stderr, "Free worked!\n");
138+
exit(0); // Prevents the test from failing due to lack of exit
139+
},
140+
::testing::ExitedWithCode(0), "Free worked");
141+
}
142+
143+
144+
145+
TEST_F(HugeObjectMallocTest, SizeofWorks) {
146+
// Allocate a huge object
147+
void* ptr = ::malloc(1024);
148+
ASSERT_GE(allocator.size_of(ptr), 1024);
149+
}

runtime/yukon/yukon.cpp

+14-28
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
#include <alaska/alaska.hpp>
1515
#include <alaska/utils.h>
1616
#include <alaska/Runtime.hpp>
17-
#include "alaska/Configuration.hpp"
18-
#include "alaska/liballoc.h"
17+
#include <alaska/Configuration.hpp>
18+
#include <alaska/liballoc.h>
1919
#include <stdlib.h>
2020
#include <errno.h>
2121
#include <signal.h>
@@ -47,6 +47,8 @@ static alaska::Runtime *the_runtime = NULL;
4747

4848
static bool dead = false;
4949

50+
static bool is_initialized() { return the_runtime != NULL; }
51+
5052

5153
static void print_hex(const char *msg, uint64_t val) {
5254
char buf[512];
@@ -63,25 +65,8 @@ static void print_words(unsigned *words, int n) {
6365
write(STDOUT_FILENO, "\n", 1);
6466
}
6567

66-
void segfault_handler(int sig) {
67-
dead = true;
68-
write(STDOUT_FILENO, "segfault\n", 4);
69-
void *array[BACKTRACE_SIZE];
70-
size_t size;
71-
72-
// Get the backtrace
73-
size = backtrace(array, BACKTRACE_SIZE);
74-
75-
for (size_t i = 0; i < size; i++) {
76-
print_hex("bt:", (uint64_t)array[i]);
77-
print_words((unsigned *)array[i], 4);
78-
}
79-
exit(0);
80-
81-
// Print the backtrace to stderr
82-
char **ns = backtrace_symbols(array, size);
83-
}
8468

69+
static void print_string(const char *msg) { write(STDOUT_FILENO, msg, strlen(msg)); }
8570

8671
static char stdout_buf[BUFSIZ];
8772
static char stderr_buf[BUFSIZ];
@@ -115,17 +100,18 @@ static alaska::ThreadCache *get_tc() {
115100
}
116101

117102
void __attribute__((constructor(102))) alaska_init(void) {
118-
init();
103+
unsetenv("LD_PRELOAD"); // make it so we don't run alaska in subprocesses!
104+
get_tc();
119105
}
120106

121107
void __attribute__((destructor)) alaska_deinit(void) {
122-
if (the_runtime != NULL) {
123-
if (tc != NULL) {
124-
the_runtime->del_threadcache(tc);
125-
}
126-
delete the_runtime;
127-
}
128-
set_ht_addr(NULL);
108+
// if (the_runtime != NULL) {
109+
// if (tc != NULL) {
110+
// the_runtime->del_threadcache(tc);
111+
// }
112+
// delete the_runtime;
113+
// }
114+
// set_ht_addr(NULL);
129115
}
130116

131117

0 commit comments

Comments
 (0)