Skip to content

Commit 2bf8ad3

Browse files
committed
yukon: restructure and rewrite to be less hacky
1 parent 814989e commit 2bf8ad3

File tree

2 files changed

+135
-130
lines changed

2 files changed

+135
-130
lines changed

runtime/include/yukon/yukon.hpp

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* This file is part of the Alaska Handle-Based Memory Management System
3+
*
4+
* Copyright (c) 2023, Nick Wanninger <ncw@u.northwestern.edu>
5+
* Copyright (c) 2023, The Constellation Project
6+
* All rights reserved.
7+
*
8+
* This is free software. You are permitted to use, redistribute,
9+
* and modify it as specified in the file "LICENSE".
10+
*/
11+
12+
#pragma once
13+
14+
15+
#include <alaska/ThreadCache.hpp>
16+
17+
18+
namespace yukon {
19+
20+
constexpr int csr_htbase = 0xc2;
21+
constexpr int csr_htdump = 0xc3;
22+
constexpr int csr_htinval = 0xc4;
23+
24+
// Set the handle table base register in hardware to enable handle translation
25+
void set_handle_table_base(void *base);
26+
// Trigger an HTLB dump
27+
void dump_htlb(alaska::ThreadCache *tc);
28+
29+
30+
void init(void);
31+
32+
alaska::ThreadCache *get_tc(void);
33+
34+
35+
}

runtime/yukon/yukon.cpp

+100-130
Original file line numberDiff line numberDiff line change
@@ -25,80 +25,38 @@
2525
#include <execinfo.h>
2626
#include <unistd.h>
2727

28-
#ifdef __riscv
29-
#define write_csr(reg, val) \
30-
({ asm volatile("csrw " #reg ", %0" ::"rK"((uint64_t)val) : "memory"); })
31-
#else
32-
#define write_csr(reg, val)
33-
// #warning YUKON expects riscv
34-
#endif
35-
36-
static alaska::ThreadCache *tc = NULL;
37-
38-
static void set_ht_addr(void *addr) {
39-
alaska::printf("set htbase to %p\n", addr);
40-
uint64_t value = (uint64_t)addr;
41-
if (value != 0 and getenv("YUKON_PHYS") != nullptr) {
42-
value |= (1LU << 63);
43-
}
44-
write_csr(0xc2, value);
45-
}
46-
47-
static alaska::Runtime *the_runtime = NULL;
48-
49-
50-
51-
#define BACKTRACE_SIZE 100
52-
53-
static bool dead = false;
28+
#include <yukon/yukon.hpp>
5429

55-
static bool is_initialized() { return the_runtime != NULL; }
5630

57-
58-
static void print_hex(const char *msg, uint64_t val) {
59-
char buf[512];
60-
snprintf(buf, 512, "%s 0x%zx\n", msg, val);
61-
write(STDOUT_FILENO, buf, strlen(buf));
62-
}
63-
64-
static void print_words(unsigned *words, int n) {
65-
char buf[512];
66-
for (int i = 0; i < n; i++) {
67-
snprintf(buf, 512, "%08x \n", words[i]);
68-
write(STDOUT_FILENO, buf, strlen(buf));
69-
}
70-
write(STDOUT_FILENO, "\n", 1);
71-
}
72-
73-
74-
static void print_string(const char *msg) { write(STDOUT_FILENO, msg, strlen(msg)); }
75-
76-
static char stdout_buf[BUFSIZ];
77-
static char stderr_buf[BUFSIZ];
31+
#define write_csr(reg, val) \
32+
({ asm volatile("csrw %0, %1" ::"i"(reg), "rK"((uint64_t)val) : "memory"); })
7833

7934

35+
#define read_csr(csr, val) \
36+
__asm__ __volatile__("csrr %0, %1" : "=r"(val) : "n"(csr) : /* clobbers: none */);
8037

81-
static void wait_for_csr_zero(void) {
82-
volatile uint32_t csr_value = 0x1;
83-
do {
84-
__asm__ volatile("csrr %0, 0xc3\n\t" : "=r"(csr_value) : : "memory");
85-
} while (csr_value != 0);
86-
}
8738

39+
#define wait_for_csr_zero(reg) \
40+
do { \
41+
volatile uint32_t csr_value = 0x1; \
42+
do { \
43+
read_csr(reg, csr_value); \
44+
} while (csr_value != 0); \
45+
} while (0);
8846

8947

90-
#define BACKTRACE_SIZE 100
48+
#define CSR_HTBASE 0xc2
49+
#define CSR_HTDUMP 0xc3
50+
#define CSR_HTINVAL 0xc4
9151

52+
static alaska::ThreadCache *tc = NULL;
53+
static alaska::Runtime *the_runtime = NULL;
9254

9355

94-
static void handle_sig(int sig) {
95-
printf("Caught signal %d (%s)\n", sig, strsignal(sig));
96-
void *buffer[BACKTRACE_SIZE];
97-
// Get the backtrace
98-
int nptrs = backtrace(buffer, BACKTRACE_SIZE);
99-
// Print the backtrace symbols
100-
backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO);
101-
exit(0);
56+
static inline uint64_t read_cycle_counter() {
57+
uint64_t cycles;
58+
asm volatile("rdcycle %0" : "=r"(cycles));
59+
return cycles;
10260
}
10361

10462

@@ -108,84 +66,108 @@ static void handle_sig(int sig) {
10866
// stores the fact that it will cause an exception until you
10967
// invalidate the entry.
11068
static void segv_handler(int sig, siginfo_t *info, void *ucontext) {
111-
printf("Caught segfault to address %p\n", info->si_addr);
69+
printf("Caught segfault to address %p. Clearing htlb and trying again!\n", info->si_addr);
11270

113-
// void *buffer[BACKTRACE_SIZE];
114-
// // Get the backtrace
115-
// int nptrs = backtrace(buffer, BACKTRACE_SIZE);
116-
// // Print the backtrace symbols
117-
// backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO);
118-
// alaska_dump_backtrace();
119-
120-
__asm__ volatile("csrw 0xc4, %0" ::"rK"((1LU << (64 - ALASKA_SIZE_BITS)) - 1) : "memory");
71+
write_csr(CSR_HTINVAL, ((1LU << (64 - ALASKA_SIZE_BITS)) - 1));
12172
__asm__ volatile("fence" ::: "memory");
12273
// exit(0);
12374
return;
12475
}
12576

12677

127-
static void init(void) {
128-
setvbuf(stdout, stdout_buf, _IOLBF, BUFSIZ);
129-
setvbuf(stderr, stderr_buf, _IOLBF, BUFSIZ);
78+
static pthread_t yukon_dump_daemon_thread;
79+
static void *yukon_dump_daemon(void *) {
80+
auto *tc = yukon::get_tc();
81+
while (1) {
82+
// Sleep
13083

131-
alaska::Configuration config;
132-
// Use the "malloc" backend to operate cleanly w/ libc's malloc
133-
config.huge_strategy = alaska::HugeAllocationStrategy::CUSTOM_MMAP_BACKED;
84+
auto start = read_cycle_counter();
85+
usleep(10 * 1000);
86+
auto end = read_cycle_counter();
87+
printf("Slept for %lu cycles\n", end - start);
88+
yukon::dump_htlb(tc);
89+
}
13490

135-
the_runtime = new alaska::Runtime(config);
136-
void *handle_table_base = the_runtime->handle_table.get_base();
137-
// printf("Handle table at %p\n", handle_table_base);
138-
// Make sure the handle table performs mlocks
139-
the_runtime->handle_table.enable_mlock();
91+
return NULL;
92+
}
14093

141-
asm volatile("fence" ::: "memory");
142-
set_ht_addr(handle_table_base);
14394

144-
struct sigaction act = {0};
145-
act.sa_sigaction = segv_handler;
146-
act.sa_flags = SA_SIGINFO;
147-
sigaction(SIGSEGV, &act, NULL);
14895

14996

150-
// signal(SIGABRT, handle_sig);
151-
// signal(SIGSEGV, handle_sig);
152-
// signal(SIGBUS, handle_sig);
153-
// signal(SIGILL, handle_sig);
154-
}
97+
namespace yukon {
98+
void set_handle_table_base(void *addr) {
99+
alaska::printf("set htbase to %p\n", addr);
100+
uint64_t value = (uint64_t)addr;
101+
if (value != 0 and getenv("YUKON_PHYS") != nullptr) {
102+
value |= (1LU << 63);
103+
}
104+
write_csr(CSR_HTBASE, value);
105+
}
155106

156107

157108

158109

159-
static alaska::ThreadCache *get_tc() {
160-
if (the_runtime == NULL) init();
161-
if (tc == NULL) tc = the_runtime->new_threadcache();
162-
return tc;
163-
}
110+
void dump_htlb(alaska::ThreadCache *tc) {
111+
auto size = 576;
112+
auto *space = tc->localizer.get_hotness_buffer(size);
113+
memset(space, 0, size * sizeof(alaska::handle_id_t));
114+
115+
asm volatile("fence" ::: "memory");
116+
117+
auto start = read_cycle_counter();
118+
write_csr(CSR_HTDUMP, (uint64_t)space);
119+
wait_for_csr_zero(CSR_HTDUMP);
120+
auto end = read_cycle_counter();
121+
asm volatile("fence" ::: "memory");
122+
tc->localizer.feed_hotness_buffer(size, space);
123+
asm volatile("fence" ::: "memory");
124+
printf("Dumping htlb took %lu cycles\n", end - start);
125+
}
164126

127+
alaska::ThreadCache *get_tc() {
128+
if (the_runtime == NULL) init();
129+
if (tc == NULL) tc = the_runtime->new_threadcache();
130+
return tc;
131+
}
165132

166-
static void dump_htlb() {
167-
auto tc = get_tc();
168-
auto size = 576;
169-
auto *space = tc->localizer.get_hotness_buffer(size);
170-
memset(space, 0, size * sizeof(alaska::handle_id_t));
171133

172-
asm volatile("fence" ::: "memory");
134+
static char stdout_buf[BUFSIZ];
135+
static char stderr_buf[BUFSIZ];
136+
void init(void) {
137+
setvbuf(stdout, stdout_buf, _IOLBF, BUFSIZ);
138+
setvbuf(stderr, stderr_buf, _IOLBF, BUFSIZ);
139+
140+
alaska::Configuration config;
141+
// Use the "malloc" backend to operate cleanly w/ libc's malloc
142+
config.huge_strategy = alaska::HugeAllocationStrategy::CUSTOM_MMAP_BACKED;
143+
144+
the_runtime = new alaska::Runtime(config);
145+
void *handle_table_base = the_runtime->handle_table.get_base();
146+
// printf("Handle table at %p\n", handle_table_base);
147+
// Make sure the handle table performs mlocks
148+
the_runtime->handle_table.enable_mlock();
149+
150+
asm volatile("fence" ::: "memory");
151+
yukon::set_handle_table_base(handle_table_base);
152+
153+
struct sigaction act = {0};
154+
act.sa_sigaction = segv_handler;
155+
act.sa_flags = SA_SIGINFO;
156+
sigaction(SIGSEGV, &act, NULL);
157+
158+
pthread_create(&yukon_dump_daemon_thread, NULL, yukon_dump_daemon, NULL);
159+
}
160+
} // namespace yukon
173161

174-
write_csr(0xc3, (uint64_t)space);
175-
wait_for_csr_zero();
176-
asm volatile("fence" ::: "memory");
177-
tc->localizer.feed_hotness_buffer(size, space);
178-
asm volatile("fence" ::: "memory");
179-
}
180162

181163

182164
void __attribute__((constructor(102))) alaska_init(void) {
183165
unsetenv("LD_PRELOAD"); // make it so we don't run alaska in subprocesses!
184-
get_tc();
166+
yukon::get_tc();
185167

186168
atexit([]() {
187169
printf("Setting ht addr to zero!\n");
188-
set_ht_addr(0);
170+
yukon::set_handle_table_base(NULL);
189171
printf("set!\n");
190172
});
191173
}
@@ -195,32 +177,22 @@ void __attribute__((destructor)) alaska_deinit(void) {}
195177
static void *_halloc(size_t sz, int zero) {
196178
// HACK: make it so we *always* zero the data to avoid pagefaults
197179
// *this is slow*
198-
zero = 1;
180+
// zero = 1;
199181
void *result = NULL;
200182

201-
result = get_tc()->halloc(sz, zero);
183+
result = yukon::get_tc()->halloc(sz, zero);
202184
auto m = (uintptr_t)alaska::Mapping::translate(result);
203185
if (result == NULL) errno = ENOMEM;
204186

205-
// dump_htlb();
206-
207-
208187
return result;
209188
}
210189

211-
212-
// #define halloc malloc
213-
// #define hcalloc calloc
214-
// #define hrealloc realloc
215-
// #define hfree free
216-
217190
extern "C" void *halloc(size_t sz) noexcept { return _halloc(sz, 0); }
218-
219191
extern "C" void *hcalloc(size_t nmemb, size_t size) { return _halloc(nmemb * size, 1); }
220192

221193
// Reallocate a handle
222194
extern "C" void *hrealloc(void *handle, size_t new_size) {
223-
auto *tc = get_tc();
195+
auto *tc = yukon::get_tc();
224196

225197
// If the handle is null, then this call is equivalent to malloc(size)
226198
if (handle == NULL) {
@@ -251,13 +223,11 @@ extern "C" void *hrealloc(void *handle, size_t new_size) {
251223
extern "C" void hfree(void *ptr) {
252224
// no-op if NULL is passed
253225
if (unlikely(ptr == NULL)) return;
254-
255-
// Simply ask the thread cache to free it!
256-
get_tc()->hfree(ptr);
226+
yukon::get_tc()->hfree(ptr);
257227
}
258228

259229

260-
extern "C" size_t halloc_usable_size(void *ptr) { return get_tc()->get_size(ptr); }
230+
extern "C" size_t halloc_usable_size(void *ptr) { return yukon::get_tc()->get_size(ptr); }
261231

262232

263233

0 commit comments

Comments
 (0)