Skip to content

Shuffle batch mode partitions if a seed is provided #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Driver/CompilerMode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public enum CompilerMode: Equatable {
/// Information about batch mode, which is used to determine how to form
/// the batches of jobs.
public struct BatchModeInfo: Equatable {
let seed: Int
let seed: Int?
let count: Int?
let sizeLimit: Int?
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ extension Driver {

// For batch mode, collect information
if wantBatchMode {
let batchSeed = parseIntOption(&parsedOptions, option: .driverBatchSeed, diagnosticsEngine: diagnosticsEngine) ?? 0
let batchSeed = parseIntOption(&parsedOptions, option: .driverBatchSeed, diagnosticsEngine: diagnosticsEngine)
let batchCount = parseIntOption(&parsedOptions, option: .driverBatchCount, diagnosticsEngine: diagnosticsEngine)
let batchSizeLimit = parseIntOption(&parsedOptions, option: .driverBatchSizeLimit, diagnosticsEngine: diagnosticsEngine)
return .batchCompile(BatchModeInfo(seed: batchSeed, count: batchCount, sizeLimit: batchSizeLimit))
Expand Down
6 changes: 5 additions & 1 deletion Sources/SwiftDriver/Jobs/Planning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,11 @@ extension Driver {
partitionIndices.append(contentsOf: Array(repeating: partitionIdx, count: fillCount))
}
assert(partitionIndices.count == numInputFiles)
// FIXME: If info.seed is non-null, shuffle.

if let seed = info.seed {
var generator = PredictableRandomNumberGenerator(seed: UInt64(seed))
partitionIndices.shuffle(using: &generator)
}

// Form the actual partitions.
var assignment: [TypedVirtualPath : Int] = [:]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//===------------ PredictableRandomNumberGenerator.swift ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// An _insecure_ random number generator which given an initial seed will generate a _predictable_
/// sequence of pseudo-random numbers. This generator is not thread safe.
///
/// The generator uses the [xoshiro256**](http://prng.di.unimi.it/xoshiro256starstar.c)
/// algorithm to produce its output. It is initialized using the
/// [splitmix64](http://prng.di.unimi.it/splitmix64.c) algorithm.
public struct PredictableRandomNumberGenerator: RandomNumberGenerator {

var state: (UInt64, UInt64, UInt64, UInt64)

public init(seed: UInt64) {
func initNext(_ state: inout UInt64) -> UInt64 {
state = state &+ 0x9e3779b97f4a7c15
var z = state
z = (z ^ (z &>> 30)) &* 0xbf58476d1ce4e5b9
z = (z ^ (z &>> 27)) &* 0x94d049bb133111eb
return z ^ (z &>> 31)
}

var initState = seed
state = (initNext(&initState), initNext(&initState),
initNext(&initState), initNext(&initState))
}

mutating public func next() -> UInt64 {
defer {
let t = state.1 &<< 17
state.2 ^= state.0
state.3 ^= state.1;
state.1 ^= state.2;
state.0 ^= state.3;
state.2 ^= t;
state.3 = state.3.rotateLeft(45)
}
return (state.1 &* 5).rotateLeft(7) &* 9
}
}

fileprivate extension UInt64 {
func rotateLeft(_ numBits: UInt8) -> UInt64 {
return (self &<< numBits) | (self &>> (64 - numBits))
}
}
49 changes: 49 additions & 0 deletions Tests/SwiftDriverTests/PredictableRandomNumberGeneratorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===--------------- PredictableRandomNumberGeneratorTests.swift ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import XCTest
import SwiftDriver

/// This generator is deterministic and platform independent, so the sequence for each seed should remain constant.
final class PredictableRandomNumberGeneratorTests: XCTestCase {
func testPredictability() {
var generator = PredictableRandomNumberGenerator(seed: 42)
XCTAssertEqual([generator.next(), generator.next(), generator.next(),
generator.next(), generator.next()],
[1546998764402558742, 6990951692964543102,
12544586762248559009, 17057574109182124193,
18295552978065317476])

var generator2 = PredictableRandomNumberGenerator(seed: 42)
XCTAssertEqual([generator2.next(), generator2.next(), generator2.next(),
generator2.next(), generator2.next()],
[1546998764402558742, 6990951692964543102,
12544586762248559009, 17057574109182124193,
18295552978065317476])
}

func testUnusualSeeds() {
var generator = PredictableRandomNumberGenerator(seed: 0)
XCTAssertEqual([generator.next(), generator.next(), generator.next(),
generator.next(), generator.next()],
[11091344671253066420, 13793997310169335082,
1900383378846508768, 7684712102626143532,
13521403990117723737])

var generator2 = PredictableRandomNumberGenerator(seed: 0xFFFFFFFFFFFFFFFF)
XCTAssertEqual([generator2.next(), generator2.next(), generator2.next(),
generator2.next(), generator2.next()],
[10328197420357168392, 14156678507024973869,
9357971779955476126, 13791585006304312367,
10463432026814718762])
}
}