Skip to content

Commit 0c3bd27

Browse files
committed
runtime: Cache asc_type_id results on ValidModule
Every WASM heap allocation (API version > 0.0.4) called asc_type_id(), which did a call_async into the WASM module for a trivial idof<T>() switch. The result is deterministic per compiled module, yet every allocation paid ~200-500ns of call_async overhead (fiber creation, epoch checking, context switching). Cache the results on ValidModule using a parking_lot::RwLock<HashMap>, so after the first trigger warms the cache, all subsequent lookups are cheap read-lock hits. Lock guards never span .await points.
1 parent e716825 commit 0c3bd27

File tree

5 files changed

+39
-12
lines changed

5 files changed

+39
-12
lines changed

graph/src/runtime/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl_asc_type!(u8, u16, u32, u64, i8, i32, i64, f32, f64);
157157
/// 3. Once defined, items and their discriminants cannot be changed, as this would break running
158158
/// subgraphs compiled in previous versions of this representation.
159159
#[repr(u32)]
160-
#[derive(Copy, Clone, Debug)]
160+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
161161
pub enum IndexForAscTypeId {
162162
// Ethereum type IDs
163163
String = 0,

runtime/test/src/test.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ async fn json_conversions_v0_0_4() {
401401

402402
#[graph::test]
403403
async fn json_conversions_v0_0_5() {
404-
test_json_conversions(API_VERSION_0_0_5, 2289897).await;
404+
test_json_conversions(API_VERSION_0_0_5, 2214813).await;
405405
}
406406

407407
async fn test_json_parsing(api_version: Version, gas_used: u64) {
@@ -766,7 +766,7 @@ async fn big_int_to_hex_v0_0_4() {
766766

767767
#[graph::test]
768768
async fn big_int_to_hex_v0_0_5() {
769-
test_big_int_to_hex(API_VERSION_0_0_5, 2858580).await;
769+
test_big_int_to_hex(API_VERSION_0_0_5, 2565990).await;
770770
}
771771

772772
async fn test_big_int_arithmetic(api_version: Version, gas_used: u64) {
@@ -832,7 +832,7 @@ async fn big_int_arithmetic_v0_0_4() {
832832

833833
#[graph::test]
834834
async fn big_int_arithmetic_v0_0_5() {
835-
test_big_int_arithmetic(API_VERSION_0_0_5, 7318364).await;
835+
test_big_int_arithmetic(API_VERSION_0_0_5, 5256825).await;
836836
}
837837

838838
async fn test_abort(api_version: Version, error_msg: &str) {
@@ -970,7 +970,7 @@ async fn data_source_create_v0_0_4() {
970970

971971
#[graph::test]
972972
async fn data_source_create_v0_0_5() {
973-
test_data_source_create(API_VERSION_0_0_5, 101450079).await;
973+
test_data_source_create(API_VERSION_0_0_5, 101425051).await;
974974
}
975975

976976
async fn test_ens_name_by_hash(api_version: Version) {
@@ -1827,5 +1827,5 @@ async fn yaml_parsing_v0_0_4() {
18271827

18281828
#[graph::test]
18291829
async fn yaml_parsing_v0_0_5() {
1830-
test_yaml_parsing(API_VERSION_0_0_5, 1053955992265).await;
1830+
test_yaml_parsing(API_VERSION_0_0_5, 1053946160531).await;
18311831
}

runtime/test/src/test/abi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ async fn abi_array_v0_0_4() {
117117

118118
#[graph::test]
119119
async fn abi_array_v0_0_5() {
120-
test_abi_array(API_VERSION_0_0_5, 1636130).await;
120+
test_abi_array(API_VERSION_0_0_5, 1561046).await;
121121
}
122122

123123
async fn test_abi_subarray(api_version: Version) {

runtime/wasm/src/mapping.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use graph::data_source::{MappingTrigger, TriggerWithHandler};
77
use graph::futures01::sync::mpsc;
88
use graph::futures01::{Future as _, Stream as _};
99
use graph::futures03::channel::oneshot::Sender;
10+
use graph::parking_lot::RwLock;
1011
use graph::prelude::*;
1112
use graph::runtime::gas::Gas;
13+
use graph::runtime::IndexForAscTypeId;
1214
use parity_wasm::elements::ExportEntry;
13-
use std::collections::BTreeMap;
15+
use std::collections::{BTreeMap, HashMap};
1416
use std::panic::AssertUnwindSafe;
1517
use std::sync::atomic::{AtomicUsize, Ordering};
1618
use std::sync::Arc;
@@ -248,6 +250,10 @@ pub struct ValidModule {
248250

249251
// Used as a guard to terminate this task dependency.
250252
epoch_counter_abort_handle: Option<tokio::task::AbortHandle>,
253+
254+
/// Cache for asc_type_id results. Maps IndexForAscTypeId to their WASM runtime
255+
/// type IDs. Populated lazily on first use; deterministic per compiled module.
256+
asc_type_id_cache: RwLock<HashMap<IndexForAscTypeId, u32>>,
251257
}
252258

253259
impl ValidModule {
@@ -355,8 +361,17 @@ impl ValidModule {
355361
start_function,
356362
timeout,
357363
epoch_counter_abort_handle,
364+
asc_type_id_cache: RwLock::new(HashMap::new()),
358365
})
359366
}
367+
368+
pub fn get_cached_type_id(&self, idx: IndexForAscTypeId) -> Option<u32> {
369+
self.asc_type_id_cache.read().get(&idx).copied()
370+
}
371+
372+
pub fn cache_type_id(&self, idx: IndexForAscTypeId, type_id: u32) {
373+
self.asc_type_id_cache.write().insert(idx, type_id);
374+
}
360375
}
361376

362377
impl Drop for ValidModule {

runtime/wasm/src/module/mod.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,17 +368,29 @@ impl AscHeap for WasmInstanceContext<'_> {
368368
&mut self,
369369
type_id_index: IndexForAscTypeId,
370370
) -> Result<u32, HostExportError> {
371+
// Check the module-level cache. Lives on ValidModule (Arc-shared, persists
372+
// across all triggers for this subgraph module).
373+
if let Some(type_id) = self.as_ref().valid_module.get_cached_type_id(type_id_index) {
374+
return Ok(type_id);
375+
}
376+
377+
// Cache miss: call into WASM.
371378
let asc_heap = self.asc_heap().cheap_clone();
372379
let func = asc_heap.id_of_type.as_ref().unwrap();
373-
374-
// Unwrap ok because it's only called on correct apiVersion, look for AscPtr::generate_header
375-
func.call_async(self.as_context_mut(), type_id_index as u32)
380+
let type_id = func
381+
.call_async(self.as_context_mut(), type_id_index as u32)
376382
.await
377383
.map_err(|trap| {
378384
host_export_error_from_trap(
379385
trap,
380386
format!("Failed to call 'asc_type_id' with '{:?}'", type_id_index),
381387
)
382-
})
388+
})?;
389+
390+
// Store for all future triggers.
391+
self.as_ref()
392+
.valid_module
393+
.cache_type_id(type_id_index, type_id);
394+
Ok(type_id)
383395
}
384396
}

0 commit comments

Comments
 (0)