Skip to content

Performance: Eliminate transaction name string operations in hot path #641

@jeremyandrews

Description

@jeremyandrews

GitHub Issue: Performance: Eliminate transaction name string operations in hot path

Problem

The current implementation performs unnecessary string operations for transaction names in the hot path, causing memory allocations and CPU overhead on every transaction invocation.

Current Implementation Issues

1. String Cloning in GooseUser

pub struct GooseUser {
    // String fields that get cloned repeatedly
    pub transaction_name: String,
    pub scenario_name: String,
    // ...
}

2. Repeated String Operations

In invoke_transaction_function():

  • Transaction names are cloned multiple times per invocation
  • String comparisons for transaction lookups
  • Unnecessary string allocations for logging/metrics

Performance Impact

  • Memory allocations: 100% elimination potential for transaction name allocations
  • CPU overhead: String cloning and comparison operations
  • GC pressure: Frequent allocation/deallocation of transaction name strings
  • Scale impact: Grows linearly with transaction execution rate

Proposed Solution

Option 1: Simple Integer Indices (Recommended - Low Complexity)

Replace string fields with simple integer indices that reference existing data structures:

pub struct GooseUser {
    // Replace String with lightweight indices into existing collections
    pub current_scenario_index: usize,        // Index into scenarios Vec
    pub current_transaction_index: usize,     // Index into transactions Vec  
    // Remove transaction_name and scenario_name fields entirely
}

// Transaction names are already stored in the GooseAttack structure:
impl GooseUser {
    fn get_current_transaction_name(&self, goose_attack: &GooseAttack) -> &str {
        // Direct reference to existing string - no allocation
        &goose_attack.scenarios[self.current_scenario_index]
            .transactions[self.current_transaction_index].name
    }
}

Option 2: Cow (Clone-on-Write) Strings

Use Cow<'static, str> to avoid cloning when possible:

use std::borrow::Cow;

pub struct GooseUser {
    pub transaction_name: Cow<'static, str>,  // Only clones when necessary
    pub scenario_name: Cow<'static, str>,
    // ...
}

Option 3: Arc for Shared Ownership (Medium Complexity)

Use Arc<str> for cheap cloning of immutable strings:

use std::sync::Arc;

pub struct GooseUser {
    pub transaction_name: Arc<str>,  // Cheap to clone, shared ownership
    pub scenario_name: Arc<str>,
    // ...
}

Recommended Approach: Simple Integer Indices

Why this is better than string interning:

  • No external dependencies - uses existing data structures
  • Zero complexity overhead - simple array indexing
  • Leverages existing architecture - GooseAttack already stores all names
  • Same performance benefits - eliminates string allocations
  • Easier to maintain - straightforward implementation

Implementation Approach

Phase 1: Structure Simplification

  1. Remove String fields from GooseUser
  2. Add index fields that reference existing collections
  3. Update constructor to use indices instead of strings

Phase 2: Hot Path Optimization

  1. Update invoke_transaction_function() to use integer operations
  2. Pass indices instead of cloning strings
  3. Only resolve strings when actually needed for logging

Phase 3: Helper Methods

  1. Add getter methods that return &str references to existing data
  2. Update logging/reporting code to use getter methods
  3. Ensure all string access goes through the existing collections

Expected Performance Gains

  • Memory reduction: 100% elimination of transaction name string allocations
  • CPU improvement: Faster integer comparisons vs string operations
  • Cache efficiency: Better memory locality with integer indices
  • Simplicity: No external dependencies or complex data structures
  • Maintainability: Uses existing GooseAttack architecture

Testing Strategy

  • Unit tests: Verify index-based lookups work correctly
  • Integration tests: Ensure transaction execution remains correct
  • Performance tests: Measure allocation reduction and CPU improvement
  • Memory profiling: Validate elimination of string allocations

Acceptance Criteria

  • GooseUser uses string indices instead of String fields
  • Transaction name operations use integer comparisons
  • 100% elimination of transaction name string allocations in hot path
  • All existing functionality preserved
  • Performance benchmarks show measurable improvement
  • Memory usage reduced for high-transaction-rate tests

Related Issues

Part of comprehensive performance optimization effort. Related to:

Additional Notes

This optimization complements the string allocation reductions in #638 by addressing a different category of string operations. Together, they should significantly reduce memory pressure in high-throughput scenarios.

Labels

  • enhancement

Priority

Priority 2 (High Impact)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions