Skip to content

Commit 10ab608

Browse files
committed
[UnitTests][Threading] Tweak ConditionVariable test for Windows.
Windows' behaviour wrt `Sleep` family functions can be odd. Apparently, if you specify a time lower than a system tick, they can return early. This makes the test flaky when it shouldn't be. To fix it, we use the Multimedia functions to adjust the system tick count as low as we can get it. rdar://100236038
1 parent fcf3bfa commit 10ab608

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

unittests/Threading/ConditionVariable.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,51 @@
1919
#include "ThreadingHelpers.h"
2020
#include "LockingHelpers.h"
2121

22+
#ifdef _WIN32
23+
#include <windows.h>
24+
#endif
25+
2226
using namespace swift;
2327

2428
template <typename Body>
2529
std::chrono::duration<double> measureDuration(Body body) {
30+
#ifdef _WIN32
31+
using namespace std::chrono_literals;
32+
33+
/* On Windows, we use SleepConditionVariableSRW() to implement
34+
ConditionVariable. The way Windows implements the SleepXXX() functions,
35+
if you specify a timeout smaller than the current system tick rate,
36+
the function may return early. See
37+
38+
https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep
39+
40+
This causes flakiness in this test, which is undesirable.
41+
42+
To combat this, we adjust the system tick rate temporarily here.
43+
44+
Even *after* doing that, measurement suggests that Windows can return
45+
early by an amount not exceeding a system tick. */
46+
TIMECAPS tc;
47+
UINT uTimerRes;
48+
49+
ASSERT_NE(timeGetDevCaps(&tc, sizeof(TIMECAPS)), TIMERR_NOERROR);
50+
51+
uTimerRes = min(max(tc.wPeriodMin, 1/*ms*/), tc.wPeriodMax);
52+
timeBeginPeriod(uTimerRes);
53+
#endif
54+
2655
auto start = std::chrono::steady_clock::now();
2756
body();
28-
return std::chrono::steady_clock::now() - start;
57+
std::chrono::duration<double> elapsed = std::chrono::steady_clock::now() - start;
58+
59+
#ifdef _WIN32
60+
timeEndPeriod(uTimerRes);
61+
62+
// Lie about the elapsed time to make the test more robust
63+
elapsed += 0.001s;
64+
#endif
65+
66+
return elapsed;
2967
}
3068

3169
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)