in SourceKitStressTester/Sources/SwiftCWrapper/SwiftCWrapper.swift [84:199]
func run() throws -> Int32 {
// Execute the compiler
let swiftcResult = ProcessRunner(launchPath: swiftcPath, arguments: arguments)
.run(captureStdout: false, captureStderr: false)
guard swiftcResult.status == EXIT_SUCCESS else { return swiftcResult.status }
let startTime = Date()
// Determine the list of stress testing operations to perform
let operations = swiftFiles.flatMap { (file, sizeInBytes) -> [StressTestOperation] in
if let fileFilter = ProcessInfo.processInfo.environment["SK_STRESS_FILE_FILTER"] {
if !fileFilter.split(separator: ",").contains(where: { file.contains($0) }) {
return []
}
}
// Split large files into multiple parts to improve load balancing
let partCount = max(Int(sizeInBytes / 1000), 1)
return rewriteModes.flatMap { mode in
(1...partCount).map { part in
StressTestOperation(file: file, rewriteMode: mode,
requests: requestKinds,
conformingMethodTypes: conformingMethodTypes,
limit: astBuildLimit,
part: (part, of: partCount),
reportResponses: dumpResponsesPath != nil,
compilerArgs: arguments,
executable: stressTesterPath,
swiftc: swiftcPath,
extraCodeCompleteOptions: extraCodeCompleteOptions,
requestDurationsOutputFile: requestDurationsOutputFile)
}
}
}
guard !operations.isEmpty else { return swiftcResult.status }
// Run the operations, reporting progress
let progress: ProgressAnimationProtocol?
if !suppressOutput {
progress = PercentProgressAnimation(stream: stderrStream, header: "Stress testing SourceKit...")
progress?.update(step: 0, total: operations.count, text: "Scheduling \(operations.count) operations")
} else {
progress = nil
}
// Write out response data once it's received and all preceding operations are complete
var orderingHandler: OrderingBuffer<[SourceKitResponseData]>? = nil
var seenResponses = Set<UInt64>()
if let dumpResponsesPath = dumpResponsesPath {
orderingHandler = OrderingBuffer(itemCount: operations.count) { responses in
self.writeResponseData(responses, to: dumpResponsesPath, seenResponses: &seenResponses)
}
}
let queue = StressTesterOperationQueue(operations: operations, maxWorkers: maxJobs) { index, operation, completed, total -> Bool in
let message = "\(operation.file) (\(operation.summary)): \(operation.status.name)"
progress?.update(step: completed, total: total, text: message)
orderingHandler?.complete(operation.responses, at: index, setLast: !operation.status.isPassed)
operation.responses.removeAll()
// We can control whether to stop scheduling new operations here. As long
// as we return `true`, the stress tester continues to schedule new
// test operations. To stop at the first failure, return
// `operation.status.isPassed`.
return true
}
queue.waitUntilFinished()
if !suppressOutput {
progress?.complete(success: operations.allSatisfy {$0.status.isPassed})
stderrStream <<< "\n"
stderrStream.flush()
// Report the overall runtime
let elapsedSeconds = -startTime.timeIntervalSinceNow
stderrStream <<< "Runtime: \(elapsedSeconds.formatted() ?? String(elapsedSeconds))\n\n"
stderrStream.flush()
}
// Determine the set of processed files and the first failure (if any)
var processedFiles = Set<String>()
var detectedIssues: [StressTesterIssue] = []
for operation in operations {
switch operation.status {
case .cancelled:
fatalError("cancelled operation before failed operation")
case .unexecuted:
fatalError("unterminated operation")
case .errored(let status):
detectedIssues.append(.errored(status: status, file: operation.file,
arguments: escapeArgs(operation.args)))
case .failed(let sourceKitErrors):
for sourceKitError in sourceKitErrors {
detectedIssues.append(.failed(sourceKitError: sourceKitError,
arguments: escapeArgs(operation.args)))
}
fallthrough
case .passed:
processedFiles.insert(operation.file)
}
}
var hasUnexpectedIssue = false
for detectedIssue in detectedIssues {
let matchingSpec = try issueManager?.update(for: processedFiles, issue: detectedIssue)
if issueManager == nil || matchingSpec != nil {
hasUnexpectedIssue = true
}
try report(detectedIssue, matching: matchingSpec)
}
if hasUnexpectedIssue {
return ignoreIssues ? swiftcResult.status : EXIT_FAILURE
} else {
return EXIT_SUCCESS
}
}