Skip to content
Open
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
1 change: 1 addition & 0 deletions Sources/SwiftDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ add_library(SwiftDriver
Utilities/Sanitizer.swift
Utilities/StringAdditions.swift
Utilities/System.swift
Utilities/TimeTrace.swift
Utilities/Triple+Platforms.swift
Utilities/Triple.swift
Utilities/TypedVirtualPath.swift
Expand Down
51 changes: 47 additions & 4 deletions Sources/SwiftDriver/Driver/Driver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,12 @@ public struct Driver {
/// Path to the loaded module trace file.
let loadedModuleTracePath: VirtualPath.Handle?

/// Path to the time trace profiling output file.
let timeTraceOutputPath: VirtualPath.Handle?

/// Time trace profiler, active when `-time-trace` is passed.
var timeTrace = TimeTrace()

/// Path to the TBD file (text-based dylib).
let tbdPath: VirtualPath.Handle?

Expand Down Expand Up @@ -1335,6 +1341,15 @@ public struct Driver {
moduleName: moduleOutputInfo.name)
}

self.timeTraceOutputPath = try Self.computeSupplementaryOutputPath(
&parsedOptions, type: .timeTrace, isOutputOptions: [.timeTrace],
outputPath: .timeTracePath,
compilerOutputType: compilerOutputType,
compilerMode: compilerMode,
emitModuleSeparately: emitModuleSeparately,
outputFileMap: self.outputFileMap,
moduleName: moduleOutputInfo.name)

self.tbdPath = try Self.computeSupplementaryOutputPath(
&parsedOptions, type: .tbd, isOutputOptions: [.emitTbd],
outputPath: .emitTbdPath,
Expand Down Expand Up @@ -1429,11 +1444,16 @@ public struct Driver {
swiftInterfacePath: self.moduleOutputPaths.swiftInterfacePath,
diagnosticEngine: diagnosticsEngine)

self.timeTrace = TimeTrace(enabled: parsedOptions.hasArgument(.timeTrace))

try verifyOutputOptions()
}

public mutating func planBuild() throws -> [Job] {
let (jobs, incrementalCompilationState, explicitModulePlanner) = try planPossiblyIncrementalBuild()
let (jobs, incrementalCompilationState, explicitModulePlanner) =
try timeTrace.measure("Plan Build") {
try planPossiblyIncrementalBuild()
}
self.incrementalCompilationState = incrementalCompilationState
self.intermoduleDependencyGraph = explicitModulePlanner?.dependencyGraph
return jobs
Expand Down Expand Up @@ -1964,12 +1984,16 @@ extension Driver {
defer {
writeIncrementalBuildInformation(jobs)
}
try performTheBuild(allJobs: childJobs,
jobExecutionDelegate: toolExecutionDelegate,
forceResponseFiles: forceResponseFiles)
try timeTrace.measure("Execute Jobs") {
try performTheBuild(allJobs: childJobs,
jobExecutionDelegate: toolExecutionDelegate,
forceResponseFiles: forceResponseFiles)
}
}
}

try writeDriverTimeTrace()

// If we have a job to run in-place, do so at the end.
if let inPlaceJob = inPlaceJob {
// Print the driver source version first before we print the compiler
Expand Down Expand Up @@ -2001,6 +2025,25 @@ extension Driver {
}
}

/// Write the driver's time trace to a `.driver.time-trace.json` file alongside
/// the frontend's time trace output. The file is automatically discovered by
/// SwiftPM's `importCompilerTimeTraces(under:)` because it ends in `.time-trace.json`.
public mutating func writeDriverTimeTrace() throws {
guard timeTrace.enabled,
let tracePathHandle = timeTraceOutputPath else { return }
let tracePath = VirtualPath.lookup(tracePathHandle)
// Frontend trace: foo.time-trace.json → Driver trace: foo.driver.time-trace.json
let pathString = tracePath.name
let driverPathString = pathString.replacingOccurrences(
of: ".time-trace.json", with: ".driver.time-trace.json")
guard driverPathString != pathString else { return }

let driverTracePath = try VirtualPath.intern(path: driverPathString)
let resolvedPath = VirtualPath.lookup(driverTracePath)
.resolvedRelativePath(base: workingDirectory ?? fileSystem.currentWorkingDirectory!)
try timeTrace.write(to: resolvedPath.name)
}

mutating func createToolExecutionDelegate() -> ToolExecutionDelegate {
var mode: ToolExecutionDelegate.Mode = .regular

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
/// status of the scanner prefix mapping option supported by the frontend
private let supportsScannerPrefixMapPaths: Bool

/// Whether to emit time trace profiling data for dependency module builds
private let enableTimeTrace: Bool

/// Time trace granularity in microseconds, if specified
private let timeTraceGranularity: UInt?

/// Cached command-line additions for all main module compile jobs
private struct ResolvedModuleDependenciesCommandLineComponents {
let inputs: [TypedVirtualPath]
Expand Down Expand Up @@ -94,7 +100,9 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
cas: SwiftScanCAS? = nil,
prefixMap: [(AbsolutePath, AbsolutePath)] = [],
supportsBridgingHeaderPCHCommand: Bool = false,
supportsScannerPrefixMapPaths: Bool = false) throws {
supportsScannerPrefixMapPaths: Bool = false,
enableTimeTrace: Bool = false,
timeTraceGranularity: UInt? = nil) throws {
self.dependencyGraph = dependencyGraph
self.toolchain = toolchain
self.integratedDriver = integratedDriver
Expand All @@ -103,6 +111,8 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
self.supportsExplicitInterfaceBuild = supportsExplicitInterfaceBuild
self.supportsBridgingHeaderPCHCommand = supportsBridgingHeaderPCHCommand
self.supportsScannerPrefixMapPaths = supportsScannerPrefixMapPaths
self.enableTimeTrace = enableTimeTrace
self.timeTraceGranularity = timeTraceGranularity
self.cas = cas
self.prefixMap = prefixMap
let mainModuleId: ModuleDependencyId = .swift(dependencyGraph.mainModuleName)
Expand Down Expand Up @@ -236,6 +246,20 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
}
}

// Add time trace flags so dependency module builds produce profiling data.
if enableTimeTrace {
let traceFileName = outputModulePath.file.basenameWithoutExt
.appendingFileTypeExtension(.timeTrace)
let tracePath = outputModulePath.file.parentDirectory
.appending(component: traceFileName)
commandLine.appendFlag("-emit-time-trace-path")
commandLine.appendPath(tracePath)
if let granularity = timeTraceGranularity {
commandLine.appendFlag("-time-trace-granularity")
commandLine.appendFlag(String(granularity))
}
}

jobs.append(Job(
moduleName: moduleId.moduleName,
kind: .compileModuleFromInterface,
Expand Down Expand Up @@ -302,6 +326,20 @@ public typealias ExternalTargetModuleDetailsMap = [ModuleDependencyId: ExternalT
}
}

// Add time trace flags so dependency module builds produce profiling data.
if enableTimeTrace {
let traceFileName = modulePCMPath.file.basenameWithoutExt
.appendingFileTypeExtension(.timeTrace)
let tracePath = modulePCMPath.file.parentDirectory
.appending(component: traceFileName)
commandLine.appendFlag("-emit-time-trace-path")
commandLine.appendPath(tracePath)
if let granularity = timeTraceGranularity {
commandLine.appendFlag("-time-trace-granularity")
commandLine.appendFlag(String(granularity))
}
}

jobs.append(Job(
moduleName: moduleId.moduleName,
kind: .generatePCM,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ extension Diagnostic.Message {
/// module dependencies.
mutating func scanModuleDependencies(forVariantModule: Bool = false)
throws -> InterModuleDependencyGraph {
let dependencyGraph = try performDependencyScan(forVariantModule: forVariantModule)
let dependencyGraph =
try timeTrace.measure("Dependency Scanning") {
try performDependencyScan(forVariantModule: forVariantModule)
}

if parsedOptions.hasArgument(.printPreprocessedExplicitDependencyGraph) {
try stdoutStream.send(dependencyGraph.toJSONString())
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftDriver/Jobs/CompileJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ extension Driver {
case .swift, .image, .dSYM, .dependencies, .emitModuleDependencies, .autolink,
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile,
.diagnostics, .emitModuleDiagnostics, .objcHeader, .swiftDeps, .remap, .tbd,
.moduleTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch,
.moduleTrace, .timeTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch,
.clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts,
.indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, .jsonABIBaseline,
.swiftConstValues, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .dependencyScanDiagnostics,
Expand Down Expand Up @@ -549,7 +549,7 @@ extension FileType {

case .swift, .dSYM, .autolink, .dependencies, .emitModuleDependencies,
.swiftDocumentation, .pcm, .diagnostics, .emitModuleDiagnostics,
.objcHeader, .image, .swiftDeps, .moduleTrace, .tbd, .yamlOptimizationRecord,
.objcHeader, .image, .swiftDeps, .moduleTrace, .timeTrace, .tbd, .yamlOptimizationRecord,
.bitstreamOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.swiftSourceInfoFile, .clangModuleMap, .jsonSwiftArtifacts,
.indexUnitOutputPath, .modDepCache, .jsonAPIBaseline, .jsonABIBaseline,
Expand Down
25 changes: 22 additions & 3 deletions Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ extension Driver {
try commandLine.appendLast(.traceStatsEvents, from: &parsedOptions)
try commandLine.appendLast(.profileStatsEvents, from: &parsedOptions)
try commandLine.appendLast(.profileStatsEntities, from: &parsedOptions)
try commandLine.appendLast(.timeTraceGranularity, from: &parsedOptions)
try commandLine.appendLast(.solverShrinkUnsolvedThreshold, from: &parsedOptions)
try commandLine.appendLast(in: .O, from: &parsedOptions)
try commandLine.appendLast(.RemoveRuntimeAsserts, from: &parsedOptions)
Expand Down Expand Up @@ -996,6 +997,12 @@ extension Driver {
flag: "-save-optimization-record-path")
}
}

try addOutputOfType(
outputType: .timeTrace,
finalOutputPath: timeTraceOutputPath,
input: input,
flag: "-emit-time-trace-path")
}

let optRecordTypeWarning = self.optimizationRecordFileType ?? .yamlOptimizationRecord
Expand Down Expand Up @@ -1094,9 +1101,15 @@ extension Driver {
output: TypedVirtualPath(file: tracePath, type: .moduleTrace)))
}

// Separate time trace pairs from supplementary output pairs.
// Time trace is not a supplementary output — it must not go into the
// supplementary output file map (which feeds the CAS caching layer).
let timeTracePairs = flaggedInputOutputPairs.filter { $0.flag == "-emit-time-trace-path" }
let supplementaryPairs = flaggedInputOutputPairs.filter { $0.flag != "-emit-time-trace-path" }

// When we have multiple opt records in flaggedInputOutputPairs, we must use a supplementary
// output file map to pass all the per-file paths to the frontend.
let hasMultipleOptRecords = flaggedInputOutputPairs
let hasMultipleOptRecords = supplementaryPairs
.filter { $0.flag == "-save-optimization-record-path" }.count > 1

if inputsGeneratingCodeCount * FileType.allCases.count > fileListThreshold || hasMultipleOptRecords {
Expand All @@ -1121,7 +1134,7 @@ extension Driver {
entries[firstSourceInputHandle] = [:]
}

for flaggedPair in flaggedInputOutputPairs {
for flaggedPair in supplementaryPairs {
try addEntry(&entries, input: flaggedPair.input, output: flaggedPair.output)
}
// To match the legacy driver behavior, make sure we add an entry for the
Expand All @@ -1138,13 +1151,19 @@ extension Driver {
commandLine.appendFlag(.supplementaryOutputFileMap)
commandLine.appendPath(fileList)
} else {
for flaggedPair in flaggedInputOutputPairs {
for flaggedPair in supplementaryPairs {
// Add the appropriate flag.
commandLine.appendFlag(flaggedPair.flag)
commandLine.appendPath(flaggedPair.output.file)
}
}

// Emit time trace paths as direct flags (not in supplementary output file map).
for flaggedPair in timeTracePairs {
commandLine.appendFlag(flaggedPair.flag)
commandLine.appendPath(flaggedPair.output.file)
}

return flaggedInputOutputPairs.map { $0.output }
}

Expand Down
24 changes: 19 additions & 5 deletions Sources/SwiftDriver/Jobs/Planning.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,22 @@ extension Driver {
// the planning process. This state contains the module dependency graph and
// cross-module dependency information.
let initialIncrementalState =
try IncrementalCompilationState.computeIncrementalStateForPlanning(driver: &self)
try timeTrace.measure("Incremental State") {
try IncrementalCompilationState.computeIncrementalStateForPlanning(driver: &self)
}

// For an explicit build, compute the inter-module dependency graph
let explicitModulePlanner = try configureExplicitModulePlanner()
let explicitModulePlanner =
try timeTrace.measure("Configure Explicit Module Planner") {
try configureExplicitModulePlanner()
}

// Compute the set of all jobs required to build this module
let jobsInPhases = try computeJobsForPhasedStandardBuild(explicitModulePlanner: explicitModulePlanner,
initialIncrementalState: initialIncrementalState)
let jobsInPhases =
try timeTrace.measure("Compute Jobs") {
try computeJobsForPhasedStandardBuild(explicitModulePlanner: explicitModulePlanner,
initialIncrementalState: initialIncrementalState)
}

// Determine the state for incremental compilation
let incrementalCompilationState: IncrementalCompilationState?
Expand Down Expand Up @@ -127,7 +135,13 @@ extension Driver {
supportsBridgingHeaderPCHCommand:
interModuleDependencyOracle.supportsBridgingHeaderPCHCommand,
supportsScannerPrefixMapPaths:
isFrontendArgSupported(.scannerPrefixMapPaths))
isFrontendArgSupported(.scannerPrefixMapPaths),
enableTimeTrace:
parsedOptions.hasArgument(.timeTrace),
timeTraceGranularity:
parsedOptions.hasArgument(.timeTraceGranularity)
? UInt(parsedOptions.getLastArgument(.timeTraceGranularity)!.asSingle)
: nil)
} else {
return nil
}
Expand Down
18 changes: 13 additions & 5 deletions Sources/SwiftDriver/Utilities/FileType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ public enum FileType: String, Hashable, CaseIterable, Codable {
/// Swift section of the internal wiki.
case moduleTrace = "trace.json"

/// Time trace profiling output
case timeTrace = "time-trace.json"

/// Indexing data directory
///
/// The extension isn't real, rather this FileType specifies a directory path.
Expand Down Expand Up @@ -241,6 +244,9 @@ extension FileType: CustomStringConvertible {
case .moduleTrace:
return "module-trace"

case .timeTrace:
return "time-trace"

case .indexData:
return "index-data"

Expand Down Expand Up @@ -306,7 +312,7 @@ extension FileType {
.jsonSwiftArtifacts, .indexUnitOutputPath, .modDepCache, .jsonAPIBaseline,
.jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor,
.moduleSummary, .moduleSemanticInfo, .cachedDiagnostics, .raw_llvmIr,
.jsonSupportedFeatures:
.jsonSupportedFeatures, .timeTrace:
return false
}
}
Expand Down Expand Up @@ -420,6 +426,8 @@ extension FileType {
return "imported-modules"
case .moduleTrace:
return "module-trace"
case .timeTrace:
return "time-trace"
case .indexData:
return "index-data"
case .yamlOptimizationRecord:
Expand Down Expand Up @@ -459,7 +467,7 @@ extension FileType {
switch self {
case .swift, .sil, .dependencies, .emitModuleDependencies, .assembly, .ast,
.raw_sil, .llvmIR,.objcHeader, .autolink, .importedModules, .tbd,
.moduleTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.moduleTrace, .timeTrace, .yamlOptimizationRecord, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.jsonDependencies, .clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo,
.jsonSwiftArtifacts, .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues,
.jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics,
Expand All @@ -483,7 +491,7 @@ extension FileType {
.autolink, .swiftModule, .swiftDocumentation, .swiftInterface,
.privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile, .raw_sil, .raw_sib,
.diagnostics, .emitModuleDiagnostics, .objcHeader, .swiftDeps, .remap,
.importedModules, .tbd, .moduleTrace, .indexData, .yamlOptimizationRecord,
.importedModules, .tbd, .moduleTrace, .timeTrace, .indexData, .yamlOptimizationRecord,
.modDepCache, .bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies,
.clangModuleMap, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSwiftArtifacts,
.indexUnitOutputPath, .jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues,
Expand All @@ -498,7 +506,7 @@ extension FileType {
switch self {
case .swift, .ast, .indexData, .indexUnitOutputPath, .jsonCompilerFeatures, .jsonTargetInfo, .jsonSupportedFeatures:
return false
case .sil, .sib, .image, .object, .dSYM, .dependencies, .autolink, .swiftModule, .swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile, .swiftConstValues, .assembly, .raw_sil, .raw_sib, .llvmIR, .llvmBitcode, .diagnostics, .emitModuleDiagnostics, .emitModuleDependencies, .objcHeader, .swiftDeps, .modDepCache, .remap, .importedModules, .tbd, .jsonDependencies, .jsonSwiftArtifacts, .moduleTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch, .clangModuleMap, .jsonAPIBaseline, .jsonABIBaseline, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics, .raw_llvmIr, .dependencyScanDiagnostics:
case .sil, .sib, .image, .object, .dSYM, .dependencies, .autolink, .swiftModule, .swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface, .swiftSourceInfoFile, .swiftConstValues, .assembly, .raw_sil, .raw_sib, .llvmIR, .llvmBitcode, .diagnostics, .emitModuleDiagnostics, .emitModuleDependencies, .objcHeader, .swiftDeps, .modDepCache, .remap, .importedModules, .tbd, .jsonDependencies, .jsonSwiftArtifacts, .moduleTrace, .timeTrace, .yamlOptimizationRecord, .bitstreamOptimizationRecord, .pcm, .pch, .clangModuleMap, .jsonAPIBaseline, .jsonABIBaseline, .jsonAPIDescriptor, .moduleSummary, .moduleSemanticInfo, .cachedDiagnostics, .raw_llvmIr, .dependencyScanDiagnostics:
return true
}
}
Expand All @@ -517,7 +525,7 @@ extension FileType {
.dependencies, .emitModuleDependencies, .swiftModule, .dependencyScanDiagnostics,
.swiftDocumentation, .swiftInterface, .privateSwiftInterface, .packageSwiftInterface,
.swiftSourceInfoFile, .raw_sil, .raw_sib, .objcHeader, .swiftDeps, .tbd,
.moduleTrace, .indexData, .yamlOptimizationRecord,
.moduleTrace, .timeTrace, .indexData, .yamlOptimizationRecord,
.bitstreamOptimizationRecord, .pcm, .pch, .jsonDependencies,
.jsonAPIBaseline, .jsonABIBaseline, .swiftConstValues, .jsonAPIDescriptor,
.moduleSummary, .moduleSemanticInfo, .cachedDiagnostics, .raw_llvmIr:
Expand Down
Loading
Loading