Skip to content

Commit

Permalink
Merge branch 'master' into inputs-wiring
Browse files Browse the repository at this point in the history
  • Loading branch information
eljobe committed Sep 28, 2024
2 parents faed5a9 + 4a93769 commit e20d793
Show file tree
Hide file tree
Showing 33 changed files with 443 additions and 78 deletions.
19 changes: 3 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,12 @@ jobs:
uses: actions/cache@v3
with:
path: |
~/.cargo/registry/
~/.cargo/git/
~/.cargo/
arbitrator/target/
arbitrator/wasm-libraries/target/
arbitrator/wasm-libraries/soft-float/SoftFloat/build
arbitrator/wasm-libraries/soft-float/
target/etc/initial-machine-cache/
/home/runner/.rustup/toolchains/
key: ${{ runner.os }}-cargo-${{ steps.install-rust.outputs.rustc_hash }}-min-${{ hashFiles('arbitrator/Cargo.lock') }}-${{ matrix.test-mode }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.install-rust.outputs.rustc_hash }}-

Expand Down Expand Up @@ -166,19 +166,6 @@ jobs:
fi
done
- name: run tests with race detection and path state scheme
if: matrix.test-mode == 'race'
env:
TEST_STATE_SCHEME: path
run: |
packages=`go list ./...`
for package in $packages; do
echo running tests for $package
if ! stdbuf -oL gotestsum --format short-verbose --packages="$package" --rerun-fails=2 --no-color=false -- -race -timeout 30m > >(stdbuf -oL tee -a full.log | grep -vE "INFO|seal"); then
exit 1
fi
done
- name: run tests with race detection and hash state scheme
if: matrix.test-mode == 'race'
env:
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Additional Use Grant: You may use the Licensed Work in a production environment
Expansion Program Term of Use](https://docs.arbitrum.foundation/assets/files/Arbitrum%20Expansion%20Program%20Jan182024-4f08b0c2cb476a55dc153380fa3e64b0.pdf). For purposes of this
Additional Use Grant, the "Covered Arbitrum Chains" are
(a) Arbitrum One (chainid:42161), Arbitrum Nova (chainid:42170),
rbitrum Rinkeby testnet/Rinkarby (chainid:421611),Arbitrum Nitro
Arbitrum Rinkeby testnet/Rinkarby (chainid:421611),Arbitrum Nitro
Goerli testnet (chainid:421613), and Arbitrum Sepolia Testnet
(chainid:421614); (b) any future blockchains authorized to be
designated as Covered Arbitrum Chains by the decentralized autonomous
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ clean:
rm -f arbitrator/wasm-libraries/soft-float/SoftFloat/build/Wasm-Clang/*.a
rm -f arbitrator/wasm-libraries/forward/*.wat
rm -rf arbitrator/stylus/tests/*/target/ arbitrator/stylus/tests/*/*.wasm
rm -rf brotli/buildfiles
@rm -rf contracts/build contracts/cache solgen/go/
@rm -f .make/*

Expand Down
2 changes: 1 addition & 1 deletion arbcompress/native.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
package arbcompress

/*
#cgo CFLAGS: -g -Wall -I${SRCDIR}/../target/include/
#cgo CFLAGS: -g -I${SRCDIR}/../target/include/
#cgo LDFLAGS: ${SRCDIR}/../target/lib/libstylus.a -lm
#include "arbitrator.h"
*/
Expand Down
8 changes: 7 additions & 1 deletion arbitrator/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions arbitrator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ repository = "https://github.com/OffchainLabs/nitro.git"
rust-version = "1.67"

[workspace.dependencies]
cfg-if = "1.0.0"
lazy_static = "1.4.0"
lru = "0.12.3"
num_enum = { version = "0.7.2", default-features = false }
ruint2 = "1.9.0"
wasmparser = "0.121"
Expand Down
7 changes: 4 additions & 3 deletions arbitrator/arbutil/src/evm/req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,10 @@ impl<D: DataReader, H: RequestHandler<D>> EvmApi<D> for EvmApiRequestor<D, H> {
let mut request = Vec::with_capacity(2 * 8 + 3 * 2 + name.len() + args.len() + outs.len());
request.extend(start_ink.to_be_bytes());
request.extend(end_ink.to_be_bytes());
request.extend((name.len() as u16).to_be_bytes());
request.extend((args.len() as u16).to_be_bytes());
request.extend((outs.len() as u16).to_be_bytes());
// u32 is enough to represent the slices lengths because the WASM environment runs in 32 bits.
request.extend((name.len() as u32).to_be_bytes());
request.extend((args.len() as u32).to_be_bytes());
request.extend((outs.len() as u32).to_be_bytes());
request.extend(name.as_bytes());
request.extend(args);
request.extend(outs);
Expand Down
2 changes: 1 addition & 1 deletion arbitrator/stylus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ thiserror = "1.0.33"
bincode = "1.3.3"
lazy_static.workspace = true
libc = "0.2.108"
lru.workspace = true
eyre = "0.6.5"
rand = "0.8.5"
fnv = "1.0.7"
hex = "0.4.3"
clru = "0.6.2"

[dev-dependencies]
num-bigint = "0.4.4"
Expand Down
140 changes: 123 additions & 17 deletions arbitrator/stylus/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE

use arbutil::Bytes32;
use clru::{CLruCache, CLruCacheConfig, WeightScale};
use eyre::Result;
use lazy_static::lazy_static;
use lru::LruCache;
use parking_lot::Mutex;
use prover::programs::config::CompileConfig;
use std::hash::RandomState;
use std::{collections::HashMap, num::NonZeroUsize};
use wasmer::{Engine, Module, Store};

use crate::target_cache::target_native;

lazy_static! {
static ref INIT_CACHE: Mutex<InitCache> = Mutex::new(InitCache::new(256));
static ref INIT_CACHE: Mutex<InitCache> = Mutex::new(InitCache::new(256 * 1024 * 1024));
}

macro_rules! cache {
Expand All @@ -22,9 +23,16 @@ macro_rules! cache {
};
}

pub struct LruCounters {
pub hits: u32,
pub misses: u32,
pub does_not_fit: u32,
}

pub struct InitCache {
long_term: HashMap<CacheKey, CacheItem>,
lru: LruCache<CacheKey, CacheItem>,
lru: CLruCache<CacheKey, CacheItem, RandomState, CustomWeightScale>,
lru_counters: LruCounters,
}

#[derive(Clone, Copy, Hash, PartialEq, Eq)]
Expand All @@ -48,35 +56,83 @@ impl CacheKey {
struct CacheItem {
module: Module,
engine: Engine,
entry_size_estimate_bytes: usize,
}

impl CacheItem {
fn new(module: Module, engine: Engine) -> Self {
Self { module, engine }
fn new(module: Module, engine: Engine, entry_size_estimate_bytes: usize) -> Self {
Self {
module,
engine,
entry_size_estimate_bytes,
}
}

fn data(&self) -> (Module, Store) {
(self.module.clone(), Store::new(self.engine.clone()))
}
}

struct CustomWeightScale;
impl WeightScale<CacheKey, CacheItem> for CustomWeightScale {
fn weight(&self, _key: &CacheKey, val: &CacheItem) -> usize {
// clru defines that each entry consumes (weight + 1) of the cache capacity.
// We subtract 1 since we only want to use the weight as the size of the entry.
val.entry_size_estimate_bytes.saturating_sub(1)
}
}

#[repr(C)]
pub struct LruCacheMetrics {
pub size_bytes: u64,
pub count: u32,
pub hits: u32,
pub misses: u32,
pub does_not_fit: u32,
}

pub fn deserialize_module(
module: &[u8],
version: u16,
debug: bool,
) -> Result<(Module, Engine, usize)> {
let engine = CompileConfig::version(version, debug).engine(target_native());
let module = unsafe { Module::deserialize_unchecked(&engine, module)? };

let asm_size_estimate_bytes = module.serialize()?.len();
// add 128 bytes for the cache item overhead
let entry_size_estimate_bytes = asm_size_estimate_bytes + 128;

Ok((module, engine, entry_size_estimate_bytes))
}

impl InitCache {
// current implementation only has one tag that stores to the long_term
// future implementations might have more, but 0 is a reserved tag
// that will never modify long_term state
const ARBOS_TAG: u32 = 1;

fn new(size: usize) -> Self {
const DOES_NOT_FIT_MSG: &'static str = "Failed to insert into LRU cache, item too large";

fn new(size_bytes: usize) -> Self {
Self {
long_term: HashMap::new(),
lru: LruCache::new(NonZeroUsize::new(size).unwrap()),
lru: CLruCache::with_config(
CLruCacheConfig::new(NonZeroUsize::new(size_bytes).unwrap())
.with_scale(CustomWeightScale),
),
lru_counters: LruCounters {
hits: 0,
misses: 0,
does_not_fit: 0,
},
}
}

pub fn set_lru_size(size: u32) {
pub fn set_lru_capacity(capacity_bytes: u64) {
cache!()
.lru
.resize(NonZeroUsize::new(size.try_into().unwrap()).unwrap())
.resize(NonZeroUsize::new(capacity_bytes.try_into().unwrap()).unwrap())
}

/// Retrieves a cached value, updating items as necessary.
Expand All @@ -91,8 +147,11 @@ impl InitCache {

// See if the item is in the LRU cache, promoting if so
if let Some(item) = cache.lru.get(&key) {
return Some(item.data());
let data = item.data();
cache.lru_counters.hits += 1;
return Some(data);
}
cache.lru_counters.misses += 1;
None
}

Expand All @@ -116,20 +175,24 @@ impl InitCache {
if long_term_tag == Self::ARBOS_TAG {
cache.long_term.insert(key, item.clone());
} else {
cache.lru.promote(&key)
// only calls get to move the key to the head of the LRU list
cache.lru.get(&key);
}
return Ok(item.data());
}
drop(cache);

let engine = CompileConfig::version(version, debug).engine(target_native());
let module = unsafe { Module::deserialize_unchecked(&engine, module)? };
let (module, engine, entry_size_estimate_bytes) =
deserialize_module(module, version, debug)?;

let item = CacheItem::new(module, engine);
let item = CacheItem::new(module, engine, entry_size_estimate_bytes);
let data = item.data();
let mut cache = cache!();
if long_term_tag != Self::ARBOS_TAG {
cache.lru.put(key, item);
if cache.lru.put_with_weight(key, item).is_err() {
cache.lru_counters.does_not_fit += 1;
eprintln!("{}", Self::DOES_NOT_FIT_MSG);
};
} else {
cache.long_term.insert(key, item);
}
Expand All @@ -144,7 +207,9 @@ impl InitCache {
let key = CacheKey::new(module_hash, version, debug);
let mut cache = cache!();
if let Some(item) = cache.long_term.remove(&key) {
cache.lru.put(key, item);
if cache.lru.put_with_weight(key, item).is_err() {
eprintln!("{}", Self::DOES_NOT_FIT_MSG);
}
}
}

Expand All @@ -155,7 +220,48 @@ impl InitCache {
let mut cache = cache!();
let cache = &mut *cache;
for (key, item) in cache.long_term.drain() {
cache.lru.put(key, item); // not all will fit, just a heuristic
// not all will fit, just a heuristic
if cache.lru.put_with_weight(key, item).is_err() {
eprintln!("{}", Self::DOES_NOT_FIT_MSG);
}
}
}

pub fn get_lru_metrics() -> LruCacheMetrics {
let mut cache = cache!();

let count = cache.lru.len();
let metrics = LruCacheMetrics {
// add 1 to each entry to account that we subtracted 1 in the weight calculation
size_bytes: (cache.lru.weight() + count).try_into().unwrap(),

count: count.try_into().unwrap(),

hits: cache.lru_counters.hits,
misses: cache.lru_counters.misses,
does_not_fit: cache.lru_counters.does_not_fit,
};

// Empty counters.
// go side, which is the only consumer of this function besides tests,
// will read those counters and increment its own prometheus counters with them.
cache.lru_counters = LruCounters {
hits: 0,
misses: 0,
does_not_fit: 0,
};

metrics
}

// only used for testing
pub fn clear_lru_cache() {
let mut cache = cache!();
cache.lru.clear();
cache.lru_counters = LruCounters {
hits: 0,
misses: 0,
does_not_fit: 0,
};
}
}
Loading

0 comments on commit e20d793

Please sign in to comment.