about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAspen Smith <root@gws.fyi>2024-07-28T16·36-0400
committeraspen <root@gws.fyi>2024-08-08T00·02+0000
commit6559ab4cf5bb81fcf13578da6c9978f61ea56204 (patch)
treebe77c191dfacfc1fa448af65cbb8c6a91997ce58
parent6366cee717d47dc002d874b0c3eab2182e6cf55f (diff)
feat(tvix/eval): Put interner in a thread-local RefCell r/8455
Rather than making the interner be a global lazy_static mutex, put it in
a thread-local RefCell. This doesn't change anything in terms of
sharing (since we're currently actually just single threaded), but
avoids the overhead of a mutex, for a nice performance boost (compared
to the mutex version):

hello outpath           time:   [726.71 ms 729.79 ms 735.69 ms]
                        change: [-5.7277% -3.9733% -2.1144%] (p = 0.00 < 0.05)
                        Performance has improved.

Change-Id: I240b238dcbaf854ebafc3017b4425fb7d7b91b03
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12048
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Autosubmit: aspen <root@gws.fyi>
-rw-r--r--tvix/eval/src/value/string.rs17
1 files changed, 8 insertions, 9 deletions
diff --git a/tvix/eval/src/value/string.rs b/tvix/eval/src/value/string.rs
index 7fcdad413466..0365f5a9be77 100644
--- a/tvix/eval/src/value/string.rs
+++ b/tvix/eval/src/value/string.rs
@@ -4,18 +4,17 @@
 //! level, allowing us to shave off some memory overhead and only
 //! paying the cost when creating new strings.
 use bstr::{BStr, BString, ByteSlice, Chars};
-use lazy_static::lazy_static;
 use rnix::ast;
 use rustc_hash::{FxHashMap, FxHashSet};
 use std::alloc::dealloc;
 use std::alloc::{alloc, handle_alloc_error, Layout};
 use std::borrow::{Borrow, Cow};
+use std::cell::RefCell;
 use std::ffi::c_void;
 use std::fmt::{self, Debug, Display};
 use std::hash::Hash;
 use std::ops::Deref;
 use std::ptr::{self, NonNull};
-use std::sync::Mutex;
 use std::{mem, slice};
 
 use serde::de::{Deserializer, Visitor};
@@ -423,21 +422,21 @@ impl InternerInner {
 }
 
 #[derive(Default)]
-struct Interner(Mutex<InternerInner>);
+struct Interner(RefCell<InternerInner>);
 
 impl Interner {
     pub fn intern(&self, s: &[u8]) -> NixString {
-        self.0.lock().unwrap().intern(s)
+        self.0.borrow_mut().intern(s)
     }
 
     #[cfg(feature = "no_leak")]
     pub fn is_interned_string(&self, string: &NixString) -> bool {
-        self.0.lock().unwrap().interned_strings.contains(&string.0)
+        self.0.borrow().interned_strings.contains(&string.0)
     }
 }
 
-lazy_static! {
-    static ref INTERNER: Interner = Interner::default();
+thread_local! {
+    static INTERNER: Interner = Interner::default();
 }
 
 /// Nix string values
@@ -472,7 +471,7 @@ impl Drop for NixString {
 
     #[cfg(feature = "no_leak")]
     fn drop(&mut self) {
-        if INTERNER.is_interned_string(self) {
+        if INTERNER.with(|i| i.is_interned_string(self)) {
             return;
         }
 
@@ -724,7 +723,7 @@ impl NixString {
             && contents.len() <= INTERN_THRESHOLD
             && context.is_none()
         {
-            return INTERNER.intern(contents);
+            return INTERNER.with(|i| i.intern(contents));
         }
 
         Self::new_inner(contents, context)