mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[test] Add a timeout to runRaceTest(). Use it to limit test AtomicInt.swift. This cuts AtomicInt.swift's execution time from several hours to about ten minutes on slow hardware and slow build configurations.
184 lines
4.9 KiB
Swift
184 lines
4.9 KiB
Swift
// RUN: %target-build-swift -Xfrontend -disable-access-control -module-name a %s -o %t.out
|
|
// RUN: %target-run %t.out | %FileCheck %s
|
|
|
|
import StdlibUnittest
|
|
#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
|
|
import Darwin
|
|
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android)
|
|
import Glibc
|
|
#endif
|
|
|
|
|
|
_setTestSuiteFailedCallback() { print("abort()") }
|
|
|
|
struct RaceTest1 : RaceTestWithPerTrialData {
|
|
static var shouldPass: Bool = true
|
|
static var iterationCountdown: _stdlib_AtomicInt = _stdlib_AtomicInt(8)
|
|
|
|
class RaceData {
|
|
init() {}
|
|
}
|
|
|
|
typealias ThreadLocalData = Void
|
|
typealias Observation = Observation1UInt
|
|
|
|
func makeRaceData() -> RaceData {
|
|
return RaceData()
|
|
}
|
|
|
|
func makeThreadLocalData() -> Void {
|
|
return Void()
|
|
}
|
|
|
|
func thread1(
|
|
_ raceData: RaceData, _ threadLocalData: inout ThreadLocalData
|
|
) -> Observation {
|
|
switch RaceTest1.iterationCountdown.fetchAndAdd(-1) {
|
|
case 0:
|
|
return Observation(0x1)
|
|
|
|
case 1:
|
|
return Observation(RaceTest1.shouldPass ? 0x1 : 0xffff)
|
|
|
|
case 1, 2:
|
|
return Observation(0x2)
|
|
|
|
case 3, 4, 5:
|
|
return Observation(RaceTest1.shouldPass ? 0x2 : 0xfffe)
|
|
|
|
default:
|
|
return Observation(0x1)
|
|
}
|
|
}
|
|
|
|
func evaluateObservations(
|
|
_ observations: [Observation],
|
|
_ sink: (RaceTestObservationEvaluation) -> Void
|
|
) {
|
|
for observation in observations {
|
|
switch observation {
|
|
case Observation(0x1):
|
|
sink(.pass)
|
|
case Observation(0x2):
|
|
sink(.passInteresting(String(describing: observation)))
|
|
case Observation(0xffff):
|
|
sink(.failure)
|
|
case Observation(0xfffe):
|
|
sink(.failureInteresting(String(describing: observation)))
|
|
default:
|
|
fatalError("should not happen")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var RaceTestSuite = TestSuite("Race")
|
|
|
|
RaceTestSuite.test("passes") {
|
|
RaceTest1.shouldPass = true
|
|
RaceTest1.iterationCountdown = _stdlib_AtomicInt(8)
|
|
runRaceTest(RaceTest1.self, trials: 10)
|
|
}
|
|
// CHECK: [ RUN ] Race.passes
|
|
// CHECK: stdout>>> Pass: {{.*}} times
|
|
// CHECK: stdout>>> Pass (2): 4 times
|
|
// CHECK: stdout>>> Failure: 0 times
|
|
// CHECK: [ OK ] Race.passes
|
|
|
|
RaceTestSuite.test("fails") {
|
|
RaceTest1.shouldPass = false
|
|
RaceTest1.iterationCountdown = _stdlib_AtomicInt(8)
|
|
runRaceTest(RaceTest1.self, trials: 10)
|
|
}
|
|
// CHECK: [ RUN ] Race.fails
|
|
// REQUIRES: executable_test
|
|
// CHECK: stdout>>> Pass: {{.*}} times
|
|
// CHECK: stdout>>> Pass (2): 1 times
|
|
// CHECK: stdout>>> Failure: 1 times
|
|
// CHECK: stdout>>> Failure (65534): 3 times
|
|
// CHECK: [ FAIL ] Race.fails
|
|
|
|
RaceTestSuite.test("closure") {
|
|
let count = _stdlib_AtomicInt(0)
|
|
runRaceTest(trials: 10) {
|
|
_ = count.fetchAndAdd(1)
|
|
}
|
|
expectNotEqual(0, count.load())
|
|
}
|
|
// CHECK: [ RUN ] Race.closure
|
|
// CHECK: [ OK ] Race.closure
|
|
|
|
RaceTestSuite.test("timeout-zero") {
|
|
// Zero timeout is still expected to run at least one trial.
|
|
let count = _stdlib_AtomicInt(0)
|
|
runRaceTest(trials: 2000000000, timeoutInSeconds: 0) {
|
|
_ = count.fetchAndAdd(1)
|
|
}
|
|
expectGT(count.load(), 0)
|
|
}
|
|
// CHECK: [ RUN ] Race.timeout-zero
|
|
// CHECK: [ OK ] Race.timeout-zero
|
|
|
|
|
|
func -(_ lhs: timeval, _ rhs: timeval) -> timeval {
|
|
var result = timeval(tv_sec: 0, tv_usec: 0)
|
|
result.tv_sec = lhs.tv_sec - rhs.tv_sec
|
|
result.tv_usec = lhs.tv_usec - rhs.tv_usec
|
|
if result.tv_usec < 0 {
|
|
result.tv_usec += 1000000
|
|
result.tv_sec -= 1
|
|
}
|
|
return result
|
|
}
|
|
|
|
func gettimeofday() -> timeval {
|
|
var result = timeval(tv_sec: 0, tv_usec: 0)
|
|
gettimeofday(&result, nil)
|
|
return result
|
|
}
|
|
|
|
RaceTestSuite.test("timeout-small") {
|
|
// Verify that the timeout fires after the correct number of seconds.
|
|
// If the timeout fails to fire then this test will run for a very long time.
|
|
var startTime: timeval
|
|
var endTime: timeval
|
|
let timeout = 5
|
|
let count = _stdlib_AtomicInt(0)
|
|
startTime = gettimeofday()
|
|
runRaceTest(trials: 2000000000, timeoutInSeconds: timeout) {
|
|
_ = count.fetchAndAdd(1)
|
|
}
|
|
endTime = gettimeofday()
|
|
expectGT(count.load(), 0)
|
|
// Test should have run to the timeout.
|
|
// Test should not have run too long after the timeout.
|
|
let duration = endTime - startTime
|
|
expectGE(duration.tv_sec, timeout)
|
|
expectLT(duration.tv_sec, timeout*100) // large to avoid spurious failures
|
|
}
|
|
// CHECK: [ RUN ] Race.timeout-small
|
|
// CHECK: [ OK ] Race.timeout-small
|
|
|
|
RaceTestSuite.test("timeout-big") {
|
|
// Verify that a short test with a long timeout completes before the timeout.
|
|
var startTime: timeval
|
|
var endTime: timeval
|
|
let timeout = 10000
|
|
let count = _stdlib_AtomicInt(0)
|
|
startTime = gettimeofday()
|
|
runRaceTest(trials: 10, timeoutInSeconds: timeout) {
|
|
_ = count.fetchAndAdd(1)
|
|
}
|
|
endTime = gettimeofday()
|
|
expectGT(count.load(), 0)
|
|
// Test should have stopped long before the timeout.
|
|
let duration = endTime - startTime
|
|
expectLT(duration.tv_sec, timeout / 2)
|
|
}
|
|
// CHECK: [ RUN ] Race.timeout-big
|
|
// CHECK: [ OK ] Race.timeout-big
|
|
|
|
runAllTests()
|
|
// CHECK: Race: Some tests failed, aborting
|
|
|