Skip to content

Commit 0fdb7ad

Browse files
Merge pull request #1853 from cachemeifyoucan/eng/PR-147874145
[Incremental] Track and return skipped non-compile job
2 parents 8b96d1b + e46ffab commit 0fdb7ad

File tree

6 files changed

+35
-11
lines changed

6 files changed

+35
-11
lines changed

Sources/SwiftDriver/IncrementalCompilation/FirstWaveComputer.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ extension IncrementalCompilationState {
5151

5252
public func compute(batchJobFormer: inout Driver) throws -> FirstWave {
5353
return try blockingConcurrentAccessOrMutation {
54-
let (initiallySkippedCompileJobs, mandatoryJobsInOrder, afterCompiles) =
54+
let (initiallySkippedCompileJobs, skippedNonCompileJobs, mandatoryJobsInOrder, afterCompiles) =
5555
try computeInputsAndGroups(batchJobFormer: &batchJobFormer)
5656
return FirstWave(
5757
initiallySkippedCompileJobs: initiallySkippedCompileJobs,
58+
skippedNonCompileJobs: skippedNonCompileJobs,
5859
mandatoryJobsInOrder: mandatoryJobsInOrder,
5960
jobsAfterCompiles: afterCompiles)
6061
}
@@ -75,6 +76,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
7576
/// listed in fingerprintExternalDependencies.
7677
private func computeInputsAndGroups(batchJobFormer: inout Driver)
7778
throws -> (initiallySkippedCompileJobs: [TypedVirtualPath: Job],
79+
skippedNonCompileJobs: [Job],
7880
mandatoryJobsInOrder: [Job],
7981
jobsAfterCompiles: [Job])
8082
{
@@ -86,6 +88,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
8688

8789
func everythingIsMandatory()
8890
throws -> (initiallySkippedCompileJobs: [TypedVirtualPath: Job],
91+
skippedNonCompileJobs: [Job],
8992
mandatoryJobsInOrder: [Job],
9093
jobsAfterCompiles: [Job])
9194
{
@@ -103,6 +106,7 @@ extension IncrementalCompilationState.FirstWaveComputer {
103106

104107
moduleDependencyGraph.setPhase(to: .buildingAfterEachCompilation)
105108
return (initiallySkippedCompileJobs: [:],
109+
skippedNonCompileJobs: [],
106110
mandatoryJobsInOrder: mandatoryJobsInOrder,
107111
jobsAfterCompiles: jobsInPhases.afterCompiles)
108112
}
@@ -133,14 +137,20 @@ extension IncrementalCompilationState.FirstWaveComputer {
133137
// we can skip running `beforeCompiles` jobs if we also ensure that none of the `afterCompiles` jobs
134138
// have any dependencies on them.
135139
let skipAllJobs = batchedCompilationJobs.isEmpty ? !nonVerifyAfterCompileJobsDependOnBeforeCompileJobs() : false
140+
let beforeCompileJobs = skipAllJobs ? [] : jobsInPhases.beforeCompiles
141+
var skippedNonCompileJobs = skipAllJobs ? jobsInPhases.beforeCompiles : []
136142

137143
// Schedule emitModule job together with verify module interface job.
138-
let beforeCompileJobs = skipAllJobs ? [] : jobsInPhases.beforeCompiles
139-
let afterCompileJobs = jobsInPhases.afterCompiles.compactMap { job in
140-
skipAllJobs && job.kind == .verifyModuleInterface ? nil : job
144+
let afterCompileJobs = jobsInPhases.afterCompiles.compactMap { job -> Job? in
145+
if skipAllJobs && job.kind == .verifyModuleInterface {
146+
skippedNonCompileJobs.append(job)
147+
return nil
148+
}
149+
return job
141150
}
142151
let mandatoryJobsInOrder = beforeCompileJobs + batchedCompilationJobs
143152
return (initiallySkippedCompileJobs: initiallySkippedCompileJobs,
153+
skippedNonCompileJobs: skippedNonCompileJobs,
144154
mandatoryJobsInOrder: mandatoryJobsInOrder,
145155
jobsAfterCompiles: afterCompileJobs)
146156
}

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState+Extensions.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ extension IncrementalCompilationState {
6565
/// incremental dependency graph and the status of the input files for this
6666
/// incremental build.
6767
let initiallySkippedCompileJobs: [TypedVirtualPath: Job]
68+
/// The non-compile jobs that can be skipped given the state of the
69+
/// incremental build.
70+
let skippedNonCompileJobs: [Job]
6871
/// All of the pre-compile or compilation job (groups) known to be required
6972
/// for the first wave to execute.
7073
/// The primaries could be other than .swift files, i.e. .sib
7174
let mandatoryJobsInOrder: [Job]
72-
75+
/// The job after compilation that needs to run.
7376
let jobsAfterCompiles: [Job]
7477
}
7578
}

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public final class IncrementalCompilationState {
4444
/// Jobs to run *after* the last compile, for instance, link-editing.
4545
public let jobsAfterCompiles: [Job]
4646

47+
/// The skipped non compile jobs.
48+
public let skippedJobsNonCompile: [Job]
49+
4750
public let info: IncrementalCompilationState.IncrementalDependencyAndInputSetup
4851

4952
internal let upToDateInterModuleDependencyGraph: InterModuleDependencyGraph?
@@ -78,6 +81,7 @@ public final class IncrementalCompilationState {
7881
&driver)
7982
self.mandatoryJobsInOrder = firstWave.mandatoryJobsInOrder
8083
self.jobsAfterCompiles = firstWave.jobsAfterCompiles
84+
self.skippedJobsNonCompile = firstWave.skippedNonCompileJobs
8185
}
8286

8387
/// Allow concurrent access to while preventing mutation of ``IncrementalCompilationState/protectedState``

Sources/SwiftDriver/Jobs/Planning.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ extension Driver {
9494
// If the jobs are batched during the incremental build, reuse the computation rather than computing the batches again.
9595
if let incrementalState = incrementalCompilationState {
9696
// For compatibility reasons, all the jobs planned will be returned, even the incremental state suggests the job is not mandatory.
97-
batchedJobs = incrementalState.skippedJobs + incrementalState.mandatoryJobsInOrder + incrementalState.jobsAfterCompiles
97+
batchedJobs = incrementalState.skippedJobs + incrementalState.skippedJobsNonCompile + incrementalState.mandatoryJobsInOrder + incrementalState.jobsAfterCompiles
9898
} else {
9999
batchedJobs = try formBatchedJobs(jobsInPhases.allJobs,
100100
showJobLifecycle: showJobLifecycle,

Tests/SwiftDriverTests/ExplicitModuleBuildTests.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -845,15 +845,19 @@ final class ExplicitModuleBuildTests: XCTestCase {
845845
let incrementalJobs = try incrementalDriver.planBuild()
846846
try incrementalDriver.run(jobs: incrementalJobs)
847847
XCTAssertFalse(incrementalDriver.diagnosticEngine.hasErrors)
848+
let state = try XCTUnwrap(incrementalDriver.incrementalCompilationState)
849+
XCTAssertTrue(state.mandatoryJobsInOrder.contains { $0.kind == .emitModule })
850+
XCTAssertTrue(state.jobsAfterCompiles.contains { $0.kind == .verifyModuleInterface })
848851

849852
// TODO: emitModule job should run again if interface is deleted.
850853
// try localFileSystem.removeFileTree(swiftInterfaceOutput)
851854

852855
// This should be a null build but it is actually building the main module due to the previous build of all the modules.
853856
var reDriver = try Driver(args: invocationArguments + ["-color-diagnostics"])
854-
let reJobs = try reDriver.planBuild()
855-
XCTAssertFalse(reJobs.contains { $0.kind == .emitModule })
856-
XCTAssertFalse(reJobs.contains { $0.kind == .verifyModuleInterface })
857+
let _ = try reDriver.planBuild()
858+
let reState = try XCTUnwrap(reDriver.incrementalCompilationState)
859+
XCTAssertFalse(reState.mandatoryJobsInOrder.contains { $0.kind == .emitModule })
860+
XCTAssertFalse(reState.jobsAfterCompiles.contains { $0.kind == .verifyModuleInterface })
857861
}
858862
}
859863

Tests/SwiftDriverTests/IncrementalCompilationTests.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,14 @@ extension IncrementalCompilationTests {
220220

221221
// Null planning should not return an empty compile job for compatibility reason.
222222
// `swift-build` wraps the jobs returned by swift-driver in `Executor` so returning an empty list of compile job will break build system.
223-
func testNullPlanningCompatility() throws {
223+
func testNullPlanningCompatibility() throws {
224224
guard let sdkArgumentsForTesting = try Driver.sdkArgumentsForTesting() else {
225225
throw XCTSkip("Cannot perform this test on this host")
226226
}
227-
var driver = try Driver(args: commonArgs + sdkArgumentsForTesting)
227+
let extraArguments = ["-experimental-emit-module-separately", "-emit-module"]
228+
var driver = try Driver(args: commonArgs + extraArguments + sdkArgumentsForTesting)
228229
let initialJobs = try driver.planBuild()
230+
XCTAssertTrue(initialJobs.contains { $0.kind == .emitModule})
229231
try driver.run(jobs: initialJobs)
230232

231233
// Plan the build again without touching any file. This should be a null build but for compatibility reason,
@@ -235,6 +237,7 @@ extension IncrementalCompilationTests {
235237
XCTAssertFalse(
236238
replanJobs.filter { $0.kind == .compile }.isEmpty,
237239
"more than one compile job needs to be planned")
240+
XCTAssertTrue(replanJobs.contains { $0.kind == .emitModule})
238241
}
239242
}
240243

0 commit comments

Comments
 (0)