Skip to content

test(benchmarks): run shared logging executor inline to make CodSpeed measurements deterministic - #32435

Merged
yassin-berriai merged 1 commit into
litellm_internal_stagingfrom
litellm_lit4260_hermetic_codspeed_benchmarks
Jul 9, 2026
Merged

test(benchmarks): run shared logging executor inline to make CodSpeed measurements deterministic#32435
yassin-berriai merged 1 commit into
litellm_internal_stagingfrom
litellm_lit4260_hermetic_codspeed_benchmarks

Conversation

@yassin-berriai

@yassin-berriai yassin-berriai commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Resolves LIT-4260

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Before (unfixed, observed on production CI over a 12h window ending 2026-07-08 06:20 UTC): the CodSpeed Performance Analysis check flagged false regressions on 10 of ~40 PR heads, always in the three completion benchmarks of tests/benchmarks/test_inference_benchmarks.py and never in the other 27 benchmarks. The measurements are bimodal, with the same ~1.0-1.6 ms cost roaming between benchmarks run to run. For example, at PR head 661db9a (compared against staging 6df5e1b) the report read test_completion_multi_turn 3.1 ms -> 4.2 ms (-25.9%), test_completion_simple_message 3.8 ms -> 4.7 ms (-17.96%), test_completion_with_tools 4.2 ms -> 3.2 ms (+30.98%); at PR head db24027 the same benchmarks flipped the other way. BASE values for unchanged staging code also flap (test_completion_simple_message was variously 3.2, 3.8, 4.1, 4.6 and 4.8 ms across the window), proving the instability is benchmark-internal rather than caused by any PR's diff

After (this PR, head 8da870f): the CodSpeed workflow was run twice on the same commit (run 28923307313 and its rerun) and the reports agree on every benchmark. test_completion_multi_turn measured 3.8 ms in both runs and test_completion_simple_message 3.9 ms in both, with the reported efficiency deltas differing by only 0.06 percentage points between runs (-17.65% vs -17.71%, +16.75% vs +16.77%); before the fix, two runs of the same code flipped by 25 to 47 points. The new values also confirm the mechanism: they equal the old fast mode (3.1/3.2 ms) plus exactly one success handler, meaning each measurement now contains precisely its own work

Note for reviewers: the CodSpeed check on this PR reads as a small regression by design, for two reasons that both resolve on merge. The BASE it compares against is staging's still-flapping measurement, and the handler cost that was previously attributed to a random benchmark is now deterministically included, shifting the completion benchmarks up by ~0.7 ms once. The shift should be acknowledged on the CodSpeed dashboard; the property that matters, reruns of the same commit agreeing, is demonstrated above

Type

✅ Test
🚄 Infrastructure

Changes

The three completion benchmarks call litellm.completion(..., mock_response=...), and each such call submits its success handler (cost calculation, response copying) to the shared ThreadPoolExecutor in litellm/litellm_core_utils/thread_pool_executor.py (submitted from the sync wrapper in litellm/utils.py). pytest-codspeed's simulation mode runs one warmup call and one measured call, toggling callgrind instrumentation around the measured call only. Callgrind counts instructions from every thread while the window is open, and valgrind serializes all threads onto one virtual CPU, so the queued handler work lands inside whichever benchmark's measured window the valgrind scheduler happens to resume it under. GC and random are already neutralized by pytest-codspeed itself (gc.collect(); gc.disable() and random.seed(0) around every measurement), which is why the flakiness only ever appeared in the benchmarks that enqueue background work

This PR adds tests/benchmarks/conftest.py with a session-scoped autouse fixture that replaces the shared executor's submit with an inline implementation for the benchmark session, so every measurement contains exactly its own work. This is deterministic and also more representative of the true per-request cost. A guard benchmark, test_logging_executor_runs_inline, asserts that submissions through the shared executor complete inline on the calling thread; it fails immediately if the fixture is removed (verified by running it with the conftest moved aside)

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes flaky CodSpeed benchmark measurements by ensuring that work submitted to litellm's shared ThreadPoolExecutor runs synchronously on the calling thread during benchmark sessions, rather than being attributed to whichever benchmark's callgrind window valgrind happens to resume it under.

  • Adds tests/benchmarks/conftest.py with a session-scoped autouse fixture that monkey-patches executor.submit with an inline implementation; the patch is cleanly removed via del executor.submit after the session, correctly restoring the class-level method.
  • Adds a guard test test_logging_executor_runs_inline to test_benchmarks.py that verifies both that the future completes immediately and that the work ran on the calling thread, ensuring the fixture removal will be caught quickly.

Confidence Score: 5/5

Safe to merge — changes are confined to the test benchmarks directory and do not touch any production code.

The implementation is correct: _submit_inline faithfully mirrors ThreadPoolExecutor._WorkItem.run() (same except BaseException pattern, same future state transitions), the Python 3.10+ type annotations (ParamSpec, collections.abc.Callable) match the project's requires-python >= 3.10 floor, the del executor.submit teardown correctly restores the class method via normal attribute lookup, and the guard test reliably detects fixture removal by asserting both immediate completion and calling-thread identity.

No files require special attention.

Important Files Changed

Filename Overview
tests/benchmarks/conftest.py New session-scoped autouse fixture that replaces ThreadPoolExecutor.submit with an inline implementation to make CodSpeed callgrind measurements hermetic; implementation is correct and well-documented.
tests/benchmarks/test_benchmarks.py Adds a guard benchmark (test_logging_executor_runs_inline) that verifies the patched executor runs inline and on the calling thread; the assertion is reliable and will catch fixture removal.

Reviews (1): Last reviewed commit: "test(benchmarks): run shared logging exe..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

⚡ 1 improved benchmark
❌ 1 regressed benchmark
✅ 28 untouched benchmarks
🆕 1 new benchmark

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
test_completion_multi_turn 3.1 ms 3.8 ms -17.71%
test_completion_simple_message 4.6 ms 3.9 ms +16.77%
🆕 test_logging_executor_runs_inline N/A 128.3 µs N/A

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing litellm_lit4260_hermetic_codspeed_benchmarks (8da870f) with litellm_internal_staging (d6cbf6e)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (bcd5275) during the generation of this report, so d6cbf6e was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@mateo-berri mateo-berri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; thanks!

@yassin-berriai
yassin-berriai merged commit 60729f7 into litellm_internal_staging Jul 9, 2026
126 of 127 checks passed
@yassin-berriai
yassin-berriai deleted the litellm_lit4260_hermetic_codspeed_benchmarks branch July 9, 2026 08:14
edelauna pushed a commit to edelauna/litellm that referenced this pull request Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants