Skip to content

Conversation

@codeflash-ai
Copy link

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

📄 6% (0.06x) speedup for string2json in inference/core/workflows/core_steps/formatters/vlm_as_detector/v2.py

⏱️ Runtime : 13.0 milliseconds 12.2 milliseconds (best of 209 runs)

📝 Explanation and details

The optimization replaces findall() with search() in the regex pattern matching, delivering a 5% speedup with particularly strong gains on specific test cases.

Key optimization:

  • Changed from findall() to search(): Instead of scanning the entire string to find ALL JSON markdown blocks and creating a list, search() stops at the first match and returns a match object directly.
  • Direct group extraction: Uses match.group(1) to extract the JSON content instead of indexing into a list of all matches.

Why this is faster:

  • findall() must scan the entire input string even after finding the first match, while search() stops immediately after the first match
  • findall() allocates memory for a list to store all matches, while search() returns a single match object
  • The original code only uses the first match anyway, making the extra work wasteful

Performance characteristics:

  • Moderate gains (5-17%) on typical single-block cases
  • Exceptional gains (up to 70%) on inputs with multiple JSON blocks, since search() avoids scanning for subsequent blocks that aren't needed
  • Consistent improvements across all test cases, from simple JSON strings to large nested objects
  • Largest benefits appear in the test_large_json_multiple_blocks_only_first_used case (69.6% faster) where avoiding the scan for the second large block provides substantial savings

The optimization maintains identical behavior and error handling while eliminating unnecessary regex scanning and memory allocation.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 68 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import json
import logging
import re
from typing import Tuple

# imports
import pytest  # used for our unit tests
from inference.core.workflows.core_steps.formatters.vlm_as_detector.v2 import \
    string2json

JSON_MARKDOWN_BLOCK_PATTERN = re.compile(r"```json([\s\S]*?)```", flags=re.IGNORECASE)
from inference.core.workflows.core_steps.formatters.vlm_as_detector.v2 import \
    string2json

# unit tests

# --- Basic Test Cases ---

def test_valid_json_string():
    # Basic valid JSON string
    s = '{"a": 1, "b": 2}'
    err, d = string2json(s) # 5.88μs -> 5.00μs (17.7% faster)

def test_valid_json_markdown_block():
    # JSON inside a markdown block
    s = "Here is some data:\n```json{\"x\": 42, \"y\": [1,2,3]}```"
    err, d = string2json(s) # 7.21μs -> 6.39μs (12.9% faster)

def test_multiple_json_blocks():
    # Multiple markdown blocks, should parse the first
    s = "```json{\"first\": 1}```\nSome text\n```json{\"second\": 2}```"
    err, d = string2json(s) # 6.45μs -> 5.18μs (24.3% faster)

def test_json_block_with_whitespace():
    # JSON block with leading/trailing whitespace
    s = "```json   {\"foo\": \"bar\"}   ```"
    err, d = string2json(s) # 5.99μs -> 5.18μs (15.5% faster)

def test_json_block_case_insensitive():
    # Markdown block with "JSON" in different case
    s = "```JSON{\"case\": \"insensitive\"}```"
    err, d = string2json(s) # 5.77μs -> 5.15μs (12.0% faster)

def test_json_block_with_newlines():
    # JSON block with newlines inside
    s = "```json\n{\n  \"a\": 1,\n  \"b\": 2\n}\n```"
    err, d = string2json(s) # 6.51μs -> 5.53μs (17.7% faster)

def test_json_block_with_comments_outside():
    # Only the block is parsed, not outside comments
    s = "Some text\n```json{\"only\": \"this\"}```\nOther text"
    err, d = string2json(s) # 5.62μs -> 5.11μs (9.98% faster)

# --- Edge Test Cases ---

def test_empty_string():
    # Empty string should fail to parse
    s = ""
    err, d = string2json(s) # 682μs -> 648μs (5.17% faster)

def test_invalid_json_string():
    # Invalid JSON string
    s = "{not: valid, json}"
    err, d = string2json(s) # 662μs -> 631μs (4.90% faster)

def test_invalid_json_in_block():
    # Invalid JSON inside markdown block
    s = "```json{not: valid}```"
    err, d = string2json(s) # 659μs -> 620μs (6.25% faster)

def test_non_json_markdown_block():
    # Markdown block but not JSON type
    s = "```python{'a': 1}```"
    err, d = string2json(s) # 626μs -> 599μs (4.45% faster)

def test_json_block_with_extra_text():
    # Extra text after the block, should ignore it
    s = "```json{\"foo\": \"bar\"}```\nExtra text"
    err, d = string2json(s) # 8.34μs -> 7.53μs (10.7% faster)

def test_json_block_with_unicode():
    # JSON block with unicode characters
    s = "```json{\"emoji\": \"😀\", \"lang\": \"日本語\"}```"
    err, d = string2json(s) # 9.23μs -> 8.46μs (9.12% faster)

def test_json_block_with_escaped_characters():
    # JSON block with escaped characters
    s = r'```json{"path": "C:\\\\Users\\\\Test"}```'
    err, d = string2json(s) # 7.12μs -> 6.63μs (7.41% faster)

def test_json_block_with_nested_objects():
    # JSON block with nested objects and arrays
    s = "```json{\"outer\": {\"inner\": [1,2,3], \"deep\": {\"x\": 9}}}```"
    err, d = string2json(s) # 7.72μs -> 6.95μs (11.1% faster)

def test_json_block_with_boolean_and_null():
    # JSON block with boolean and null values
    s = "```json{\"flag\": true, \"missing\": null}```"
    err, d = string2json(s) # 6.19μs -> 5.31μs (16.7% faster)

def test_json_block_with_leading_and_trailing_newlines():
    # JSON block with newlines before/after block
    s = "\n\n```json{\"a\": 1}```\n\n"
    err, d = string2json(s) # 5.85μs -> 4.99μs (17.3% faster)

def test_json_block_with_empty_object():
    # JSON block with empty object
    s = "```json{}```"
    err, d = string2json(s) # 4.94μs -> 4.38μs (12.8% faster)

def test_json_block_with_empty_array():
    # JSON block with empty array
    s = "```json[]```"
    err, d = string2json(s) # 4.99μs -> 4.34μs (14.8% faster)

def test_json_block_with_number():
    # JSON block with a number
    s = "```json42```"
    err, d = string2json(s) # 4.89μs -> 4.43μs (10.2% faster)

def test_json_block_with_string():
    # JSON block with a string
    s = "```json\"hello world\"```"
    err, d = string2json(s) # 5.02μs -> 4.53μs (10.7% faster)

def test_json_block_with_false_and_true():
    # JSON block with JSON booleans
    s = "```jsonfalse```"
    err, d = string2json(s) # 4.74μs -> 4.39μs (7.97% faster)
    s2 = "```jsontrue```"
    err2, d2 = string2json(s2) # 2.29μs -> 2.13μs (7.42% faster)

def test_json_block_with_null():
    # JSON block with null
    s = "```jsonnull```"
    err, d = string2json(s) # 4.53μs -> 4.03μs (12.3% faster)

def test_json_block_with_weird_spacing():
    # JSON block with weird spacing and tabs
    s = "```json\t{\"a\":\t1}\t```"
    err, d = string2json(s) # 5.76μs -> 5.22μs (10.4% faster)

def test_json_block_with_large_numbers():
    # JSON block with large numbers
    s = "```json{\"big\": 12345678901234567890}```"
    err, d = string2json(s) # 6.20μs -> 5.65μs (9.79% faster)

def test_json_block_with_float_and_exponent():
    # JSON block with float and exponent
    s = "```json{\"f\": 1.23, \"exp\": 1e6}```"
    err, d = string2json(s) # 6.96μs -> 6.11μs (14.1% faster)

def test_json_block_with_trailing_comma():
    # JSON block with trailing comma (invalid in JSON)
    s = "```json{\"a\": 1,}```"
    err, d = string2json(s) # 705μs -> 675μs (4.49% faster)

# --- Large Scale Test Cases ---

def test_large_json_object():
    # Large JSON object with 1000 keys
    obj = {f"key{i}": i for i in range(1000)}
    s = "```json" + json.dumps(obj) + "```"
    err, d = string2json(s) # 303μs -> 289μs (4.67% faster)

def test_large_json_array():
    # Large JSON array with 1000 elements
    arr = list(range(1000))
    s = "```json" + json.dumps(arr) + "```"
    err, d = string2json(s) # 92.9μs -> 88.2μs (5.33% faster)

def test_large_json_nested_object():
    # Large nested JSON object
    nested = {"root": {"level1": {"level2": {"level3": [i for i in range(1000)]}}}}
    s = "```json" + json.dumps(nested) + "```"
    err, d = string2json(s) # 91.6μs -> 87.6μs (4.56% faster)

def test_large_json_string():
    # Large string value inside JSON
    big_str = "a" * 1000
    s = f"```json{{\"big\": \"{big_str}\"}}```"
    err, d = string2json(s) # 18.4μs -> 17.6μs (4.94% faster)

def test_large_json_with_multiple_blocks():
    # Multiple large blocks, should only parse the first
    arr1 = list(range(500))
    arr2 = list(range(500, 1000))
    s = f"```json{json.dumps(arr1)}```\nSome text\n```json{json.dumps(arr2)}```"
    err, d = string2json(s) # 78.4μs -> 45.7μs (71.4% faster)

def test_large_invalid_json():
    # Large invalid JSON (missing closing brace)
    s = "```json{" + ", ".join([f'"k{i}": {i}' for i in range(1000)]) + "```"
    err, d = string2json(s) # 1.01ms -> 960μs (5.15% faster)

def test_large_json_no_block():
    # Large JSON string not inside markdown block
    obj = {f"key{i}": i for i in range(1000)}
    s = json.dumps(obj)
    err, d = string2json(s) # 115μs -> 109μs (5.36% faster)

def test_large_json_array_no_block():
    # Large JSON array not inside markdown block
    arr = list(range(1000))
    s = json.dumps(arr)
    err, d = string2json(s) # 34.9μs -> 33.0μs (5.57% faster)

def test_large_json_with_unicode():
    # Large JSON object with unicode values
    obj = {f"emoji{i}": "😀" for i in range(1000)}
    s = "```json" + json.dumps(obj, ensure_ascii=False) + "```"
    err, d = string2json(s) # 365μs -> 348μs (4.86% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import json
import logging
import re
from typing import Tuple

# imports
import pytest  # used for our unit tests
from inference.core.workflows.core_steps.formatters.vlm_as_detector.v2 import \
    string2json

JSON_MARKDOWN_BLOCK_PATTERN = re.compile(r"```json([\s\S]*?)```", flags=re.IGNORECASE)
from inference.core.workflows.core_steps.formatters.vlm_as_detector.v2 import \
    string2json

# unit tests

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

def test_valid_json_string():
    # Basic valid JSON string, no markdown block
    s = '{"a": 1, "b": "c"}'
    err, out = string2json(s) # 7.18μs -> 6.18μs (16.1% faster)

def test_valid_json_markdown_block():
    # JSON string inside a markdown block
    s = "Here is some data:\n```json{\"x\": 10, \"y\": [1,2,3]}```\nEnd."
    err, out = string2json(s) # 7.67μs -> 6.93μs (10.8% faster)

def test_multiple_json_markdown_blocks():
    # Multiple markdown blocks, should parse only the first
    s = "First block:\n```json{\"foo\": 1}```\nSecond block:\n```json{\"bar\": 2}```"
    err, out = string2json(s) # 6.48μs -> 5.22μs (24.2% faster)

def test_json_with_whitespace_in_block():
    # JSON block with leading/trailing whitespace
    s = "```json   {\"test\": true}   ```"
    err, out = string2json(s) # 5.95μs -> 5.34μs (11.3% faster)

def test_json_with_newlines_in_block():
    # JSON block with newlines
    s = "```json\n{\n  \"a\": [1,2,3],\n  \"b\": \"yes\"\n}\n```"
    err, out = string2json(s) # 6.68μs -> 6.19μs (8.00% faster)

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

def test_invalid_json_string():
    # Invalid JSON string, no markdown block
    s = '{"a": 1, "b": "c",}'  # trailing comma
    err, out = string2json(s) # 713μs -> 674μs (5.82% faster)

def test_invalid_json_markdown_block():
    # Invalid JSON inside markdown block
    s = "```json{\"foo\": 1,}```"
    err, out = string2json(s) # 662μs -> 629μs (5.19% faster)

def test_empty_string():
    # Empty string input
    s = ""
    err, out = string2json(s) # 631μs -> 598μs (5.58% faster)

def test_empty_markdown_block():
    # Empty markdown block
    s = "```json```"
    err, out = string2json(s) # 632μs -> 600μs (5.31% faster)

def test_non_json_string():
    # String that is not JSON at all
    s = "hello world"
    err, out = string2json(s) # 631μs -> 598μs (5.61% faster)

def test_non_json_markdown_block():
    # Markdown block with non-JSON content
    s = "```json\nnot a json\n```"
    err, out = string2json(s) # 631μs -> 600μs (5.05% faster)

def test_json_with_unicode_characters():
    # JSON with unicode characters
    s = '{"emoji": "😀", "text": "café"}'
    err, out = string2json(s) # 9.03μs -> 8.13μs (11.1% faster)

def test_json_with_escaped_characters():
    # JSON with escaped quotes and slashes
    s = '{"quote": "She said: \\"Hello!\\"", "path": "C:\\\\Windows"}'
    err, out = string2json(s) # 6.52μs -> 5.84μs (11.6% faster)

def test_json_with_null_and_bool_values():
    # JSON containing null, true, false
    s = '{"ok": true, "fail": false, "empty": null}'
    err, out = string2json(s) # 5.34μs -> 4.70μs (13.7% faster)

def test_json_with_numbers_and_arrays():
    # JSON with numbers and arrays
    s = '{"nums": [0, 1, 2.5, -3], "count": 4}'
    err, out = string2json(s) # 6.56μs -> 6.05μs (8.40% faster)

def test_json_markdown_block_case_insensitive():
    # Markdown block with 'JSON' in uppercase
    s = "```JSON{\"foo\": 42}```"
    err, out = string2json(s) # 5.98μs -> 5.63μs (6.31% faster)

def test_json_markdown_block_with_extra_text():
    # Markdown block with extra text before/after
    s = "Some info\n```json{\"data\":123}```\nMore info"
    err, out = string2json(s) # 5.76μs -> 5.25μs (9.78% faster)

def test_json_markdown_block_with_leading_and_trailing_newlines():
    # Markdown block with newlines before and after JSON
    s = "```json\n{\"a\":1}\n```"
    err, out = string2json(s) # 5.71μs -> 5.09μs (12.2% faster)

def test_json_markdown_block_with_nested_braces():
    # JSON with nested objects inside markdown block
    s = "```json{\"outer\": {\"inner\": {\"x\": 1}}}```"
    err, out = string2json(s) # 6.21μs -> 5.67μs (9.64% faster)

def test_json_block_with_leading_and_trailing_spaces():
    # Markdown block with spaces before/after JSON
    s = "```json   { \"key\": \"value\" }   ```"
    err, out = string2json(s) # 5.92μs -> 5.22μs (13.4% faster)

def test_json_block_with_comments():
    # JSON with comments (should fail, as comments are not valid in JSON)
    s = "```json{\n// comment\n\"a\": 1\n}```"
    err, out = string2json(s) # 702μs -> 665μs (5.54% faster)

def test_json_block_with_single_quotes():
    # JSON with single quotes (should fail, as JSON requires double quotes)
    s = "```json{'a': 1}```"
    err, out = string2json(s) # 667μs -> 629μs (6.10% faster)

def test_json_block_with_trailing_non_json():
    # Markdown block with valid JSON followed by extra text
    s = "```json{\"a\": 1} extra```"
    err, out = string2json(s) # 631μs -> 598μs (5.49% faster)

def test_json_with_large_numbers():
    # JSON with large integer and float values
    s = '{"bigint": 1234567890123456789, "bigfloat": 1.234567890123456789e+20}'
    err, out = string2json(s) # 9.54μs -> 8.73μs (9.39% faster)

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

def test_large_flat_json_object():
    # Large flat JSON object with 1000 key-value pairs
    obj = {f"key{i}": i for i in range(1000)}
    s = json.dumps(obj)
    err, out = string2json(s) # 115μs -> 109μs (5.92% faster)

def test_large_nested_json_object():
    # Large nested JSON object with depth 10 and width 10
    nested = val = 0
    for i in range(10):
        nested = {"level": i, "next": nested}
    s = json.dumps(nested)
    err, out = string2json(s) # 8.29μs -> 7.25μs (14.3% faster)
    # Check nesting depth
    cur = out
    for i in range(10):
        cur = cur["next"]

def test_large_json_array():
    # Large JSON array with 1000 elements
    arr = list(range(1000))
    s = json.dumps({"array": arr})
    err, out = string2json(s) # 34.9μs -> 32.8μs (6.35% faster)

def test_large_json_markdown_block():
    # Large JSON inside markdown block
    arr = [str(i) for i in range(1000)]
    s = f"```json{{\"data\": {json.dumps(arr)}}}```"
    err, out = string2json(s) # 111μs -> 108μs (2.69% faster)

def test_large_json_with_non_ascii():
    # Large JSON with non-ASCII characters
    arr = ["😀" * 10 for _ in range(1000)]
    s = json.dumps({"emojis": arr})
    err, out = string2json(s) # 217μs -> 204μs (6.52% faster)

def test_large_json_invalid_block():
    # Large JSON block with a single invalid character
    arr = list(range(1000))
    s = f"```json{{\"array\": {json.dumps(arr)}#}}```"  # invalid character '#'
    err, out = string2json(s) # 802μs -> 762μs (5.20% faster)

def test_large_json_multiple_blocks_only_first_used():
    # Multiple large JSON blocks, only the first is parsed
    arr1 = list(range(500))
    arr2 = list(range(500, 1000))
    s = f"```json{{\"arr\": {json.dumps(arr1)}}}```\n```json{{\"arr\": {json.dumps(arr2)}}}```"
    err, out = string2json(s) # 82.1μs -> 48.4μs (69.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-string2json-mh9x3e47 and push.

Codeflash

The optimization replaces `findall()` with `search()` in the regex pattern matching, delivering a **5% speedup** with particularly strong gains on specific test cases.

**Key optimization:**
- **Changed from `findall()` to `search()`**: Instead of scanning the entire string to find ALL JSON markdown blocks and creating a list, `search()` stops at the first match and returns a match object directly.
- **Direct group extraction**: Uses `match.group(1)` to extract the JSON content instead of indexing into a list of all matches.

**Why this is faster:**
- `findall()` must scan the entire input string even after finding the first match, while `search()` stops immediately after the first match
- `findall()` allocates memory for a list to store all matches, while `search()` returns a single match object
- The original code only uses the first match anyway, making the extra work wasteful

**Performance characteristics:**
- **Moderate gains (5-17%)** on typical single-block cases
- **Exceptional gains (up to 70%)** on inputs with multiple JSON blocks, since `search()` avoids scanning for subsequent blocks that aren't needed
- **Consistent improvements** across all test cases, from simple JSON strings to large nested objects
- **Largest benefits** appear in the `test_large_json_multiple_blocks_only_first_used` case (69.6% faster) where avoiding the scan for the second large block provides substantial savings

The optimization maintains identical behavior and error handling while eliminating unnecessary regex scanning and memory allocation.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 28, 2025 01:58
@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