func run()

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
    }
  }