Skip to content

Comments

⚡️ Speed up function _compute_wrapped_segment by 44% in PR #1561 (add/support_react)#1606

Open
codeflash-ai[bot] wants to merge 1 commit intoadd/support_reactfrom
codeflash/optimize-pr1561-2026-02-20T13.20.28
Open

⚡️ Speed up function _compute_wrapped_segment by 44% in PR #1561 (add/support_react)#1606
codeflash-ai[bot] wants to merge 1 commit intoadd/support_reactfrom
codeflash/optimize-pr1561-2026-02-20T13.20.28

Conversation

@codeflash-ai
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Feb 20, 2026

⚡️ This pull request contains optimizations for PR #1561

If you approve this dependent PR, these changes will be merged into the original PR branch add/support_react.

This PR will be automatically closed if the original PR is merged.


📄 44% (0.44x) speedup for _compute_wrapped_segment in codeflash/languages/javascript/frameworks/react/profiler.py

⏱️ Runtime : 1.20 milliseconds 835 microseconds (best of 14 runs)

📝 Explanation and details

This optimization achieves a 43% runtime improvement (from 1.20ms to 835μs) through two key changes that eliminate Python overhead:

Primary Optimization: Explicit Loop in _contains_jsx

The original used any(_contains_jsx(child) for child in node.children), which creates a generator object on every call. The optimized version replaces this with an explicit for loop that can short-circuit immediately upon finding JSX:

for child in node.children:
    if _contains_jsx(child):
        return True
return False

This eliminates generator allocation overhead and enables early termination. The line profiler shows the impact: the original's generator expression took 1.04μs (73.1% of function time), while the optimized explicit loop takes only 0.39μs total for iteration and checks (40.6% + 0.7%). This is especially effective for the common case where JSX is found early in the children list.

Secondary Optimization: Loop Consolidation in _compute_wrapped_segment

The original code iterated over return_node.children twice - once to find JSX and again to check for parenthesized expressions. The optimized version merges these into a single pass by checking child.type == "parenthesized_expression" immediately when JSX is found, before breaking from the loop.

This eliminates the redundant iteration that processed ~1395 children in the second loop (shown in the original profiler). The optimization is particularly effective for test cases with many children - the large performance test shows 104% speedup (117μs → 57.7μs) and the parenthesized test with 200+ children shows 106% speedup (77.1μs → 37.4μs).

Runtime Impact by Test Case

  • Simple JSX: 6% faster (baseline benefit)
  • Self-closing JSX with whitespace: 36.5% faster (generator elimination effect)
  • Parenthesized expression: 58% faster (both optimizations)
  • Nested JSX detection: 55.7% faster (recursive generator elimination)
  • Large workloads (300+ children): 104-106% faster (loop consolidation dominates)

The optimizations are most impactful when processing complex React component trees with many children or deeply nested JSX structures, which are common in real-world React codebases.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 11 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
import pytest  # used for our unit tests
from codeflash.languages.javascript.frameworks.react.profiler import \
    _compute_wrapped_segment

# A minimal concrete Node-like class to simulate the attributes accessed by the function.
# The original function expects tree_sitter.Node instances, but only accesses a small
# subset of attributes: .type, .start_byte, .end_byte, and .children (iterable).
# We create a real Python class with those attributes so behavior is deterministic.
class SimpleNode:
    def __init__(self, type_, start_byte=0, end_byte=0, children=None):
        # node type string (e.g. "return", "jsx_element", ";", "parenthesized_expression")
        self.type = type_
        # integer byte offsets into source bytes
        self.start_byte = start_byte
        self.end_byte = end_byte
        # list of child nodes
        self.children = children or []

def test_wraps_simple_jsx_without_parentheses():
    # Create source with a simple JSX element followed by a semicolon.
    before = b"return "
    jsx = b"<div>hello</div>"
    semicolon = b";"
    source = before + jsx + semicolon

    # Indices: jsx starts after 'return ' (7 bytes)
    jsx_start = len(before)
    jsx_end = jsx_start + len(jsx)
    # Build nodes: "return" token, jsx element node, and semicolon token.
    return_token = SimpleNode("return", 0, len("return"), [])
    jsx_node = SimpleNode("jsx_element", jsx_start, jsx_end, [])
    semicolon_node = SimpleNode(";", jsx_end, jsx_end + 1, [])
    return_node = SimpleNode("return_statement", 0, len(source), [return_token, jsx_node, semicolon_node])

    codeflash_output = _compute_wrapped_segment(source, return_node, "my-id", "mySafe"); res = codeflash_output # 2.65μs -> 2.49μs (6.05% faster)
    start, end, wrapped = res

def test_trims_whitespace_and_handles_self_closing_jsx():
    # Source contains whitespace around a self-closing JSX element.
    source = b"return   \n  <img src=\"x\" />   \n ;"
    # compute positions manually
    jsx_bytes = b"<img src=\"x\" />"
    jsx_index = source.find(b"<img")
    jsx_end = jsx_index + len(jsx_bytes)

    # build nodes: return token, some whitespace node, jsx node and semicolon token
    return_token = SimpleNode("return", 0, 6, [])
    whitespace_node = SimpleNode("space", 6, jsx_index, [])
    jsx_node = SimpleNode("jsx_self_closing_element", jsx_index, jsx_end, [])
    semicolon_node = SimpleNode(";", source.rfind(b";"), source.rfind(b";") + 1, [])
    return_node = SimpleNode("return_statement", 0, len(source), [return_token, whitespace_node, jsx_node, semicolon_node])

    codeflash_output = _compute_wrapped_segment(source, return_node, "ID", "safeName"); res = codeflash_output # 3.56μs -> 2.60μs (36.5% faster)
    start, end, wrapped = res

def test_parenthesized_expression_wrapping():
    # When JSX is wrapped in parentheses, function should remove outer parens and wrap inner content.
    # Build a source like: return (  <span>ok</span>  );
    part1 = b"return (  "
    jsx = b"<span>ok</span>"
    part2 = b"  );"
    source = part1 + jsx + part2

    # Compute indices
    jsx_start = part1.__len__()
    jsx_end = jsx_start + len(jsx)
    # parenthesized_expression spans from the '(' after 'return ' to the ')' before ';'
    paren_start = source.find(b"(")
    paren_end = source.find(b")", paren_start) + 1  # include ')'

    # Construct nested structure: return token, parenthesized_expression (spanning parens), semicolon
    return_token = SimpleNode("return", 0, 6, [])
    # The parenthesized node will cause the function to set jsx_start = child.start_byte + 1, jsx_end = child.end_byte -1
    parenthesized = SimpleNode("parenthesized_expression", paren_start, paren_end, [
        SimpleNode("jsx_element", jsx_start, jsx_end, [])  # nested child (not strictly used)
    ])
    semicolon = SimpleNode(";", paren_end, paren_end + 1, [])
    return_node = SimpleNode("return_statement", 0, len(source), [return_token, parenthesized, semicolon])

    codeflash_output = _compute_wrapped_segment(source, return_node, "PID", "safeX"); res = codeflash_output # 4.34μs -> 2.75μs (58.0% faster)
    start, end, wrapped = res

def test_nested_jsx_detection_in_children():
    # The _contains_jsx function should detect JSX even when nested deeper in children.
    # Build source: return wrapper { <b>x</b> } ;
    before = b"return wrapper { "
    jsx = b"<b>x</b>"
    after = b" } ;"
    source = before + jsx + after
    jsx_start = len(before)
    jsx_end = jsx_start + len(jsx)

    # Create nested nodes: an outer container with a non-jsx type but containing a jsx descendant
    return_token = SimpleNode("return", 0, 6, [])
    wrapper_node = SimpleNode("object", 13, 13 + len(after) + len(jsx), [
        SimpleNode("container", 13, 13 + len(after), [
            SimpleNode("jsx_element", jsx_start, jsx_end, [])  # nested deep
        ])
    ])
    semicolon = SimpleNode(";", len(source) - 2, len(source) - 1, [])
    return_node = SimpleNode("return_statement", 0, len(source), [return_token, wrapper_node, semicolon])

    codeflash_output = _compute_wrapped_segment(source, return_node, "ID2", "S"); res = codeflash_output # 4.23μs -> 2.72μs (55.7% faster)
    start, end, wrapped = res

def test_return_with_semicolon_before_jsx_ignored():
    # If a semicolon token appears before the JSX child, it should not incorrectly set jsx_end.
    # Construct source where a stray semicolon appears first, then some JSX.
    source = b"return ; <p>late</p>;"
    # find the jsx
    jsx_index = source.find(b"<p>")
    jsx_end = jsx_index + len(b"<p>late</p>")

    # children order: return token, semicolon token, jsx node, final semicolon
    return_token = SimpleNode("return", 0, 6, [])
    early_semicolon = SimpleNode(";", 7, 8, [])
    jsx_node = SimpleNode("jsx_element", jsx_index, jsx_end, [])
    last_semicolon = SimpleNode(";", jsx_end, jsx_end + 1, [])
    return_node = SimpleNode("return_statement", 0, len(source), [return_token, early_semicolon, jsx_node, last_semicolon])

    codeflash_output = _compute_wrapped_segment(source, return_node, "s", "n"); res = codeflash_output # 2.52μs -> 2.26μs (11.5% faster)
    start, end, wrapped = res

def test_large_number_of_children_performance_and_correctness():
    # Build a large source with many non-jsx children and one jsx in the middle.
    # This tests that the function scales to many children and still finds the JSX correctly.
    prefix_parts = [b"token%d " % i for i in range(300)]
    before = b"return " + b"".join(prefix_parts)
    jsx = b"<ul>" + b"".join(b"<li>%d</li>" % i for i in range(50)) + b"</ul>"
    after = b" trailing_tokens " + b" ".join(b"x" for _ in range(300)) + b";"
    source = before + jsx + after

    # compute jsx offsets
    jsx_start = len(before)
    jsx_end = jsx_start + len(jsx)

    # Build many fake children: a bunch of tokens before, then jsx node, then more tokens and semicolon
    children = []
    # 'return' token
    children.append(SimpleNode("return", 0, 6, []))
    # many non-jsx tokens
    cur = 7
    for i in range(300):
        token_bytes = prefix_parts[i]
        token_len = len(token_bytes)
        children.append(SimpleNode("identifier", cur, cur + token_len, []))
        cur += token_len
    # the jsx node
    children.append(SimpleNode("jsx_element", jsx_start, jsx_end, []))
    # trailing tokens (we do not need exact offsets for them, but set them reasonably)
    pos = jsx_end
    for i in range(10):
        children.append(SimpleNode("identifier", pos, pos + 1, []))
        pos += 1
    # final semicolon
    children.append(SimpleNode(";", pos, pos + 1, []))

    return_node = SimpleNode("return_statement", 0, len(source), children)

    codeflash_output = _compute_wrapped_segment(source, return_node, "LARGE", "bigSafe"); res = codeflash_output # 117μs -> 57.7μs (104% faster)
    start, end, wrapped = res

def test_large_parenthesized_with_many_children():
    # Stress test with parenthesized_expression among many children.
    # Build source: return before (   <span>big</span>   ) after;
    before = b"return " + b" ".join(b"t" for _ in range(200))
    inner = b"   <span>big</span>   "
    source = before + b"(" + inner + b")" + b" ;"
    paren_start = source.find(b"(")
    paren_end = source.find(b")", paren_start) + 1
    # parenthesized_expression span
    parenthesized = SimpleNode("parenthesized_expression", paren_start, paren_end, [
        SimpleNode("jsx_element", paren_start + 3, paren_start + 3 + len(b"<span>big</span>"), [])
    ])
    # Construct many siblings with random-like tokens
    children = [SimpleNode("return", 0, 6, [])] + [SimpleNode("token", i, i + 1, []) for i in range(6, 6 + 200)] + [parenthesized, SimpleNode(";", paren_end + 1, paren_end + 2, [])]
    return_node = SimpleNode("return_statement", 0, len(source), children)

    codeflash_output = _compute_wrapped_segment(source, return_node, "PAREN", "safeP"); res = codeflash_output # 77.1μs -> 37.4μs (106% faster)
    start, end, wrapped = res
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
from unittest.mock import Mock

# imports
import pytest
from codeflash.languages.javascript.frameworks.react.profiler import \
    _compute_wrapped_segment
from tree_sitter import Language, Node, Parser

# Helper function to create a mock Node with proper tree-sitter interface
def create_mock_node(node_type: str, start_byte: int, end_byte: int, children: list = None) -> Node:
    """Create a real or mock tree-sitter Node for testing."""
    node = Mock(spec=Node)
    node.type = node_type
    node.start_byte = start_byte
    node.end_byte = end_byte
    node.children = children if children is not None else []
    return node

# function to test
def _contains_jsx(node: Node) -> bool:
    """Check if a tree-sitter node contains JSX elements."""
    if node.type in ("jsx_element", "jsx_self_closing_element", "jsx_fragment"):
        return True
    return any(_contains_jsx(child) for child in node.children)

def test_contains_jsx_with_nested_children():
    """Test _contains_jsx helper with deeply nested JSX."""
    # Create a tree with nested JSX children
    deep_jsx = create_mock_node("jsx_element", 15, 25)
    nested_child = create_mock_node("unknown", 10, 30, [deep_jsx])
    root = create_mock_node("expression", 5, 35, [nested_child])

def test_contains_jsx_returns_false_for_non_jsx():
    """Test _contains_jsx returns False when no JSX present."""
    # Create a tree with no JSX elements
    child1 = create_mock_node("identifier", 5, 10)
    child2 = create_mock_node("binary_expression", 15, 20)
    root = create_mock_node("expression", 0, 25, [child1, child2])

def test_deeply_nested_jsx_structure():
    """Test _contains_jsx with deeply nested node structure (1000 levels)."""
    # Create a deeply nested structure
    current_node = create_mock_node("jsx_element", 0, 10)
    
    # Build 100 levels of nesting (not 1000 to avoid stack overflow)
    for i in range(100):
        parent = create_mock_node(f"expression_{i}", 0, 10, [current_node])
        current_node = parent

To edit these changes git checkout codeflash/optimize-pr1561-2026-02-20T13.20.28 and push.

Codeflash Static Badge

This optimization achieves a **43% runtime improvement** (from 1.20ms to 835μs) through two key changes that eliminate Python overhead:

## Primary Optimization: Explicit Loop in `_contains_jsx`
The original used `any(_contains_jsx(child) for child in node.children)`, which creates a generator object on every call. The optimized version replaces this with an explicit `for` loop that can short-circuit immediately upon finding JSX:

```python
for child in node.children:
    if _contains_jsx(child):
        return True
return False
```

This eliminates generator allocation overhead and enables early termination. The line profiler shows the impact: the original's generator expression took **1.04μs** (73.1% of function time), while the optimized explicit loop takes only **0.39μs** total for iteration and checks (40.6% + 0.7%). This is especially effective for the common case where JSX is found early in the children list.

## Secondary Optimization: Loop Consolidation in `_compute_wrapped_segment`
The original code iterated over `return_node.children` twice - once to find JSX and again to check for parenthesized expressions. The optimized version merges these into a single pass by checking `child.type == "parenthesized_expression"` immediately when JSX is found, before breaking from the loop.

This eliminates the redundant iteration that processed ~1395 children in the second loop (shown in the original profiler). The optimization is particularly effective for test cases with many children - the large performance test shows **104% speedup** (117μs → 57.7μs) and the parenthesized test with 200+ children shows **106% speedup** (77.1μs → 37.4μs).

## Runtime Impact by Test Case
- Simple JSX: 6% faster (baseline benefit)
- Self-closing JSX with whitespace: 36.5% faster (generator elimination effect)
- Parenthesized expression: 58% faster (both optimizations)
- Nested JSX detection: 55.7% faster (recursive generator elimination)
- Large workloads (300+ children): 104-106% faster (loop consolidation dominates)

The optimizations are most impactful when processing complex React component trees with many children or deeply nested JSX structures, which are common in real-world React codebases.
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Feb 20, 2026
@claude
Copy link
Contributor

claude bot commented Feb 20, 2026

PR Review Summary

Prek Checks

  • mypy: No issues found in the changed file
  • ruff format: Passed
  • ruff check: 1 issue (not auto-fixable)
    • SIM110 in profiler.py:196 — ruff prefers return any(_contains_jsx(child) for child in node.children) over the explicit for loop. This conflicts with the PR's intentional optimization (explicit loop avoids generator allocation overhead). This is a style vs. performance tradeoff for the codeflash team to decide.

Code Review

No critical issues found. The optimization is correct:

  1. _contains_jsx change (lines 196-199): Replacing any(generator) with an explicit loop is functionally equivalent. Both short-circuit on first True.

  2. _compute_wrapped_segment loop consolidation (lines 311-318): Merging the two loops is both a performance improvement and arguably more correct — the original second loop would apply parenthesized_expression bounds even if that child was not the JSX-containing one. The optimized version only adjusts bounds when the JSX-containing child itself is a parenthesized_expression.

No security vulnerabilities, breaking API changes, or test issues introduced by this PR. The 8 test failures in test_tracer.py are pre-existing on main.

Test Coverage

This PR modifies only profiler.py (vs its base branch add/support_react). The broader file list below reflects all changes between main and this branch, most of which come from the parent add/support_react branch.

File PR Coverage Main Coverage Delta
codeflash/api/aiservice.py 20% 20%
codeflash/api/schemas.py — (not covered) N/A (new) ⚠️ NEW
codeflash/languages/base.py 98% 98%
codeflash/languages/javascript/frameworks/__init__.py 100% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/detector.py 100% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/react/__init__.py 100% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/react/analyzer.py 100% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/react/benchmarking.py 100% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/react/context.py 99% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/react/discovery.py 94% N/A (new) ✅ NEW
codeflash/languages/javascript/frameworks/react/profiler.py 14% N/A (new) ⚠️ NEW
codeflash/languages/javascript/parse.py 51% 49% +2%
codeflash/languages/javascript/support.py 70% 71% -1%
codeflash/languages/javascript/treesitter.py 92% 92%
codeflash/languages/javascript/treesitter_utils.py — (not covered) N/A (new) ⚠️ NEW
codeflash/models/function_types.py 100% 100%
codeflash/result/critic.py 73% 70% +3%
codeflash/result/explanation.py 45% 46% -1%
codeflash/version.py 100% 100%
Overall (changed files) 70% 70%

Key observations:

  • profiler.py (the file this PR optimizes) has only 14% coverage — well below the 75% threshold for new files. Most of its functions involve runtime React profiling instrumentation which is hard to unit test. This is a pre-existing concern from the parent branch, not introduced by this optimization PR.
  • schemas.py and treesitter_utils.py have no coverage — also pre-existing from the parent branch.
  • Overall coverage is unchanged at 70%.

Last updated: 2026-02-20

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.

0 participants