Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Oct 28, 2025

📄 9% (0.09x) speedup for fixing_table_handler in gs_quant/risk/result_handlers.py

⏱️ Runtime : 3.95 milliseconds 3.64 milliseconds (best of 434 runs)

📝 Explanation and details

The optimized code achieves an 8% speedup through two key optimizations:

1. List Comprehensions Replace Explicit Loop:
The original code used a for loop with .append() calls to build the dates and values lists. The optimized version replaces this with list comprehensions, which are implemented in C and avoid Python function call overhead for each iteration.

2. Function Reference Caching:
The optimization extracts dt.date.fromisoformat into a local variable fromisoformat before the list comprehension. This eliminates repeated attribute lookups (dt.date.fromisoformat) on every iteration, reducing overhead from Python's attribute resolution mechanism.

Performance Analysis:
The line profiler shows the optimization is most effective for larger datasets. While small test cases (single rows) show minimal improvement, the large-scale test cases demonstrate 11-16% speedups (e.g., 1000 rows: 387μs → 336μs). This pattern makes sense because:

  • List comprehensions have fixed overhead but scale better than loops
  • Attribute lookup caching provides linear savings that compound with dataset size
  • The optimization maintains identical functionality and error handling behavior

The optimization is particularly beneficial for batch processing scenarios with many fixing table rows, which appears to be the primary use case based on the test coverage.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 32 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import datetime as dt

# imports
import pytest  # used for our unit tests
from gs_quant.risk.result_handlers import fixing_table_handler


# Minimal mocks for dependencies (since we can't use gs_quant here)
class RiskKey:
    def __init__(self, name="dummy"):
        self.name = name

class InstrumentBase:
    pass

class SeriesWithInfo:
    def __init__(self, values, index, risk_key, request_id=None):
        self.values = values
        self.index = index
        self.risk_key = risk_key
        self.request_id = request_id

    def __eq__(self, other):
        # Equality check for test assertions
        return (self.values == other.values and
                self.index == other.index and
                self.risk_key.name == other.risk_key.name and
                self.request_id == other.request_id)
from gs_quant.risk.result_handlers import fixing_table_handler

# unit tests

# --- Basic Test Cases ---

def test_basic_single_row():
    """Test with a single fixing row"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01', 'fixing': 1.23}
        ]
    }
    risk_key = RiskKey("basic_test")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 108μs -> 108μs (0.590% faster)

def test_basic_multiple_rows():
    """Test with multiple fixing rows"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01', 'fixing': 1.23},
            {'fixingDate': '2024-06-02', 'fixing': 2.34},
            {'fixingDate': '2024-06-03', 'fixing': 3.45}
        ]
    }
    risk_key = RiskKey("multi_test")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 93.2μs -> 94.1μs (0.978% slower)

def test_basic_request_id():
    """Test with request_id present"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01', 'fixing': 1.23}
        ]
    }
    risk_key = RiskKey("reqid_test")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument, request_id="abc123"); output = codeflash_output # 91.3μs -> 90.7μs (0.691% faster)

# --- Edge Test Cases ---

def test_empty_fixing_table_rows():
    """Test with empty fixingTableRows"""
    result = {'fixingTableRows': []}
    risk_key = RiskKey("empty_test")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 73.1μs -> 73.6μs (0.691% slower)

def test_missing_fixingTableRows_key():
    """Test with missing fixingTableRows key (should raise KeyError)"""
    result = {}
    risk_key = RiskKey("missing_key")
    instrument = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instrument) # 761ns -> 757ns (0.528% faster)

def test_invalid_date_format():
    """Test with invalid date format (should raise ValueError)"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '06-01-2024', 'fixing': 1.23}
        ]
    }
    risk_key = RiskKey("bad_date")
    instrument = InstrumentBase()
    with pytest.raises(ValueError):
        fixing_table_handler(result, risk_key, instrument) # 2.29μs -> 2.44μs (6.39% slower)

def test_missing_fixing_key():
    """Test with missing 'fixing' key in a row (should raise KeyError)"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01'}
        ]
    }
    risk_key = RiskKey("missing_fixing")
    instrument = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instrument) # 1.74μs -> 2.19μs (20.3% slower)

def test_missing_fixingDate_key():
    """Test with missing 'fixingDate' key in a row (should raise KeyError)"""
    result = {
        'fixingTableRows': [
            {'fixing': 1.23}
        ]
    }
    risk_key = RiskKey("missing_date")
    instrument = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instrument) # 1.28μs -> 1.50μs (14.3% slower)

def test_duplicate_dates():
    """Test with duplicate fixingDates"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01', 'fixing': 1.23},
            {'fixingDate': '2024-06-01', 'fixing': 2.34}
        ]
    }
    risk_key = RiskKey("dup_date")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 135μs -> 134μs (0.525% faster)

def test_non_float_fixing():
    """Test with non-float fixing values (int, str, None)"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01', 'fixing': 42},
            {'fixingDate': '2024-06-02', 'fixing': "3.14"},
            {'fixingDate': '2024-06-03', 'fixing': None}
        ]
    }
    risk_key = RiskKey("nonfloat")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 102μs -> 100μs (2.35% faster)

def test_unordered_dates():
    """Test with dates not in order"""
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-03', 'fixing': 3.45},
            {'fixingDate': '2024-06-01', 'fixing': 1.23},
            {'fixingDate': '2024-06-02', 'fixing': 2.34}
        ]
    }
    risk_key = RiskKey("unordered")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 94.1μs -> 93.6μs (0.484% faster)

# --- Large Scale Test Cases ---

def test_large_scale_1000_rows():
    """Test with 1000 fixing rows"""
    num_rows = 1000
    result = {
        'fixingTableRows': [
            {'fixingDate': f'2024-06-{(i % 30) + 1:02d}', 'fixing': float(i)}
            for i in range(num_rows)
        ]
    }
    risk_key = RiskKey("large_test")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 391μs -> 336μs (16.1% faster)
    # Spot check a few values
    for i in [0, 499, 999]:
        expected_date = dt.date(2024, 6, (i % 30) + 1)

def test_large_scale_all_same_date():
    """Test with 1000 rows, all with the same date"""
    num_rows = 1000
    result = {
        'fixingTableRows': [
            {'fixingDate': '2024-06-01', 'fixing': float(i)}
            for i in range(num_rows)
        ]
    }
    risk_key = RiskKey("large_same_date")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 385μs -> 334μs (15.1% faster)

def test_large_scale_non_sequential_dates():
    """Test with 1000 rows, dates not sequential"""
    num_rows = 1000
    result = {
        'fixingTableRows': [
            {'fixingDate': f'2024-06-{((i * 7) % 30) + 1:02d}', 'fixing': float(i)}
            for i in range(num_rows)
        ]
    }
    risk_key = RiskKey("large_nonseq")
    instrument = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instrument); output = codeflash_output # 374μs -> 325μs (15.2% faster)
    for i in [0, 100, 999]:
        expected_date = dt.date(2024, 6, ((i * 7) % 30) + 1)

def test_large_scale_missing_some_keys():
    """Test with some rows missing keys (should raise KeyError)"""
    num_rows = 100
    rows = []
    for i in range(num_rows):
        if i % 10 == 0:
            rows.append({'fixingDate': f'2024-06-{(i % 30) + 1:02d}'})  # missing 'fixing'
        else:
            rows.append({'fixingDate': f'2024-06-{(i % 30) + 1:02d}', 'fixing': float(i)})
    result = {'fixingTableRows': rows}
    risk_key = RiskKey("large_missing")
    instrument = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instrument) # 1.85μs -> 6.69μs (72.3% slower)

def test_large_scale_invalid_dates():
    """Test with some rows having invalid date format (should raise ValueError)"""
    num_rows = 100
    rows = []
    for i in range(num_rows):
        if i % 10 == 0:
            rows.append({'fixingDate': f'06-{(i % 30) + 1:02d}-2024', 'fixing': float(i)})  # invalid format
        else:
            rows.append({'fixingDate': f'2024-06-{(i % 30) + 1:02d}', 'fixing': float(i)})
    result = {'fixingTableRows': rows}
    risk_key = RiskKey("large_invalid_date")
    instrument = InstrumentBase()
    with pytest.raises(ValueError):
        fixing_table_handler(result, risk_key, instrument) # 1.97μs -> 2.12μs (7.44% slower)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import datetime as dt

# imports
import pytest  # used for our unit tests
from gs_quant.risk.result_handlers import fixing_table_handler


# Mocks for gs_quant dependencies
class RiskKey:
    def __init__(self, key_id=None):
        self.key_id = key_id

class InstrumentBase:
    pass

class SeriesWithInfo:
    def __init__(self, values, index=None, risk_key=None, request_id=None):
        self.values = values
        self.index = index
        self.risk_key = risk_key
        self.request_id = request_id

    def __eq__(self, other):
        # Used for test equality
        return (isinstance(other, SeriesWithInfo) and
                self.values == other.values and
                self.index == other.index and
                self.risk_key == other.risk_key and
                self.request_id == other.request_id)
from gs_quant.risk.result_handlers import fixing_table_handler

# unit tests

# --- Basic Test Cases ---

def test_basic_single_row():
    # Test with a single fixing row
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01", "fixing": 1.23}
        ]
    }
    risk_key = RiskKey("rk1")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 125μs -> 127μs (0.930% slower)

def test_basic_multiple_rows():
    # Test with multiple rows
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01", "fixing": 1.23},
            {"fixingDate": "2024-01-02", "fixing": 2.34},
            {"fixingDate": "2024-01-03", "fixing": 3.45}
        ]
    }
    risk_key = RiskKey("rk2")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 99.7μs -> 99.3μs (0.366% faster)

def test_basic_with_request_id():
    # Test with request_id provided
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01", "fixing": 1.23}
        ]
    }
    risk_key = RiskKey("rk3")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr, request_id="req123"); output = codeflash_output # 93.0μs -> 93.0μs (0.003% faster)

# --- Edge Test Cases ---

def test_edge_empty_rows():
    # Test with empty fixingTableRows
    result = {
        "fixingTableRows": []
    }
    risk_key = RiskKey("rk_empty")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 73.6μs -> 74.0μs (0.617% slower)

def test_edge_missing_fixingTableRows_key():
    # Test with missing 'fixingTableRows' key
    result = {}
    risk_key = RiskKey("rk_missing")
    instr = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instr) # 769ns -> 736ns (4.48% faster)

def test_edge_missing_fixingDate_in_row():
    # Test with missing 'fixingDate' in a row
    result = {
        "fixingTableRows": [
            {"fixing": 1.23}
        ]
    }
    risk_key = RiskKey("rk_missing_fd")
    instr = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instr) # 1.53μs -> 1.65μs (6.74% slower)

def test_edge_missing_fixing_in_row():
    # Test with missing 'fixing' in a row
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01"}
        ]
    }
    risk_key = RiskKey("rk_missing_fixing")
    instr = InstrumentBase()
    with pytest.raises(KeyError):
        fixing_table_handler(result, risk_key, instr) # 1.79μs -> 2.18μs (17.9% slower)

def test_edge_invalid_date_format():
    # Test with invalid date format
    result = {
        "fixingTableRows": [
            {"fixingDate": "01-01-2024", "fixing": 1.23}
        ]
    }
    risk_key = RiskKey("rk_invalid_date")
    instr = InstrumentBase()
    with pytest.raises(ValueError):
        fixing_table_handler(result, risk_key, instr) # 2.17μs -> 2.23μs (2.56% slower)

def test_edge_non_float_fixing():
    # Test with non-float fixing value (e.g., string)
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01", "fixing": "not_a_number"}
        ]
    }
    risk_key = RiskKey("rk_non_float")
    instr = InstrumentBase()
    # Should not raise, but the value is kept as-is
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 126μs -> 126μs (0.187% faster)

def test_edge_duplicate_dates():
    # Test with duplicate fixingDate values
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01", "fixing": 1.23},
            {"fixingDate": "2024-01-01", "fixing": 2.34}
        ]
    }
    risk_key = RiskKey("rk_dup_date")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 112μs -> 112μs (0.208% faster)

def test_edge_unordered_dates():
    # Test with unordered fixingDate values
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-03", "fixing": 3.45},
            {"fixingDate": "2024-01-01", "fixing": 1.23},
            {"fixingDate": "2024-01-02", "fixing": 2.34}
        ]
    }
    risk_key = RiskKey("rk_unordered")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 93.8μs -> 94.6μs (0.879% slower)

def test_edge_varied_types():
    # Test with mixed types in fixing values
    result = {
        "fixingTableRows": [
            {"fixingDate": "2024-01-01", "fixing": 1},
            {"fixingDate": "2024-01-02", "fixing": 2.5},
            {"fixingDate": "2024-01-03", "fixing": None}
        ]
    }
    risk_key = RiskKey("rk_types")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 92.8μs -> 92.0μs (0.860% faster)

# --- Large Scale Test Cases ---

def test_large_scale_1000_rows():
    # Test with 1000 rows
    rows = []
    for i in range(1000):
        date_str = f"2024-01-{(i % 31) + 1:02d}"
        rows.append({"fixingDate": date_str, "fixing": float(i)})
    result = {"fixingTableRows": rows}
    risk_key = RiskKey("rk_large")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 387μs -> 336μs (15.3% faster)

def test_large_scale_all_same_date():
    # Test with 500 rows, all same date
    rows = [{"fixingDate": "2024-01-01", "fixing": float(i)} for i in range(500)]
    result = {"fixingTableRows": rows}
    risk_key = RiskKey("rk_large_same_date")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 257μs -> 230μs (11.7% faster)

def test_large_scale_all_same_fixing():
    # Test with 500 rows, all same fixing value
    rows = [{"fixingDate": f"2024-01-{(i % 31) + 1:02d}", "fixing": 42.0} for i in range(500)]
    result = {"fixingTableRows": rows}
    risk_key = RiskKey("rk_large_same_fixing")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 249μs -> 218μs (14.0% faster)

def test_large_scale_varied_types():
    # Test with 1000 rows, alternating types
    rows = []
    for i in range(1000):
        date_str = f"2024-01-{(i % 31) + 1:02d}"
        fixing = i if i % 2 == 0 else str(i)
        rows.append({"fixingDate": date_str, "fixing": fixing})
    result = {"fixingTableRows": rows}
    risk_key = RiskKey("rk_large_varied_types")
    instr = InstrumentBase()
    codeflash_output = fixing_table_handler(result, risk_key, instr); output = codeflash_output # 367μs -> 316μs (16.1% faster)
    for i in range(1000):
        if i % 2 == 0:
            pass
        else:
            pass
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-fixing_table_handler-mhb364ml and push.

Codeflash

The optimized code achieves an 8% speedup through two key optimizations:

**1. List Comprehensions Replace Explicit Loop:**
The original code used a `for` loop with `.append()` calls to build the `dates` and `values` lists. The optimized version replaces this with list comprehensions, which are implemented in C and avoid Python function call overhead for each iteration.

**2. Function Reference Caching:**
The optimization extracts `dt.date.fromisoformat` into a local variable `fromisoformat` before the list comprehension. This eliminates repeated attribute lookups (`dt.date.fromisoformat`) on every iteration, reducing overhead from Python's attribute resolution mechanism.

**Performance Analysis:**
The line profiler shows the optimization is most effective for larger datasets. While small test cases (single rows) show minimal improvement, the **large-scale test cases demonstrate 11-16% speedups** (e.g., 1000 rows: 387μs → 336μs). This pattern makes sense because:
- List comprehensions have fixed overhead but scale better than loops
- Attribute lookup caching provides linear savings that compound with dataset size
- The optimization maintains identical functionality and error handling behavior

The optimization is particularly beneficial for batch processing scenarios with many fixing table rows, which appears to be the primary use case based on the test coverage.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 28, 2025 21:36
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant