Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Dec 17, 2025

📄 111% (1.11x) speedup for RegistryToolWrapper._format_parameters in backend/python/app/modules/agents/qna/tool_registry.py

⏱️ Runtime : 1.69 milliseconds 803 microseconds (best of 250 runs)

📝 Explanation and details

The optimized code achieves a 110% speedup through several key performance optimizations in the _format_parameters method:

Primary optimizations:

  1. Eliminated unnecessary exception handling: The original code wrapped the entire parameter processing loop in a try/catch. The optimized version only catches exceptions when actually accessing param.type, reducing overhead for the common case where attribute access succeeds.

  2. Reduced attribute lookups: Instead of calling getattr(param.type, 'name', str(getattr(param, 'type', 'string'))) in a single nested call, the optimized version breaks this into explicit null checks (if type_obj is not None, if type_name is not None), avoiding redundant getattr calls and string conversions.

  3. Pre-bound method reference: Used append = list.append to avoid repeated method lookups in the loop, replacing formatted_params.append() with the faster append(result, ...) pattern.

  4. Streamlined control flow: The optimized version uses explicit conditional checks rather than relying on exception handling for control flow, which is significantly faster in Python.

Performance characteristics by test case:

  • Best improvements (50-180% faster): Tests with many parameters or missing attributes benefit most from reduced exception handling overhead
  • Slight regressions (5-30% slower): Very simple cases like empty lists or basic string types show minor slowdowns due to the additional setup code, but these are minimal compared to the gains
  • Large-scale workloads: The 1000-parameter test shows 123% improvement, indicating excellent scalability

The optimization is particularly effective for registry tools with complex parameter schemas or missing attributes, where the original code's exception-heavy approach created significant overhead. The changes preserve all existing behavior while dramatically improving performance for the common use cases.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 37 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
# imports
from app.modules.agents.qna.tool_registry import RegistryToolWrapper


class DummyType:
    def __init__(self, name):
        self.name = name


class DummyParam:
    def __init__(self, name, type_=None, required=False, description=""):
        self.name = name
        self.type = type_
        self.required = required
        self.description = description


# unit tests

# -------------------------
# Basic Test Cases
# -------------------------


def test_single_param_required_with_description():
    # Simple param with required True, description, and type with name
    param = DummyParam(
        name="foo",
        type_=DummyType("integer"),
        required=True,
        description="The foo parameter",
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.44μs -> 1.47μs (66.5% faster)


def test_single_param_not_required_no_description():
    # Param with required False, no description, and type with name
    param = DummyParam(
        name="bar", type_=DummyType("string"), required=False, description=""
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.25μs -> 1.45μs (54.5% faster)


def test_multiple_params_mixed():
    # Multiple parameters, mixed required, with/without description
    params = [
        DummyParam("foo", DummyType("integer"), True, "Foo desc"),
        DummyParam("bar", DummyType("string"), False, "Bar desc"),
        DummyParam("baz", DummyType("bool"), True, ""),
    ]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 3.99μs -> 2.44μs (63.5% faster)


# -------------------------
# Edge Test Cases
# -------------------------


def test_empty_param_list():
    # No parameters
    codeflash_output = RegistryToolWrapper._format_parameters([])
    result = codeflash_output  # 400ns -> 535ns (25.2% slower)


def test_param_type_is_str():
    # Param type is just a string, not an object with .name
    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = "float"
            self.required = True
            self.description = "desc"

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 1.59μs -> 1.68μs (5.12% slower)


def test_param_type_is_none():
    # Param type is None
    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = None
            self.required = False
            self.description = "desc"

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 1.60μs -> 1.42μs (12.2% faster)


def test_param_missing_type_attr():
    # Param object has no 'type' attribute at all
    class Param:
        def __init__(self):
            self.name = "foo"
            self.required = True
            self.description = "desc"

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.42μs -> 1.58μs (52.7% faster)


def test_param_type_object_missing_name():
    # Param.type is an object without 'name'
    class TypeObj:
        pass

    param = DummyParam("foo", TypeObj(), True, "desc")
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.98μs -> 3.17μs (6.21% slower)


def test_param_missing_required_attr():
    # Param object has no 'required' attribute
    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = DummyType("string")
            self.description = "desc"

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.72μs -> 1.56μs (74.1% faster)


def test_param_missing_description_attr():
    # Param object has no 'description' attribute
    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = DummyType("string")
            self.required = True

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.62μs -> 1.60μs (63.5% faster)


def test_param_name_is_empty_string():
    # Param name is empty string
    param = DummyParam("", DummyType("string"), True, "desc")
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.30μs -> 1.43μs (61.7% faster)


def test_param_with_non_str_name():
    # Param name is not a string
    param = DummyParam(123, DummyType("int"), True, "desc")
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.42μs -> 1.58μs (53.4% faster)


def test_param_with_unicode_and_special_chars():
    # Param with unicode and special characters in name/description/type
    param = DummyParam("名字", DummyType("类型"), True, "描述 with emoji 🚀")
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.74μs -> 1.92μs (43.1% faster)


def test_param_type_getattr_raises():
    # param.type raises an Exception on getattr
    class Param:
        def __init__(self):
            self.name = "foo"
            self.required = True
            self.description = "desc"

        @property
        def type(self):
            raise ValueError("fail!")

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.35μs -> 2.60μs (9.91% slower)


# -------------------------
# Large Scale Test Cases
# -------------------------


def test_large_number_of_params():
    # Test with 1000 parameters
    params = [
        DummyParam(
            name=f"param{i}",
            type_=DummyType("int"),
            required=(i % 2 == 0),
            description=f"desc{i}",
        )
        for i in range(1000)
    ]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 464μs -> 208μs (123% faster)


def test_large_params_with_mixed_types():
    # Test with 500 params, half with type object, half with string
    params = []
    for i in range(500):
        if i % 2 == 0:
            t = DummyType("float")
        else:
            t = "float"
        params.append(DummyParam(f"p{i}", t, bool(i % 3), f"d{i}"))
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 179μs -> 114μs (57.0% faster)


def test_large_params_with_missing_attrs():
    # Test with 300 params, some missing type, required, description
    class Param:
        def __init__(self, i):
            self.name = f"x{i}"
            if i % 3 == 0:
                self.type = DummyType("t")
            if i % 3 == 1:
                self.required = True
            if i % 3 == 2:
                self.description = f"desc{i}"

    params = [Param(i) for i in range(300)]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 154μs -> 59.4μs (161% faster)


# -------------------------
# Determinism and Order
# -------------------------


def test_order_is_preserved():
    # The order of parameters should be preserved
    params = [
        DummyParam("a", DummyType("A"), True, "descA"),
        DummyParam("b", DummyType("B"), False, "descB"),
        DummyParam("c", DummyType("C"), True, "descC"),
    ]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 3.78μs -> 2.52μs (49.8% faster)


# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
# imports
from app.modules.agents.qna.tool_registry import RegistryToolWrapper


class DummyType:
    def __init__(self, name):
        self.name = name


class DummyParam:
    def __init__(self, name, type_obj=None, required=False, description=""):
        # type_obj can be a DummyType or a string (simulate broken type)
        self.name = name
        self.type = type_obj
        self.required = required
        self.description = description


# unit tests

# ----------- BASIC TEST CASES -----------


def test_single_param_required_with_description():
    # Test a single required parameter with a description and type
    param = DummyParam(
        name="foo",
        type_obj=DummyType("integer"),
        required=True,
        description="The foo parameter",
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 3.69μs -> 1.89μs (94.9% faster)


def test_single_param_optional_with_description():
    # Test a single optional parameter with a description and type
    param = DummyParam(
        name="bar", type_obj=DummyType("string"), required=False, description="Bar desc"
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.78μs -> 1.60μs (73.2% faster)


def test_multiple_params_mixed_required():
    # Test multiple parameters, some required, some not
    params = [
        DummyParam("a", DummyType("str"), True, "desc a"),
        DummyParam("b", DummyType("int"), False, "desc b"),
        DummyParam("c", DummyType("float"), True, "desc c"),
    ]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 4.39μs -> 2.61μs (67.8% faster)


def test_param_with_empty_description():
    # Test a parameter with an empty description
    param = DummyParam(
        name="baz", type_obj=DummyType("bool"), required=True, description=""
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.41μs -> 1.48μs (62.4% faster)


def test_param_with_none_description():
    # Test a parameter with description set to None
    param = DummyParam(
        name="baz", type_obj=DummyType("bool"), required=True, description=None
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.58μs -> 1.69μs (52.9% faster)


# ----------- EDGE TEST CASES -----------


def test_param_type_is_string():
    # Test when param.type is a string, not an object with .name
    param = DummyParam(
        name="foo", type_obj="customtype", required=False, description="desc"
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 1.62μs -> 1.78μs (8.90% slower)


def test_param_type_is_none():
    # Test when param.type is None
    param = DummyParam(name="foo", type_obj=None, required=True, description="desc")
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 1.69μs -> 1.39μs (21.5% faster)


def test_param_missing_type_attribute():
    # Test when param does not have a 'type' attribute at all
    class NoTypeParam:
        def __init__(self, name, required, description):
            self.name = name
            self.required = required
            self.description = description

    param = NoTypeParam("foo", True, "desc")
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.46μs -> 1.60μs (53.8% faster)


def test_param_type_attribute_raises():
    # Test when accessing param.type raises an exception
    class FailingType:
        @property
        def name(self):
            raise ValueError("fail")

    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = FailingType()
            self.required = True
            self.description = "desc"

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 3.85μs -> 2.80μs (37.3% faster)


def test_param_missing_required_attribute():
    # Test when param does not have a 'required' attribute
    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = DummyType("int")
            self.description = "desc"

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.62μs -> 1.54μs (70.7% faster)


def test_param_missing_description_attribute():
    # Test when param does not have a 'description' attribute
    class Param:
        def __init__(self):
            self.name = "foo"
            self.type = DummyType("int")
            self.required = True

    param = Param()
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.56μs -> 1.63μs (56.6% faster)


def test_empty_param_list():
    # Test with an empty parameter list
    codeflash_output = RegistryToolWrapper._format_parameters([])
    result = codeflash_output  # 405ns -> 576ns (29.7% slower)


def test_param_name_with_special_characters():
    # Test parameter names with special characters
    param = DummyParam(
        name="foo-bar_123", type_obj=DummyType("str"), required=True, description="desc"
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.58μs -> 1.57μs (64.1% faster)


def test_param_with_multiline_description():
    # Test parameter with a multiline description
    param = DummyParam(
        name="foo",
        type_obj=DummyType("str"),
        required=True,
        description="Line 1\nLine 2",
    )
    codeflash_output = RegistryToolWrapper._format_parameters([param])
    result = codeflash_output  # 2.50μs -> 1.51μs (65.4% faster)


# ----------- LARGE SCALE TEST CASES -----------


def test_large_number_of_params():
    # Test with a large number of parameters (up to 1000)
    num_params = 1000
    params = [
        DummyParam(
            name=f"param{i}",
            type_obj=DummyType(f"type{i % 5}"),
            required=(i % 2 == 0),
            description=f"description {i}",
        )
        for i in range(num_params)
    ]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 477μs -> 219μs (118% faster)
    # Check a few random spots for correctness
    for i in [0, 1, 500, 999]:
        expected = f"param{i}"
        if i % 2 == 0:
            expected += " (required)"
        expected += f": description {i} [type{i % 5}]"


def test_large_number_of_params_missing_attrs():
    # Test with a large number of parameters missing some attributes
    class Param:
        def __init__(self, name):
            self.name = name

    num_params = 500
    params = [Param(f"p{i}") for i in range(num_params)]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 235μs -> 83.3μs (183% faster)
    # All should fallback to default values
    for i, s in enumerate(result):
        pass


def test_large_number_of_params_varied_types():
    # Test with a large number of parameters with varied types (some with type objects, some with strings, some with None)
    params = []
    for i in range(300):
        if i % 3 == 0:
            t = DummyType("tA")
        elif i % 3 == 1:
            t = "tB"
        else:
            t = None
        params.append(DummyParam(f"n{i}", t, i % 2 == 0, f"desc{i}"))
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result = codeflash_output  # 100μs -> 64.2μs (56.1% faster)
    for i in range(300):
        expected = f"n{i}"
        if i % 2 == 0:
            expected += " (required)"
        expected += f": desc{i} ["
        if i % 3 == 0:
            expected += "tA"
        elif i % 3 == 1:
            expected += "tB"
        else:
            expected += "None"
        expected += "]"


# ----------- DETERMINISM TEST -----------


def test_determinism():
    # Test that repeated calls with the same input produce the same output
    params = [
        DummyParam("foo", DummyType("int"), True, "desc"),
        DummyParam("bar", DummyType("str"), False, "desc2"),
    ]
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result1 = codeflash_output  # 3.40μs -> 2.04μs (66.9% faster)
    codeflash_output = RegistryToolWrapper._format_parameters(params)
    result2 = codeflash_output  # 1.58μs -> 969ns (63.6% faster)


# 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-RegistryToolWrapper._format_parameters-mja3g4yj and push.

Codeflash Static Badge

The optimized code achieves a **110% speedup** through several key performance optimizations in the `_format_parameters` method:

**Primary optimizations:**

1. **Eliminated unnecessary exception handling**: The original code wrapped the entire parameter processing loop in a try/catch. The optimized version only catches exceptions when actually accessing `param.type`, reducing overhead for the common case where attribute access succeeds.

2. **Reduced attribute lookups**: Instead of calling `getattr(param.type, 'name', str(getattr(param, 'type', 'string')))` in a single nested call, the optimized version breaks this into explicit null checks (`if type_obj is not None`, `if type_name is not None`), avoiding redundant getattr calls and string conversions.

3. **Pre-bound method reference**: Used `append = list.append` to avoid repeated method lookups in the loop, replacing `formatted_params.append()` with the faster `append(result, ...)` pattern.

4. **Streamlined control flow**: The optimized version uses explicit conditional checks rather than relying on exception handling for control flow, which is significantly faster in Python.

**Performance characteristics by test case:**
- **Best improvements** (50-180% faster): Tests with many parameters or missing attributes benefit most from reduced exception handling overhead
- **Slight regressions** (5-30% slower): Very simple cases like empty lists or basic string types show minor slowdowns due to the additional setup code, but these are minimal compared to the gains
- **Large-scale workloads**: The 1000-parameter test shows 123% improvement, indicating excellent scalability

The optimization is particularly effective for registry tools with complex parameter schemas or missing attributes, where the original code's exception-heavy approach created significant overhead. The changes preserve all existing behavior while dramatically improving performance for the common use cases.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 December 17, 2025 14:15
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash labels Dec 17, 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: Medium Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant