Repository navigation
Fix native socket hook timestamp sequencing (PROF-16151) - #862
Conversation
Sequence the original I/O call before reading its end timestamp in send, recv, write, and read hooks so socket durations do not depend on function-argument evaluation order. Add test-only timestamp observation and regression tests for all four hooks, non-positive results, and delayed socketpair receives.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
More details
All four socket hooks now take the end timestamp after the original I/O call, ensuring recorded durations include blocking time. The test observer remains restricted to unit-test builds.
🤖 Bits Code Review · Commit 5e77163
CI Test ResultsRun: #38586942935 | Commit:
Status Overview
Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled Summary: Total: 32 | Passed: 32 | Failed: 0 Updated: 2026-10-14 15:30:24 UTC |
| ssize_t ret = fn(fd, buf, len, flags); | ||
| u64 t1 = TSC::ticks(); | ||
| return record_if_positive(fd, ret, t0, t1, 0); |
| #endif | ||
| // Separate full expressions ensure the end timestamp follows I/O regardless | ||
| // of the compiler's function-argument evaluation order. | ||
| u64 t0 = TSC::ticks(); |
There was a problem hiding this comment.
We probably should switch to monotonic timer.
What does this PR do?:
Explicitly sequence the original I/O call before the end timestamp in
NativeSocketSampler'ssend,recv,write, andreadhooks:Add regression tests that observe the real hooks' recorder arguments, check timestamp bracketing for all four operations, preserve non-positive return handling, and exercise blocking
recv/readwith a delayed peer over a socketpair.Motivation:
PROF-16151: C++ does not specify function-argument evaluation order. Previously the original I/O call and the end timestamp were separate arguments to
record_if_positive, permitting the timestamp to be read before I/O. This excludes blocking time from durations and distorts duration-based sampling and weights.Reproduced with GCC 11.4 in both debug and the optimized native release test configuration (
-O3): all four timestamp-order checks and both blocking receive tests failed before the fix. Approximately 50 ms of socket wait produced hook durations of only 39–50 ns in debug and 40–52 ns in release. In an isolated worktree, the same six release regression cases failed in each of 10 consecutive runs; restoring the fix made all applicable regression cases pass in each of 10 consecutive runs.Additional Notes:
UNIT_TEST; recording still follows the normal production path, including its stopped-profiler guard. Symbol inspection confirms the observer is absent from the production debug library.-O3andUNIT_TEST, with gtest assertions enabled. They observe the actual hook timestamps and use real blocking socketpair I/O, but are not end-to-end runs of the packaged production library/JFR recording. Fixed native tests pass with GCC and Clang in both configurations.How to test the change?:
Validated locally on Linux x64:
./.claude/commands/build-and-summarize \ :ddprof-lib:gtestDebug_nativeSocketSampler_ut \ :ddprof-lib:gtestRelease_nativeSocketSampler_ut \ -Pnative.forceCompiler=g++ ./.claude/commands/build-and-summarize \ :ddprof-lib:gtestDebug_nativeSocketSampler_ut \ :ddprof-lib:gtestRelease_nativeSocketSampler_ut \ -Pnative.forceCompiler=clang++ ./.claude/commands/build-and-summarize :ddprof-test:testDebug \ '-Ptests=*.nativesocket.*' -Pnative.forceCompiler=g++ ./.claude/commands/build-and-summarize testDebug -Pnative.forceCompiler=clang++ ./.claude/commands/build-and-summarize spotlessApplynativeSocketSampler_ut '--gtest_filter=AllHooks/NativeSocketSamplerTimingTest.*' --gtest_repeat=10. Unfixed: the same six regression failures in all 10 runs. Fixed: all 10 applicable regression cases passed in all 10 runs; the full native suite also passed (28 passed, 2 skipped, 0 failed).testDebugwith Clang: 206 passed, 19 skipped, 0 failed.git diff --checkpassed.For Datadog employees: