Skip to content

Commit fe639b5

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 fe639b5

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

unittests/Threading/ConditionVariable.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,49 @@
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+
/* On Windows, we use SleepConditionVariableSRW() to implement
32+
ConditionVariable. The way Windows implements the SleepXXX() functions,
33+
if you specify a timeout smaller than the current system tick rate,
34+
the function may return early. See
35+
36+
https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep
37+
38+
This causes flakiness in this test, which is undesirable.
39+
40+
To combat this, we adjust the system tick rate temporarily here.
41+
42+
Even *after* doing that, measurement suggests that Windows can return
43+
early by an amount not exceeding a system tick. */
44+
TIMECAPS tc;
45+
UINT uTimerRes;
46+
47+
ASSERT_NE(timeGetDevCaps(&tc, sizeof(TIMECAPS)), TIMERR_NOERROR);
48+
49+
uTimerRes = min(max(tc.wPeriodMin, 1/*ms*/), tc.wPeriodMax);
50+
timeBeginPeriod(uTimerRes);
51+
#endif
52+
2653
auto start = std::chrono::steady_clock::now();
2754
body();
28-
return std::chrono::steady_clock::now() - start;
55+
std::chrono::duration<double> elapsed = std::chrono::steady_clock::now() - start;
56+
57+
#ifdef _WIN32
58+
timeEndPeriod(uTimerRes);
59+
60+
// Lie about the elapsed time to make the test more robust
61+
elapsed += 0.001s;
62+
#endif
63+
64+
return elapsed;
2965
}
3066

3167
// -----------------------------------------------------------------------------

0 commit comments

Comments
 (0)