Skip to content

Performance Improvement: Replacing get_interned_obj_prop with get_obj_prop#214

Draft
adampetro wants to merge 1 commit intomainfrom
ap.explore-removing-string-interning
Draft

Performance Improvement: Replacing get_interned_obj_prop with get_obj_prop#214
adampetro wants to merge 1 commit intomainfrom
ap.explore-removing-string-interning

Conversation

@adampetro
Copy link
Contributor

Summary

Benchmarking revealed that using get_obj_prop instead of get_interned_obj_prop for property access in generated code results in a ~19% reduction in instruction count across all tested scenarios.

Background

The shopify_function_macro generates accessor methods for struct fields when processing GraphQL queries. Previously, these accessors used interned string lookups (get_interned_obj_prop) with the assumption that caching string IDs would improve performance for repeated property accesses.

Previous Implementation

pub fn field_name(&self) -> FieldType {
    static INTERNED_FIELD_NAME: CachedInternedStringId = CachedInternedStringId::new("fieldName");
    let interned_string_id = INTERNED_FIELD_NAME.load();

    let value = self.field_name.get_or_init(|| {
        let value = self.__wasm_value.get_interned_obj_prop(interned_string_id);
        Deserialize::deserialize(&value).unwrap()
    });
    // ...
}

New Implementation

pub fn field_name(&self) -> FieldType {
    let value = self.field_name.get_or_init(|| {
        let value = self.__wasm_value.get_obj_prop("fieldName");
        Deserialize::deserialize(&value).unwrap()
    });
    // ...
}

Benchmark Results

Tests were run using the integration_tests crate with function-runner to measure instruction counts.

Test Cases

Test Description
target_a Simple function with no input property access
target_b Function with single property access (input.id())
target_cart Function iterating over 100 cart lines, accessing quantity on each

Instruction Counts

Test get_interned_obj_prop get_obj_prop Difference % Change
target_a 4,582 4,552 -30 -0.7%
target_b 9,631 7,874 -1,757 -18.2%
target_cart (100 iterations) 364,059 293,994 -70,065 -19.2%

Memory Usage

Memory usage remained constant at 1,152 bytes across all tests for both implementations.

Analysis

The interned string approach was expected to provide benefits when the same property name is accessed multiple times (e.g., in loops). However, benchmarking showed the opposite:

The overhead of interned string caching exceeds its benefits in all tested scenarios.

The overhead comes from:

  1. Static variable access: Loading from CachedInternedStringId static
  2. Interning lookup: Calling .load() to retrieve the interned ID
  3. Provider function overhead: The get_interned_obj_prop provider call itself

Even with 100 iterations accessing the same property (quantity), the direct string-based get_obj_prop approach is ~19% faster.

Conclusion

The simpler get_obj_prop implementation:

  • Reduces instruction count by ~19%
  • Simplifies generated code
  • Removes dependency on CachedInternedStringId

This change has been applied to the shopify_function_macro crate.

Reproducing the Benchmark

Run the integration tests with output:

cargo test -p integration_tests -- --nocapture

The test output includes instruction counts and memory usage for each test case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant