Skip to content

Commit 40dde4e

Browse files
committed
Revert "fix(runtime): avoid thread-local compilers"
This reverts commit 622704b.
1 parent 622704b commit 40dde4e

1 file changed

Lines changed: 94 additions & 17 deletions

File tree

crates/revmc-runtime/src/runtime/worker.rs

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use alloy_primitives::Bytes;
2020
use crossbeam_channel as chan;
2121
use rayon::{ThreadPool, ThreadPoolBuilder};
2222
#[cfg(feature = "llvm")]
23-
use std::{fs::File, io::Read, time::Instant};
23+
use std::{cell::RefCell, fs::File, io::Read, time::Instant};
2424
use std::{
2525
sync::{
2626
Arc,
@@ -188,6 +188,7 @@ impl WorkerPool {
188188
ThreadPoolBuilder::new()
189189
.num_threads(worker_count)
190190
.thread_name(|i| format!("revmc-{i:02}"))
191+
.exit_handler(|_| clear_thread_local_compilers())
191192
.build()
192193
.expect("failed to spawn compile workers")
193194
});
@@ -240,6 +241,9 @@ impl WorkerPool {
240241
/// Shuts down all workers after draining queued jobs.
241242
pub(crate) fn shutdown(&mut self) {
242243
self.shutdown.store(true, Ordering::Release);
244+
if let Some(pool) = &self.pool {
245+
pool.broadcast(|_| clear_thread_local_compilers());
246+
}
243247
self.pool.take();
244248
}
245249
}
@@ -250,9 +254,34 @@ impl Drop for WorkerPool {
250254
}
251255
}
252256

257+
#[cfg(feature = "llvm")]
258+
fn clear_thread_local_compilers() {
259+
JIT_COMPILER.with_borrow_mut(Option::take);
260+
AOT_COMPILER.with_borrow_mut(Option::take);
261+
}
262+
263+
#[cfg(not(feature = "llvm"))]
264+
fn clear_thread_local_compilers() {}
265+
253266
#[cfg(feature = "llvm")]
254267
fn compile_job(job: CompileJob, config: &RuntimeConfig) -> WorkerResult {
255268
trace!(?job, "received job");
269+
match job.kind {
270+
CompilationKind::Jit => {
271+
JIT_COMPILER.with_borrow_mut(|state| compile_with_state(job, config, state))
272+
}
273+
CompilationKind::Aot => {
274+
AOT_COMPILER.with_borrow_mut(|state| compile_with_state(job, config, state))
275+
}
276+
}
277+
}
278+
279+
#[cfg(feature = "llvm")]
280+
fn compile_with_state(
281+
job: CompileJob,
282+
config: &RuntimeConfig,
283+
state_slot: &mut Option<CompilerState>,
284+
) -> WorkerResult {
256285
let _span = match job.kind {
257286
CompilationKind::Jit => {
258287
debug_span!("jit_compile", hash=%job.key.code_hash, spec_id=?job.key.spec_id).entered()
@@ -263,21 +292,26 @@ fn compile_job(job: CompileJob, config: &RuntimeConfig) -> WorkerResult {
263292
};
264293
let t0 = Instant::now();
265294

266-
let mut compiler = match create_compiler(config, job.kind == CompilationKind::Aot) {
267-
Ok(compiler) => compiler,
268-
Err(e) => {
269-
error!(error = %e, "failed to create LLVM backend");
270-
return WorkerResult {
271-
key: job.key,
272-
outcome: Err(e),
273-
kind: job.kind,
274-
sync_notifier: job.sync_notifier,
275-
generation: job.generation,
276-
compile_duration: t0.elapsed(),
277-
timings: CompileTimings::default(),
278-
};
295+
if state_slot.is_none() {
296+
match CompilerState::new(config, job.kind) {
297+
Ok(s) => *state_slot = Some(s),
298+
Err(e) => {
299+
error!(error = %e, "failed to create LLVM backend");
300+
return WorkerResult {
301+
key: job.key,
302+
outcome: Err(e),
303+
kind: job.kind,
304+
sync_notifier: job.sync_notifier,
305+
generation: job.generation,
306+
compile_duration: t0.elapsed(),
307+
timings: CompileTimings::default(),
308+
};
309+
}
279310
}
280-
};
311+
}
312+
313+
let state = state_slot.as_mut().unwrap();
314+
let compiler = &mut state.compiler;
281315

282316
if job.kind == CompilationKind::Jit
283317
&& let Some(base) = &config.dump_dir
@@ -289,11 +323,32 @@ fn compile_job(job: CompileJob, config: &RuntimeConfig) -> WorkerResult {
289323
compiler.set_opt_level(job.opt_level);
290324

291325
let outcome = match job.kind {
292-
CompilationKind::Jit => compile_jit_artifact(&job, &mut compiler),
293-
CompilationKind::Aot => compile_aot_artifact(&job, &mut compiler),
326+
CompilationKind::Jit => compile_jit_artifact(&job, compiler),
327+
CompilationKind::Aot => compile_aot_artifact(&job, compiler),
294328
};
295329
let timings = compiler.take_timings();
296330

331+
if let Err(err) = compiler.clear_ir() {
332+
warn!(%err, "clear_ir failed");
333+
}
334+
335+
state.compilations_since_recycle += 1;
336+
if config.tuning.compiler_recycle_threshold > 0
337+
&& state.compilations_since_recycle >= config.tuning.compiler_recycle_threshold
338+
{
339+
debug!(compilations_since_recycle = state.compilations_since_recycle, "recycling compiler");
340+
match CompilerState::new(config, job.kind) {
341+
Ok(new_state) => {
342+
*state_slot = Some(new_state);
343+
revmc_llvm::global_gc();
344+
}
345+
Err(e) => {
346+
error!(error = %e, "failed to recreate compiler");
347+
state.compilations_since_recycle = 0;
348+
}
349+
}
350+
}
351+
297352
WorkerResult {
298353
key: job.key,
299354
outcome,
@@ -305,6 +360,28 @@ fn compile_job(job: CompileJob, config: &RuntimeConfig) -> WorkerResult {
305360
}
306361
}
307362

363+
#[cfg(feature = "llvm")]
364+
struct CompilerState {
365+
compiler: EvmCompiler<EvmLlvmBackend>,
366+
compilations_since_recycle: usize,
367+
}
368+
369+
#[cfg(feature = "llvm")]
370+
impl CompilerState {
371+
fn new(config: &RuntimeConfig, kind: CompilationKind) -> Result<Self, String> {
372+
Ok(Self {
373+
compiler: create_compiler(config, kind == CompilationKind::Aot)?,
374+
compilations_since_recycle: 0,
375+
})
376+
}
377+
}
378+
379+
#[cfg(feature = "llvm")]
380+
thread_local! {
381+
static JIT_COMPILER: RefCell<Option<CompilerState>> = const { RefCell::new(None) };
382+
static AOT_COMPILER: RefCell<Option<CompilerState>> = const { RefCell::new(None) };
383+
}
384+
308385
#[cfg(feature = "llvm")]
309386
fn create_compiler(
310387
config: &RuntimeConfig,

0 commit comments

Comments
 (0)