Skip to content

Commit 22835b0

Browse files
authored
Merge pull request #37 from owenv/shuffling
Shuffle batch mode partitions if a seed is provided
2 parents c22f935 + c2559bd commit 22835b0

File tree

5 files changed

+111
-3
lines changed

5 files changed

+111
-3
lines changed

Sources/SwiftDriver/Driver/CompilerMode.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public enum CompilerMode: Equatable {
3131
/// Information about batch mode, which is used to determine how to form
3232
/// the batches of jobs.
3333
public struct BatchModeInfo: Equatable {
34-
let seed: Int
34+
let seed: Int?
3535
let count: Int?
3636
let sizeLimit: Int?
3737
}

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ extension Driver {
689689

690690
// For batch mode, collect information
691691
if wantBatchMode {
692-
let batchSeed = parseIntOption(&parsedOptions, option: .driverBatchSeed, diagnosticsEngine: diagnosticsEngine) ?? 0
692+
let batchSeed = parseIntOption(&parsedOptions, option: .driverBatchSeed, diagnosticsEngine: diagnosticsEngine)
693693
let batchCount = parseIntOption(&parsedOptions, option: .driverBatchCount, diagnosticsEngine: diagnosticsEngine)
694694
let batchSizeLimit = parseIntOption(&parsedOptions, option: .driverBatchSizeLimit, diagnosticsEngine: diagnosticsEngine)
695695
return .batchCompile(BatchModeInfo(seed: batchSeed, count: batchCount, sizeLimit: batchSizeLimit))

Sources/SwiftDriver/Jobs/Planning.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,11 @@ extension Driver {
304304
partitionIndices.append(contentsOf: Array(repeating: partitionIdx, count: fillCount))
305305
}
306306
assert(partitionIndices.count == numInputFiles)
307-
// FIXME: If info.seed is non-null, shuffle.
307+
308+
if let seed = info.seed {
309+
var generator = PredictableRandomNumberGenerator(seed: UInt64(seed))
310+
partitionIndices.shuffle(using: &generator)
311+
}
308312

309313
// Form the actual partitions.
310314
var assignment: [TypedVirtualPath : Int] = [:]
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===------------ PredictableRandomNumberGenerator.swift ------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// An _insecure_ random number generator which given an initial seed will generate a _predictable_
14+
/// sequence of pseudo-random numbers. This generator is not thread safe.
15+
///
16+
/// The generator uses the [xoshiro256**](http://prng.di.unimi.it/xoshiro256starstar.c)
17+
/// algorithm to produce its output. It is initialized using the
18+
/// [splitmix64](http://prng.di.unimi.it/splitmix64.c) algorithm.
19+
public struct PredictableRandomNumberGenerator: RandomNumberGenerator {
20+
21+
var state: (UInt64, UInt64, UInt64, UInt64)
22+
23+
public init(seed: UInt64) {
24+
func initNext(_ state: inout UInt64) -> UInt64 {
25+
state = state &+ 0x9e3779b97f4a7c15
26+
var z = state
27+
z = (z ^ (z &>> 30)) &* 0xbf58476d1ce4e5b9
28+
z = (z ^ (z &>> 27)) &* 0x94d049bb133111eb
29+
return z ^ (z &>> 31)
30+
}
31+
32+
var initState = seed
33+
state = (initNext(&initState), initNext(&initState),
34+
initNext(&initState), initNext(&initState))
35+
}
36+
37+
mutating public func next() -> UInt64 {
38+
defer {
39+
let t = state.1 &<< 17
40+
state.2 ^= state.0
41+
state.3 ^= state.1;
42+
state.1 ^= state.2;
43+
state.0 ^= state.3;
44+
state.2 ^= t;
45+
state.3 = state.3.rotateLeft(45)
46+
}
47+
return (state.1 &* 5).rotateLeft(7) &* 9
48+
}
49+
}
50+
51+
fileprivate extension UInt64 {
52+
func rotateLeft(_ numBits: UInt8) -> UInt64 {
53+
return (self &<< numBits) | (self &>> (64 - numBits))
54+
}
55+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===--------------- PredictableRandomNumberGeneratorTests.swift ----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import XCTest
14+
import SwiftDriver
15+
16+
/// This generator is deterministic and platform independent, so the sequence for each seed should remain constant.
17+
final class PredictableRandomNumberGeneratorTests: XCTestCase {
18+
func testPredictability() {
19+
var generator = PredictableRandomNumberGenerator(seed: 42)
20+
XCTAssertEqual([generator.next(), generator.next(), generator.next(),
21+
generator.next(), generator.next()],
22+
[1546998764402558742, 6990951692964543102,
23+
12544586762248559009, 17057574109182124193,
24+
18295552978065317476])
25+
26+
var generator2 = PredictableRandomNumberGenerator(seed: 42)
27+
XCTAssertEqual([generator2.next(), generator2.next(), generator2.next(),
28+
generator2.next(), generator2.next()],
29+
[1546998764402558742, 6990951692964543102,
30+
12544586762248559009, 17057574109182124193,
31+
18295552978065317476])
32+
}
33+
34+
func testUnusualSeeds() {
35+
var generator = PredictableRandomNumberGenerator(seed: 0)
36+
XCTAssertEqual([generator.next(), generator.next(), generator.next(),
37+
generator.next(), generator.next()],
38+
[11091344671253066420, 13793997310169335082,
39+
1900383378846508768, 7684712102626143532,
40+
13521403990117723737])
41+
42+
var generator2 = PredictableRandomNumberGenerator(seed: 0xFFFFFFFFFFFFFFFF)
43+
XCTAssertEqual([generator2.next(), generator2.next(), generator2.next(),
44+
generator2.next(), generator2.next()],
45+
[10328197420357168392, 14156678507024973869,
46+
9357971779955476126, 13791585006304312367,
47+
10463432026814718762])
48+
}
49+
}

0 commit comments

Comments
 (0)