Fix race condition in IpcTests#8657
Conversation
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8657) and master. ✅ No regressions detected - check the details below Full Metrics ComparisonFakeDbCommand
HttpMessageHandler
Comparison explanationExecution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:
Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard. Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph). Duration chartsFakeDbCommand (.NET Framework 4.8)gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (72ms) : 70, 75
master - mean (74ms) : 70, 78
section Bailout
This PR (8657) - mean (77ms) : 75, 79
master - mean (79ms) : 75, 83
section CallTarget+Inlining+NGEN
This PR (8657) - mean (1,110ms) : 1054, 1166
master - mean (1,102ms) : 1048, 1157
FakeDbCommand (.NET Core 3.1)gantt
title Execution time (ms) FakeDbCommand (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (113ms) : 109, 117
master - mean (117ms) : 111, 122
section Bailout
This PR (8657) - mean (116ms) : 110, 123
master - mean (115ms) : 111, 119
section CallTarget+Inlining+NGEN
This PR (8657) - mean (786ms) : 763, 808
master - mean (794ms) : 770, 818
FakeDbCommand (.NET 6)gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (103ms) : 98, 108
master - mean (101ms) : 99, 104
section Bailout
This PR (8657) - mean (101ms) : 99, 103
master - mean (101ms) : 100, 103
section CallTarget+Inlining+NGEN
This PR (8657) - mean (953ms) : 915, 990
master - mean (945ms) : 901, 989
FakeDbCommand (.NET 8)gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (101ms) : 95, 107
master - mean (102ms) : 96, 108
section Bailout
This PR (8657) - mean (103ms) : 98, 108
master - mean (103ms) : 94, 112
section CallTarget+Inlining+NGEN
This PR (8657) - mean (823ms) : 781, 866
master - mean (824ms) : 790, 858
HttpMessageHandler (.NET Framework 4.8)gantt
title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (201ms) : 194, 207
master - mean (199ms) : 194, 204
section Bailout
This PR (8657) - mean (204ms) : 201, 208
master - mean (203ms) : 200, 207
section CallTarget+Inlining+NGEN
This PR (8657) - mean (1,200ms) : 1151, 1249
master - mean (1,190ms) : 1150, 1230
HttpMessageHandler (.NET Core 3.1)gantt
title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (288ms) : 280, 296
master - mean (285ms) : 278, 291
section Bailout
This PR (8657) - mean (289ms) : 282, 295
master - mean (283ms) : 277, 290
section CallTarget+Inlining+NGEN
This PR (8657) - mean (969ms) : 945, 992
master - mean (951ms) : 930, 971
HttpMessageHandler (.NET 6)gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (281ms) : 273, 289
master - mean (276ms) : 269, 283
section Bailout
This PR (8657) - mean (282ms) : 275, 288
master - mean (276ms) : 268, 285
section CallTarget+Inlining+NGEN
This PR (8657) - mean (1,158ms) : 1123, 1193
master - mean (1,154ms) : 1119, 1188
HttpMessageHandler (.NET 8)gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8657) - mean (280ms) : 273, 287
master - mean (275ms) : 267, 283
section Bailout
This PR (8657) - mean (281ms) : 276, 286
master - mean (275ms) : 268, 281
section CallTarget+Inlining+NGEN
This PR (8657) - mean (1,037ms) : 1003, 1071
master - mean (1,035ms) : 1000, 1071
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BenchmarksBenchmark execution time: 2026-05-19 09:49:45 Comparing candidate commit 0250c77 in PR branch Some scenarios are present only in baseline or only in candidate runs. If you didn't create or remove some scenarios in your branch, this maybe a sign of crashed benchmarks 💥💥💥 Scenarios present only in baseline:
Found 3 performance improvements and 4 performance regressions! Performance is the same for 48 metrics, 17 unstable metrics, 87 known flaky benchmarks, 39 flaky benchmarks without significant changes.
|
Summary of changes
Fixes a race condition in IpcTests that is causing a lot of flake
Reason for change
There's a race condition between the client and server loops. Both callbacks call
Interlocked.Exchange(ref finalValue, value)after sending the message. During the final exchange, the server's callback for(19, 19)would send(20, 19)to the client, then the client could process it, send(20, 20)back, writefinalValue=(20, 20), and setclientTaskCompletion. That all happens before the server callback writesfinalValue, so the server overwrites with(20, 19).The table below (from 🤖) summarizes it:
(19, 19)→ increments → value =(20, 19)(20, 19)to client (mutex released)(20, 19)→ increments → value =(20, 20)(20, 20)to serverInterlocked.Exchange(finalValue, (20, 20))(20, 20)clientTaskCompletion(20, 20)Interlocked.Exchange(finalValue, (20, 19))← stale!(20, 19)serverTaskCompletion(20, 19)Implementation details
Track
finalServerValueandfinalClientValueindependently so that each callback writes its own value. As there's now only one writer, the race has gone.Test coverage
This is the test
Other details
The bug is only in the test, not in the production code