Skip to content

Commit 2f5e037

Browse files
committed
Introduce background compilation
Given the significant runtime compilation overhead associated with performing aggressive optimizations, we have implemented a background compilation mechanism to mitigate this issue. When the runtime profiler identifies a strong hotspot, it adds a T2C compilation request to the wait queue. A background thread, which continuously monitors this queue, triggers T2C to process the requests and notifies the main thread upon completion by updating a flag. This mechanism defers the execution of T2C-generated machine code, leading to more frequent use of T1C-generated code. Despite this, the approach effectively minimizes runtime compilation delays by eliminating the need for the main thread to wait for T2C compilation to complete, thereby improving overall performance. Close: #239
1 parent dd9fcca commit 2f5e037

File tree

4 files changed

+66
-8
lines changed

4 files changed

+66
-8
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ jobs:
134134
run: |
135135
sudo apt-get update -q -y
136136
sudo apt-get install -q -y clang clang-tools libsdl2-dev libsdl2-mixer-dev
137+
wget https://apt.llvm.org/llvm.sh
138+
chmod +x ./llvm.sh
139+
sudo ./llvm.sh 17
137140
shell: bash
138141
- name: run scan-build without JIT
139142
run: make distclean && scan-build -v -o ~/scan-build --status-bugs --use-cc=clang --force-analyze-debug-code --show-description -analyzer-config stable-report-filename=true -enable-checker valist,nullability make ENABLE_EXT_F=0 ENABLE_SDL=0 ENABLE_JIT=0

src/emulate.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ static block_t *block_alloc(riscv_t *rv)
308308
block->has_loops = false;
309309
block->n_invoke = 0;
310310
INIT_LIST_HEAD(&block->list);
311+
#if RV32_HAS(T2C)
312+
block->compiled = false;
313+
#endif
311314
#endif
312315
return block;
313316
}
@@ -991,13 +994,14 @@ void rv_step(void *arg)
991994
((exec_t2c_func_t) block->func)(rv);
992995
prev = NULL;
993996
continue;
994-
} /* check if the execution path is strong hotspot */
995-
if (block->n_invoke >= THRESHOLD) {
996-
t2c_compile(block,
997-
(uint64_t) ((memory_t *) PRIV(rv)->mem)->mem_base);
998-
((exec_t2c_func_t) block->func)(rv);
999-
prev = NULL;
1000-
continue;
997+
} /* check if invoking times of t1 generated code exceed threshold */
998+
else if (!block->compiled && block->n_invoke >= THRESHOLD) {
999+
block->compiled = true;
1000+
queue_entry_t *entry = malloc(sizeof(queue_entry_t));
1001+
entry->block = block;
1002+
pthread_mutex_lock(&rv->wait_queue_lock);
1003+
list_add(&entry->list, &rv->wait_queue);
1004+
pthread_mutex_unlock(&rv->wait_queue_lock);
10011005
}
10021006
#endif
10031007
/* executed through the tier-1 JIT compiler */

src/riscv.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "riscv_private.h"
2929
#include "utils.h"
3030
#if RV32_HAS(JIT)
31+
#include <pthread.h>
32+
3133
#include "cache.h"
3234
#include "jit.h"
3335
#define CODE_CACHE_SIZE (4 * 1024 * 1024)
@@ -184,6 +186,31 @@ IO_HANDLER_IMPL(byte, write_b, W)
184186
#undef R
185187
#undef W
186188

189+
#if RV32_HAS(JIT) && RV32_HAS(T2C)
190+
static pthread_t t2c_thread;
191+
static void *t2c_routine(void *arg)
192+
{
193+
riscv_t *rv = (riscv_t *) arg;
194+
while (1) {
195+
if (!list_empty(&rv->wait_queue)) {
196+
queue_entry_t *entry =
197+
list_last_entry(&rv->wait_queue, queue_entry_t, list);
198+
pthread_mutex_lock(&rv->wait_queue_lock);
199+
list_del_init(&entry->list);
200+
pthread_mutex_unlock(&rv->wait_queue_lock);
201+
t2c_compile(entry->block,
202+
(uint64_t) ((memory_t *) PRIV(rv)->mem)->mem_base);
203+
free(entry);
204+
}
205+
/* Instead of writing while(rv->exit), placing the code here prevents
206+
* rv->exit from being optimized by the compiler.*/
207+
if (rv->exit)
208+
break;
209+
}
210+
return NULL;
211+
}
212+
#endif
213+
187214
riscv_t *rv_create(riscv_user_t rv_attr)
188215
{
189216
assert(rv_attr);
@@ -269,6 +296,10 @@ riscv_t *rv_create(riscv_user_t rv_attr)
269296
rv->jit_state = jit_state_init(CODE_CACHE_SIZE);
270297
rv->block_cache = cache_create(BLOCK_MAP_CAPACITY_BITS);
271298
assert(rv->block_cache);
299+
rv->exit = false;
300+
pthread_mutex_init(&rv->wait_queue_lock, NULL);
301+
INIT_LIST_HEAD(&rv->wait_queue);
302+
pthread_create(&t2c_thread, NULL, t2c_routine, rv);
272303
#endif
273304

274305
return rv;
@@ -353,6 +384,9 @@ void rv_delete(riscv_t *rv)
353384
memory_delete(attr->mem);
354385
block_map_destroy(rv);
355386
#else
387+
rv->exit = true;
388+
pthread_join(t2c_thread, NULL);
389+
pthread_mutex_destroy(&rv->wait_queue_lock);
356390
mpool_destroy(rv->chain_entry_mp);
357391
jit_state_exit(rv->jit_state);
358392
cache_free(rv->block_cache);

src/riscv_private.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#include "riscv.h"
1515
#include "utils.h"
1616
#if RV32_HAS(JIT)
17+
#if RV32_HAS(T2C)
18+
#include <pthread.h>
19+
#endif
1720
#include "cache.h"
1821
#endif
1922

@@ -70,7 +73,10 @@ typedef struct block {
7073
bool
7174
translatable; /**< Determine the block has RV32AF insturctions or not */
7275
bool has_loops; /**< Determine the block has loop or not */
73-
uint32_t offset; /**< The machine code offset in T1 code cache */
76+
#if RV32_HAS(T2C)
77+
bool compiled; /**< The T2C request is enqueued or not */
78+
#endif
79+
uint32_t offset; /**< The machine code offset in T1 code cache */
7480
uint32_t n_invoke; /**< The invoking times of T1 machine code */
7581
void *func; /**< The function pointer of T2 machine code */
7682
struct list_head list;
@@ -82,6 +88,12 @@ typedef struct {
8288
block_t *block;
8389
struct list_head list;
8490
} chain_entry_t;
91+
#if RV32_HAS(T2C)
92+
typedef struct {
93+
block_t *block;
94+
struct list_head list;
95+
} queue_entry_t;
96+
#endif
8597
#endif
8698

8799
typedef struct {
@@ -134,6 +146,11 @@ struct riscv_internal {
134146
#else
135147
struct cache *block_cache;
136148
struct mpool *chain_entry_mp;
149+
#if RV32_HAS(T2C)
150+
struct list_head wait_queue;
151+
pthread_mutex_t wait_queue_lock;
152+
bool quit; /**< Determine the main thread is terminated or not */
153+
#endif
137154
#endif
138155
struct mpool *block_mp, *block_ir_mp;
139156

0 commit comments

Comments
 (0)