Skip to content

⚡️ Speed up method JavaFunctionRanker.get_function_addressable_time by 1,245% in PR #1874 (java-tracer)#1875

Merged
misrasaurabh1 merged 1 commit intojava-tracerfrom
codeflash/optimize-pr1874-2026-03-19T06.41.55
Mar 19, 2026
Merged

⚡️ Speed up method JavaFunctionRanker.get_function_addressable_time by 1,245% in PR #1874 (java-tracer)#1875
misrasaurabh1 merged 1 commit intojava-tracerfrom
codeflash/optimize-pr1874-2026-03-19T06.41.55

Conversation

@codeflash-ai
Copy link
Contributor

@codeflash-ai codeflash-ai bot commented Mar 19, 2026

⚡️ This pull request contains optimizations for PR #1874

If you approve this dependent PR, these changes will be merged into the original PR branch java-tracer.

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


📄 1,245% (12.45x) speedup for JavaFunctionRanker.get_function_addressable_time in codeflash/benchmarking/function_ranker.py

⏱️ Runtime : 1.14 milliseconds 85.0 microseconds (best of 250 runs)

📝 Explanation and details

The original code performed a linear scan over self._ranking on every call to get_function_addressable_time, which rank_functions invokes repeatedly (once per function to filter, plus once per function to sort). The optimized version builds a hash map _ranking_by_name during __init__, replacing the O(n) loop with an O(1) dictionary lookup. Line profiler confirms the loop and comparison accounted for 94.7% of original runtime. When rank_functions calls get_function_addressable_time dozens or hundreds of times across a 1000-method ranking (as in test_large_number_of_methods_and_repeated_queries_perf_and_correctness), the lookup cost drops from ~293 µs to ~10 µs per call, yielding the 1244% overall speedup. The optimization also consolidates the two calls to get_addressable_time_ns in get_function_stats_summary into a single call, stored in a local variable, eliminating redundant work.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 128 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Click to see Generated Regression Tests
from pathlib import Path

# imports
import pytest  # used for our unit tests

# Import the real classes from the project under test
from codeflash.benchmarking.function_ranker import JavaFunctionRanker
from codeflash.languages.java.jfr_parser import JfrProfile
from codeflash.models.function_types import FunctionToOptimize


def test_returns_zero_for_nonexistent_function():
    # Create a JfrProfile instance (provide a harmless Path and empty packages list).
    # We will inject the internal data we need afterwards.
    jfr = JfrProfile(Path("nonexistent.jfr"), packages=[])
    # Populate internals so get_method_ranking would produce at least one entry,
    # but do NOT include the target function name.
    jfr._method_samples = {"com.example.ClassA.methodA": 10}
    jfr._method_info = {"com.example.ClassA.methodA": {"class_name": "com.example.ClassA", "method_name": "methodA"}}
    jfr._total_samples = 10
    jfr._recording_duration_ns = 1_000_000_000  # 1 second in ns

    # Now build the ranker which reads the ranking during initialization.
    ranker = JavaFunctionRanker(jfr)

    # Construct a FunctionToOptimize that is NOT present in the ranking.
    func = FunctionToOptimize(function_name="not_present", file_path=Path("/tmp/fake"))

    # Since the function does not exist in the profile, addressable time should be 0.0
    assert ranker.get_function_addressable_time(func) == 0.0  # 961ns -> 581ns (65.4% faster)


def test_addressable_time_with_recording_duration():
    # Create profile and inject a method with known sample count and totals.
    jfr = JfrProfile(Path("dummy.jfr"), packages=[])
    jfr._method_samples = {"com.example.HotClass.hotMethod": 25}
    jfr._method_info = {
        "com.example.HotClass.hotMethod": {"class_name": "com.example.HotClass", "method_name": "hotMethod"}
    }
    jfr._total_samples = 100  # so method fraction = 0.25
    # recording duration in nanoseconds: use a value that yields an integer when multiplied
    jfr._recording_duration_ns = 4_000_000_000  # 4 seconds in ns

    # Initialize ranker (reads ranking on init)
    ranker = JavaFunctionRanker(jfr)

    # Create the FunctionToOptimize matching the method_name used above.
    func = FunctionToOptimize(function_name="hotMethod", file_path=Path("/tmp/fake"))

    # Expected time = (25 / 100) * 4_000_000_000 = 1_000_000_000 ns
    expected = (25 / 100) * 4_000_000_000
    result = ranker.get_function_addressable_time(func)  # 3.29μs -> 1.72μs (90.8% faster)
    # Use exact equality because values are derived from integer arithmetic producing an exact float
    assert result == expected


def test_zero_total_samples_yields_zero_addressable_time_even_if_method_present():
    # If total samples is zero, addressable_time should be 0.0 regardless of sample counts.
    jfr = JfrProfile(Path("dummy.jfr"), packages=[])
    jfr._method_samples = {"A.b": 50}
    jfr._method_info = {"A.b": {"class_name": "A", "method_name": "b"}}
    jfr._total_samples = 0  # important: zero total samples
    jfr._recording_duration_ns = 10_000_000_000

    ranker = JavaFunctionRanker(jfr)
    func = FunctionToOptimize(function_name="b", file_path=Path("/tmp/fake"))
    assert ranker.get_function_addressable_time(func) == 0.0  # 801ns -> 590ns (35.8% faster)


def test_fallback_to_sample_count_proxy_when_no_recording_duration():
    # When recording duration is zero, JfrProfile falls back to sample_count * 1_000_000
    jfr = JfrProfile(Path("dummy.jfr"), packages=[])
    jfr._method_samples = {"X.y": 7}
    jfr._method_info = {"X.y": {"class_name": "X", "method_name": "y"}}
    jfr._total_samples = 100  # non-zero to avoid the other zero branch
    jfr._recording_duration_ns = 0  # triggers the fallback branch

    ranker = JavaFunctionRanker(jfr)
    func = FunctionToOptimize(function_name="y", file_path=Path("/tmp/fake"))

    # Fallback expected value = sample_count * 1_000_000 = 7_000_000.0
    assert ranker.get_function_addressable_time(func) == float(7 * 1_000_000)  # 3.21μs -> 1.76μs (81.8% faster)


def test_method_names_with_special_characters_and_unicode():
    # Ensure matching still works if method/class names have unusual characters.
    jfr = JfrProfile(Path("dummy.jfr"), packages=[])
    special_class = "com.example.クラス"  # contains unicode
    special_method = "weird method$name"  # contains space and symbol
    key = f"{special_class}.{special_method}"
    jfr._method_samples = {key: 3}
    jfr._method_info = {key: {"class_name": special_class, "method_name": special_method}}
    jfr._total_samples = 3
    jfr._recording_duration_ns = 3_000_000_000  # 3 seconds => method should get full duration

    ranker = JavaFunctionRanker(jfr)
    # The FunctionToOptimize only cares about function_name when matching in the ranker,
    # so provide the exact method name.
    func = FunctionToOptimize(function_name=special_method, file_path=Path("/tmp/fake"))

    assert ranker.get_function_addressable_time(func) == pytest.approx(
        3_000_000_000.0
    )  # 3.51μs -> 1.93μs (81.4% faster)


def test_large_number_of_methods_and_repeated_queries_perf_and_correctness():
    # Create a profile with many methods (1_000) to test scalability and ranking behavior.
    num_methods = 1000
    jfr = JfrProfile(Path("big.jfr"), packages=[])
    jfr._method_samples = {}
    jfr._method_info = {}
    total = 0

    # Populate methods with deterministic sample counts so expected values are known.
    for i in range(num_methods):
        class_name = f"pkg.Class{i}"
        method_name = f"m{i}"
        key = f"{class_name}.{method_name}"
        # sample count cycles between 1 and 10 (so never zero)
        sample_count = (i % 10) + 1
        jfr._method_samples[key] = sample_count
        jfr._method_info[key] = {"class_name": class_name, "method_name": method_name}
        total += sample_count

    jfr._total_samples = total
    # Use a non-zero recording duration so addressable times are fractions of this duration.
    jfr._recording_duration_ns = 5_000_000_000  # 5 seconds in ns

    # Initialize ranker (will sort and cache the ranking)
    ranker = JavaFunctionRanker(jfr)

    # Query methods with diverse, scattered indices to avoid cache optimization benefits.
    # Use indices spread across the entire range to simulate production access patterns.
    scattered_indices = [0, 999, 17, 823, 111, 742, 333, 500, 29, 456, 88, 234, 701, 445, 612]
    for idx in scattered_indices:
        class_name = f"pkg.Class{idx}"
        method_name = f"m{idx}"
        func = FunctionToOptimize(function_name=method_name, file_path=Path("/tmp/fake"))

        # Expected value computed directly using the JfrProfile instance method for consistency.
        expected = jfr.get_addressable_time_ns(class_name, method_name)
        result = ranker.get_function_addressable_time(func)  # 293μs -> 10.3μs (2745% faster)
        # Use approximate equality due to floating point arithmetic; tolerance tiny.
        assert abs(result - expected) < 1e-6

    # Query additional methods with different sample count patterns to exercise variation.
    # Use non-contiguous indices from different regions to avoid sequential access patterns.
    varied_indices = [2, 111, 345, 567, 789, 123, 654, 987, 11, 89, 234, 456, 678, 901, 555]
    for idx in varied_indices:
        class_name = f"pkg.Class{idx}"
        method_name = f"m{idx}"
        func = FunctionToOptimize(function_name=method_name, file_path=Path("/tmp/fake"))
        expected = jfr.get_addressable_time_ns(class_name, method_name)
        result = ranker.get_function_addressable_time(func)  # 246μs -> 9.47μs (2502% faster)
        assert abs(result - expected) < 1e-6

    # Query edge case methods at various boundary positions.
    boundary_indices = [0, 1, 10, 99, 100, 500, 900, 990, 998, 999]
    for idx in boundary_indices:
        class_name = f"pkg.Class{idx}"
        method_name = f"m{idx}"
        func = FunctionToOptimize(function_name=method_name, file_path=Path("/tmp/fake"))
        expected = jfr.get_addressable_time_ns(class_name, method_name)
        result = ranker.get_function_addressable_time(func)  # 233μs -> 6.08μs (3737% faster)
        assert abs(result - expected) < 1e-6

    # As an additional sanity check, ensure total_samples sums to what we set.
    assert jfr._total_samples == total
from pathlib import Path

# imports
from codeflash.benchmarking.function_ranker import JavaFunctionRanker
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
from codeflash.languages.java.jfr_parser import JfrProfile


# Helper function to create real FunctionToOptimize instances
def create_function_to_optimize(
    function_name: str = "testFunc", file_path: str = "/path/to/Test.java", parents: list = None
) -> FunctionToOptimize:
    """Create a real FunctionToOptimize instance for testing."""
    return FunctionToOptimize(
        function_name=function_name, file_path=Path(file_path), parents=parents if parents is not None else []
    )


# Helper function to create a real JfrProfile with mocked internal data
def create_jfr_profile_with_data(
    method_samples: dict = None,
    method_info: dict = None,
    recording_duration_ns: int = 1_000_000_000,
    total_samples: int = 100,
) -> JfrProfile:
    """Create a real JfrProfile instance and populate it with test data."""
    # Create a JfrProfile with a dummy path and empty packages list
    jfr_profile = JfrProfile(jfr_file=Path("/tmp/dummy.jfr"), packages=[])

    # Populate internal state directly
    jfr_profile._method_samples = method_samples if method_samples is not None else {}
    jfr_profile._method_info = method_info if method_info is not None else {}
    jfr_profile._recording_duration_ns = recording_duration_ns
    jfr_profile._total_samples = total_samples

    return jfr_profile


def test_get_function_addressable_time_returns_float():
    """Test that the function returns a float type."""
    # Create test data: one method with 50 samples out of 100 total
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    # Create JfrProfile with test data
    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=100
    )

    # Create ranker
    ranker = JavaFunctionRanker(jfr_profile)

    # Create function to optimize
    func = create_function_to_optimize(function_name="myMethod")

    # Call the function and verify it returns a float
    result = ranker.get_function_addressable_time(func)  # 3.12μs -> 1.64μs (89.6% faster)
    assert isinstance(result, float)


def test_get_function_addressable_time_basic_calculation():
    """Test that addressable time is calculated correctly for a found method."""
    # Create test data: method with 50 samples out of 100, recording is 1 second
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=1_000_000_000,  # 1 second
        total_samples=100,
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="myMethod")

    # Expected: (50 / 100) * 1_000_000_000 = 500_000_000 ns
    result = ranker.get_function_addressable_time(func)  # 3.02μs -> 1.63μs (85.2% faster)
    assert result == 500_000_000.0


def test_get_function_addressable_time_function_not_found():
    """Test that the function returns 0.0 when the method is not found in ranking."""
    # Create test data with one method
    method_samples = {"com.example.TestClass.methodA": 50}
    method_info = {"com.example.TestClass.methodA": {"class_name": "com.example.TestClass", "method_name": "methodA"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=100
    )

    ranker = JavaFunctionRanker(jfr_profile)
    # Try to find a method that doesn't exist
    func = create_function_to_optimize(function_name="nonExistentMethod")

    result = ranker.get_function_addressable_time(func)  # 912ns -> 640ns (42.5% faster)
    assert result == 0.0


def test_get_function_addressable_time_single_sample():
    """Test calculation with a method that has only one sample."""
    method_samples = {"com.example.TestClass.smallMethod": 1}
    method_info = {
        "com.example.TestClass.smallMethod": {"class_name": "com.example.TestClass", "method_name": "smallMethod"}
    }

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=1000
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="smallMethod")

    # Expected: (1 / 1000) * 1_000_000_000 = 1_000_000 ns
    result = ranker.get_function_addressable_time(func)  # 3.02μs -> 1.64μs (84.2% faster)
    assert result == 1_000_000.0


def test_get_function_addressable_time_majority_of_samples():
    """Test calculation when method has the majority of samples."""
    method_samples = {"com.example.TestClass.hotMethod": 90}
    method_info = {
        "com.example.TestClass.hotMethod": {"class_name": "com.example.TestClass", "method_name": "hotMethod"}
    }

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=10_000_000_000,  # 10 seconds
        total_samples=100,
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="hotMethod")

    # Expected: (90 / 100) * 10_000_000_000 = 9_000_000_000 ns
    result = ranker.get_function_addressable_time(func)  # 3.04μs -> 1.76μs (72.8% faster)
    assert result == 9_000_000_000.0


def test_get_function_addressable_time_empty_method_samples():
    """Test behavior when there are no method samples in the profile."""
    jfr_profile = create_jfr_profile_with_data(
        method_samples={}, method_info={}, recording_duration_ns=1_000_000_000, total_samples=0
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="anyMethod")

    # Should return 0.0 when no methods are available
    result = ranker.get_function_addressable_time(func)  # 781ns -> 571ns (36.8% faster)
    assert result == 0.0


def test_get_function_addressable_time_zero_recording_duration():
    """Test calculation when recording duration is zero."""
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=0,  # Zero duration
        total_samples=100,
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="myMethod")

    # When recording_duration_ns is 0, get_addressable_time_ns falls back to sample count * 1_000_000
    # Expected: 50 * 1_000_000 = 50_000_000
    result = ranker.get_function_addressable_time(func)  # 3.27μs -> 1.82μs (79.2% faster)
    assert result == 50_000_000.0


def test_get_function_addressable_time_zero_total_samples():
    """Test calculation when total samples is zero."""
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=1_000_000_000,
        total_samples=0,  # Zero total samples
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="myMethod")

    # When total_samples is 0, get_addressable_time_ns should return 0.0
    result = ranker.get_function_addressable_time(func)  # 771ns -> 611ns (26.2% faster)
    assert result == 0.0


def test_get_function_addressable_time_case_sensitive_matching():
    """Test that method name matching is case-sensitive."""
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=100
    )

    ranker = JavaFunctionRanker(jfr_profile)
    # Try with different case
    func = create_function_to_optimize(function_name="MyMethod")

    result = ranker.get_function_addressable_time(func)  # 972ns -> 641ns (51.6% faster)
    assert result == 0.0  # Should not match due to case difference


def test_get_function_addressable_time_very_small_percentage():
    """Test calculation with very small percentage of samples."""
    method_samples = {"com.example.TestClass.tinyMethod": 1}
    method_info = {
        "com.example.TestClass.tinyMethod": {"class_name": "com.example.TestClass", "method_name": "tinyMethod"}
    }

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=10_000_000_000,  # 10 seconds
        total_samples=1_000_000,  # Very many total samples
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="tinyMethod")

    # Expected: (1 / 1_000_000) * 10_000_000_000 = 10_000 ns
    result = ranker.get_function_addressable_time(func)  # 3.27μs -> 1.76μs (85.9% faster)
    assert result == 10_000.0


def test_get_function_addressable_time_very_large_recording_duration():
    """Test calculation with very large recording duration."""
    method_samples = {"com.example.TestClass.myMethod": 500}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    # 1 hour in nanoseconds
    one_hour_ns = 3_600_000_000_000

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=one_hour_ns, total_samples=1000
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="myMethod")

    # Expected: (500 / 1000) * 3_600_000_000_000 = 1_800_000_000_000 ns
    result = ranker.get_function_addressable_time(func)  # 3.09μs -> 1.65μs (87.2% faster)
    assert result == 1_800_000_000_000.0


def test_get_function_addressable_time_exact_match_required():
    """Test that method name must match exactly as stored in ranking."""
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=100
    )

    ranker = JavaFunctionRanker(jfr_profile)
    # Try partial match
    func = create_function_to_optimize(function_name="Method")

    result = ranker.get_function_addressable_time(func)  # 931ns -> 621ns (49.9% faster)
    assert result == 0.0


def test_get_function_addressable_time_special_characters_in_name():
    """Test with special characters in method name."""
    method_samples = {"com.example.TestClass.<init>": 30}
    method_info = {"com.example.TestClass.<init>": {"class_name": "com.example.TestClass", "method_name": "<init>"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=100
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="<init>")

    # Expected: (30 / 100) * 1_000_000_000 = 300_000_000 ns
    result = ranker.get_function_addressable_time(func)  # 2.96μs -> 1.55μs (91.0% faster)
    assert result == 300_000_000.0


def test_get_function_addressable_time_all_samples_in_one_method():
    """Test when all samples are attributed to a single method."""
    method_samples = {"com.example.TestClass.onlyMethod": 1000}
    method_info = {
        "com.example.TestClass.onlyMethod": {"class_name": "com.example.TestClass", "method_name": "onlyMethod"}
    }

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=2_000_000_000,  # 2 seconds
        total_samples=1000,
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="onlyMethod")

    # Expected: (1000 / 1000) * 2_000_000_000 = 2_000_000_000 ns
    result = ranker.get_function_addressable_time(func)  # 3.09μs -> 1.73μs (78.6% faster)
    assert result == 2_000_000_000.0


def test_get_function_addressable_time_empty_string_function_name():
    """Test with empty string as function name."""
    method_samples = {"com.example.TestClass.myMethod": 50}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=100
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="")

    result = ranker.get_function_addressable_time(func)  # 921ns -> 611ns (50.7% faster)
    assert result == 0.0


def test_get_function_addressable_time_many_methods_in_ranking():
    """Test with a large number of methods in the ranking."""
    # Create 1000 methods with varying sample counts
    method_samples = {f"com.example.TestClass.method{i}": (i + 1) * 10 for i in range(1000)}
    method_info = {
        f"com.example.TestClass.method{i}": {"class_name": "com.example.TestClass", "method_name": f"method{i}"}
        for i in range(1000)
    }

    # Calculate total samples
    total_samples = sum(method_samples.values())

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=1_000_000_000,
        total_samples=total_samples,
    )

    ranker = JavaFunctionRanker(jfr_profile)

    # Test lookup of a method in the middle
    func = create_function_to_optimize(function_name="method500")
    result = ranker.get_function_addressable_time(func)  # 20.6μs -> 1.85μs (1013% faster)

    # method500 has samples = 501 * 10 = 5010
    # Expected: (5010 / total_samples) * 1_000_000_000
    expected = (5010 / total_samples) * 1_000_000_000
    assert abs(result - expected) < 0.01  # Allow small floating point difference


def test_get_function_addressable_time_lookup_last_method_in_ranking():
    """Test lookup performance for the last method in a large ranking."""
    # Create 1000 methods
    method_samples = {f"com.example.TestClass.method{i}": (i + 1) * 10 for i in range(1000)}
    method_info = {
        f"com.example.TestClass.method{i}": {"class_name": "com.example.TestClass", "method_name": f"method{i}"}
        for i in range(1000)
    }

    total_samples = sum(method_samples.values())

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=1_000_000_000,
        total_samples=total_samples,
    )

    ranker = JavaFunctionRanker(jfr_profile)

    # Test lookup of the last method
    func = create_function_to_optimize(function_name="method999")
    result = ranker.get_function_addressable_time(func)  # 3.33μs -> 1.77μs (88.1% faster)

    # method999 has samples = 1000 * 10 = 10000
    expected = (10000 / total_samples) * 1_000_000_000
    assert abs(result - expected) < 0.01


def test_get_function_addressable_time_lookup_first_method_in_ranking():
    """Test lookup performance for the first method in a large ranking."""
    # Create 1000 methods
    method_samples = {f"com.example.TestClass.method{i}": (i + 1) * 10 for i in range(1000)}
    method_info = {
        f"com.example.TestClass.method{i}": {"class_name": "com.example.TestClass", "method_name": f"method{i}"}
        for i in range(1000)
    }

    total_samples = sum(method_samples.values())

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=1_000_000_000,
        total_samples=total_samples,
    )

    ranker = JavaFunctionRanker(jfr_profile)

    # Test lookup of the first method
    func = create_function_to_optimize(function_name="method0")
    result = ranker.get_function_addressable_time(func)  # 36.3μs -> 1.89μs (1815% faster)

    # method0 has samples = 1 * 10 = 10
    expected = (10 / total_samples) * 1_000_000_000
    assert abs(result - expected) < 0.01


def test_get_function_addressable_time_multiple_lookups_large_ranking():
    """Test multiple sequential lookups on a large ranking with diverse inputs."""
    # Create 500 methods
    method_samples = {f"com.example.TestClass.method{i}": (i + 1) * 5 for i in range(500)}
    method_info = {
        f"com.example.TestClass.method{i}": {"class_name": "com.example.TestClass", "method_name": f"method{i}"}
        for i in range(500)
    }

    total_samples = sum(method_samples.values())

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples,
        method_info=method_info,
        recording_duration_ns=5_000_000_000,
        total_samples=total_samples,
    )

    ranker = JavaFunctionRanker(jfr_profile)

    # Perform lookups with diverse, non-repetitive indices
    test_indices = [
        0,
        123,
        250,
        376,
        499,
        50,
        299,
        75,
        450,
        1,
        499,
        100,
        256,
        400,
        10,
        350,
        25,
        475,
        111,
        333,
        456,
        200,
        15,
        380,
        490,
    ]
    for method_idx in test_indices:
        func = create_function_to_optimize(function_name=f"method{method_idx}")
        result = ranker.get_function_addressable_time(func)  # 244μs -> 18.2μs (1245% faster)

        # Verify result is reasonable
        assert result >= 0.0
        assert isinstance(result, float)

        # Verify calculation accuracy for this specific method
        expected = ((method_idx + 1) * 5 / total_samples) * 5_000_000_000
        assert abs(result - expected) < 0.01


def test_get_function_addressable_time_high_precision_calculation():
    """Test calculation accuracy with high-precision input values."""
    method_samples = {"com.example.TestClass.preciseMethod": 333}
    method_info = {
        "com.example.TestClass.preciseMethod": {"class_name": "com.example.TestClass", "method_name": "preciseMethod"}
    }

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=999_999_999, total_samples=777
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="preciseMethod")

    result = ranker.get_function_addressable_time(func)  # 3.06μs -> 1.66μs (84.4% faster)
    expected = (333 / 777) * 999_999_999

    # Should be very close due to floating point precision
    assert abs(result - expected) < 0.1


def test_get_function_addressable_time_repeated_calls_consistency():
    """Test that repeated calls with diverse methods return correct values."""
    method_samples = {
        "com.example.TestClass.methodX": 40,
        "com.example.TestClass.methodY": 60,
        "com.example.TestClass.methodZ": 35,
        "com.example.TestClass.methodW": 25,
    }
    method_info = {
        "com.example.TestClass.methodX": {"class_name": "com.example.TestClass", "method_name": "methodX"},
        "com.example.TestClass.methodY": {"class_name": "com.example.TestClass", "method_name": "methodY"},
        "com.example.TestClass.methodZ": {"class_name": "com.example.TestClass", "method_name": "methodZ"},
        "com.example.TestClass.methodW": {"class_name": "com.example.TestClass", "method_name": "methodW"},
    }

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=1_000_000_000, total_samples=160
    )

    ranker = JavaFunctionRanker(jfr_profile)

    # Test different methods with varied, non-repetitive access patterns
    test_methods = [
        ("methodZ", 35 / 160 * 1_000_000_000),
        ("methodW", 25 / 160 * 1_000_000_000),
        ("methodX", 40 / 160 * 1_000_000_000),
        ("methodY", 60 / 160 * 1_000_000_000),
        ("methodW", 25 / 160 * 1_000_000_000),
        ("methodZ", 35 / 160 * 1_000_000_000),
        ("methodY", 60 / 160 * 1_000_000_000),
        ("methodX", 40 / 160 * 1_000_000_000),
        ("methodW", 25 / 160 * 1_000_000_000),
        ("methodY", 60 / 160 * 1_000_000_000),
    ]

    for method_name, expected in test_methods:
        func = create_function_to_optimize(function_name=method_name)
        result = ranker.get_function_addressable_time(func)  # 15.0μs -> 6.78μs (121% faster)

        # Verify consistency and correctness
        assert result == expected
        assert isinstance(result, float)


def test_get_function_addressable_time_fractional_contribution():
    """Test calculation with methods contributing fractional time."""
    method_samples = {"com.example.TestClass.myMethod": 33}
    method_info = {"com.example.TestClass.myMethod": {"class_name": "com.example.TestClass", "method_name": "myMethod"}}

    jfr_profile = create_jfr_profile_with_data(
        method_samples=method_samples, method_info=method_info, recording_duration_ns=999_999_999, total_samples=777
    )

    ranker = JavaFunctionRanker(jfr_profile)
    func = create_function_to_optimize(function_name="myMethod")

    result = ranker.get_function_addressable_time(func)  # 2.79μs -> 1.54μs (80.6% faster)
    expected = (33 / 777) * 999_999_999

    # Verify floating point result is close
    assert abs(result - expected) < 1.0  # Allow 1 ns tolerance due to floating point

To edit these changes git checkout codeflash/optimize-pr1874-2026-03-19T06.41.55 and push.

Codeflash Static Badge

The original code performed a linear scan over `self._ranking` on every call to `get_function_addressable_time`, which `rank_functions` invokes repeatedly (once per function to filter, plus once per function to sort). The optimized version builds a hash map `_ranking_by_name` during `__init__`, replacing the O(n) loop with an O(1) dictionary lookup. Line profiler confirms the loop and comparison accounted for 94.7% of original runtime. When `rank_functions` calls `get_function_addressable_time` dozens or hundreds of times across a 1000-method ranking (as in `test_large_number_of_methods_and_repeated_queries_perf_and_correctness`), the lookup cost drops from ~293 µs to ~10 µs per call, yielding the 1244% overall speedup. The optimization also consolidates the two calls to `get_addressable_time_ns` in `get_function_stats_summary` into a single call, stored in a local variable, eliminating redundant work.
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Mar 19, 2026
@misrasaurabh1 misrasaurabh1 merged commit 59f34d8 into java-tracer Mar 19, 2026
19 of 28 checks passed
@misrasaurabh1 misrasaurabh1 deleted the codeflash/optimize-pr1874-2026-03-19T06.41.55 branch March 19, 2026 06:49
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