diff --git a/Sources/SWBBuildSystem/BuildOperation.swift b/Sources/SWBBuildSystem/BuildOperation.swift index b0a049b9..826bfea3 100644 --- a/Sources/SWBBuildSystem/BuildOperation.swift +++ b/Sources/SWBBuildSystem/BuildOperation.swift @@ -525,7 +525,7 @@ package final class BuildOperation: BuildSystemOperation { return .commandNamePriority }() - let laneWidth = UserDefaults.schedulerLaneWidth ?? 0 + let laneWidth = request.schedulerLaneWidthOverride ?? UserDefaults.schedulerLaneWidth ?? 0 // Create the low-level build system. let adaptor: OperationSystemAdaptor @@ -542,7 +542,7 @@ package final class BuildOperation: BuildSystemOperation { if let entry { // If the entry is valid, reuse it. - if let cachedAdaptor = entry.adaptor, entry.environment == buildEnvironment, entry.buildDescription! === buildDescription, entry.llbQoS == llbQoS { + if let cachedAdaptor = entry.adaptor, entry.environment == buildEnvironment, entry.buildDescription! === buildDescription, entry.llbQoS == llbQoS, entry.laneWidth == laneWidth { adaptor = cachedAdaptor await adaptor.reset(operation: self, buildOutputDelegate: buildOutputDelegate) } else { @@ -551,6 +551,7 @@ package final class BuildOperation: BuildSystemOperation { entry.adaptor = adaptor entry.buildDescription = buildDescription entry.llbQoS = llbQoS + entry.laneWidth = laneWidth entry.fileSystemMode = fs.fileSystemMode entry.system = SWBLLBuild.BuildSystem(buildFile: buildDescription.manifestPath.str, databaseFile: dbPath.str, delegate: adaptor, environment: buildEnvironment, serial: serial, traceFile: traceFile?.str, schedulerAlgorithm: algorithm, schedulerLanes: laneWidth, qos: llbQoS) } diff --git a/Sources/SWBBuildSystem/BuildSystemCache.swift b/Sources/SWBBuildSystem/BuildSystemCache.swift index 82873d9a..645d3837 100644 --- a/Sources/SWBBuildSystem/BuildSystemCache.swift +++ b/Sources/SWBBuildSystem/BuildSystemCache.swift @@ -40,6 +40,9 @@ package final class SystemCacheEntry: CacheableValue { /// The QoS to use for the llbuild invocation. var llbQoS: SWBLLBuild.BuildSystem.QualityOfService? = nil + /// Overrides the number of llbuild scheduler lanes. + var laneWidth: UInt32 = 0 + /// The system to use. var system: SWBLLBuild.BuildSystem? = nil diff --git a/Sources/SWBCore/BuildRequest.swift b/Sources/SWBCore/BuildRequest.swift index c7720567..622ead43 100644 --- a/Sources/SWBCore/BuildRequest.swift +++ b/Sources/SWBCore/BuildRequest.swift @@ -260,6 +260,9 @@ public final class BuildRequest: CustomStringConvertible, Sendable { /// The quality-of-service to use for this request. public let qos: SWBQoS + /// Overrides the number of lanes in the llbuild scheduler. + public let schedulerLaneWidthOverride: UInt32? + /// Optional path of a directory into which to write diagnostic information about the build plan. public let buildPlanDiagnosticsDirPath: Path? @@ -282,7 +285,7 @@ public final class BuildRequest: CustomStringConvertible, Sendable { /// - Parameters: /// - parameters: The default build parameters, used in non-target specific contexts. /// - buildTargets: The list of targets which should be built - public init(parameters: BuildParameters, buildTargets: [BuildTargetInfo], dependencyScope: DependencyScope = .workspace, continueBuildingAfterErrors: Bool, hideShellScriptEnvironment: Bool = false, useParallelTargets: Bool, useImplicitDependencies: Bool, useDryRun: Bool, enableStaleFileRemoval: Bool? = nil, showNonLoggedProgress: Bool = true, recordBuildBacktraces: Bool? = nil, generatePrecompiledModulesReport: Bool? = nil, buildDescriptionID: BuildDescriptionID? = nil, qos: SWBQoS? = nil, buildPlanDiagnosticsDirPath: Path? = nil, buildCommand: BuildCommand? = nil, schemeCommand: SchemeCommand? = .launch, containerPath: Path? = nil, jsonRepresentation: Data? = nil) { + public init(parameters: BuildParameters, buildTargets: [BuildTargetInfo], dependencyScope: DependencyScope = .workspace, continueBuildingAfterErrors: Bool, hideShellScriptEnvironment: Bool = false, useParallelTargets: Bool, useImplicitDependencies: Bool, useDryRun: Bool, enableStaleFileRemoval: Bool? = nil, showNonLoggedProgress: Bool = true, recordBuildBacktraces: Bool? = nil, generatePrecompiledModulesReport: Bool? = nil, buildDescriptionID: BuildDescriptionID? = nil, qos: SWBQoS? = nil, schedulerLaneWidthOverride: UInt32? = nil, buildPlanDiagnosticsDirPath: Path? = nil, buildCommand: BuildCommand? = nil, schemeCommand: SchemeCommand? = .launch, containerPath: Path? = nil, jsonRepresentation: Data? = nil) { self.parameters = parameters self.buildTargets = buildTargets self.dependencyScope = dependencyScope @@ -298,6 +301,7 @@ public final class BuildRequest: CustomStringConvertible, Sendable { self.generatePrecompiledModulesReport = generatePrecompiledModulesReport ?? SWBFeatureFlag.generatePrecompiledModulesReport.value self.buildDescriptionID = buildDescriptionID self.qos = qos ?? UserDefaults.defaultRequestQoS + self.schedulerLaneWidthOverride = schedulerLaneWidthOverride self.buildPlanDiagnosticsDirPath = buildPlanDiagnosticsDirPath self.buildCommand = buildCommand ?? .build(style: .buildOnly, skipDependencies: false) self.schemeCommand = schemeCommand @@ -332,7 +336,7 @@ extension BuildRequest { case .buildRequest: dependencyScope = .buildRequest } - try self.init(parameters: parameters, buildTargets: payload.configuredTargets.map{ try BuildRequest.BuildTargetInfo(from: $0, defaultParameters: parameters, workspace: workspace) }, dependencyScope: dependencyScope, continueBuildingAfterErrors: payload.continueBuildingAfterErrors, hideShellScriptEnvironment: payload.hideShellScriptEnvironment, useParallelTargets: payload.useParallelTargets, useImplicitDependencies: payload.useImplicitDependencies, useDryRun: payload.useDryRun, enableStaleFileRemoval: nil, showNonLoggedProgress: payload.showNonLoggedProgress, recordBuildBacktraces: payload.recordBuildBacktraces, generatePrecompiledModulesReport: payload.generatePrecompiledModulesReport, buildDescriptionID: payload.buildDescriptionID.map(BuildDescriptionID.init), qos: qos, buildPlanDiagnosticsDirPath: payload.buildPlanDiagnosticsDirPath, buildCommand: buildCommand, schemeCommand: payload.schemeCommand?.coreRepresentation, containerPath: payload.containerPath, jsonRepresentation: payload.jsonRepresentation) + try self.init(parameters: parameters, buildTargets: payload.configuredTargets.map{ try BuildRequest.BuildTargetInfo(from: $0, defaultParameters: parameters, workspace: workspace) }, dependencyScope: dependencyScope, continueBuildingAfterErrors: payload.continueBuildingAfterErrors, hideShellScriptEnvironment: payload.hideShellScriptEnvironment, useParallelTargets: payload.useParallelTargets, useImplicitDependencies: payload.useImplicitDependencies, useDryRun: payload.useDryRun, enableStaleFileRemoval: nil, showNonLoggedProgress: payload.showNonLoggedProgress, recordBuildBacktraces: payload.recordBuildBacktraces, generatePrecompiledModulesReport: payload.generatePrecompiledModulesReport, buildDescriptionID: payload.buildDescriptionID.map(BuildDescriptionID.init), qos: qos, schedulerLaneWidthOverride: payload.schedulerLaneWidthOverride, buildPlanDiagnosticsDirPath: payload.buildPlanDiagnosticsDirPath, buildCommand: buildCommand, schemeCommand: payload.schemeCommand?.coreRepresentation, containerPath: payload.containerPath, jsonRepresentation: payload.jsonRepresentation) } /// Whether the build request _explicitly_ contains the specified `target`. diff --git a/Sources/SWBProtocol/MessageSupport.swift b/Sources/SWBProtocol/MessageSupport.swift index e78e9465..81544c7e 100644 --- a/Sources/SWBProtocol/MessageSupport.swift +++ b/Sources/SWBProtocol/MessageSupport.swift @@ -166,9 +166,10 @@ public struct BuildRequestMessagePayload: SerializableCodable, Equatable, Sendab public var containerPath: Path? public var buildDescriptionID: String? public var qos: BuildQoSMessagePayload? + public var schedulerLaneWidthOverride: UInt32? public var jsonRepresentation: Foundation.Data? - public init(parameters: BuildParametersMessagePayload, configuredTargets: [ConfiguredTargetMessagePayload], dependencyScope: DependencyScopeMessagePayload, continueBuildingAfterErrors: Bool, hideShellScriptEnvironment: Bool, useParallelTargets: Bool, useImplicitDependencies: Bool, useDryRun: Bool, showNonLoggedProgress: Bool, recordBuildBacktraces: Bool?, generatePrecompiledModulesReport: Bool?, buildPlanDiagnosticsDirPath: Path?, buildCommand: BuildCommandMessagePayload, schemeCommand: SchemeCommandMessagePayload?, containerPath: Path?, buildDescriptionID: String?, qos: BuildQoSMessagePayload?, jsonRepresentation: Foundation.Data?) { + public init(parameters: BuildParametersMessagePayload, configuredTargets: [ConfiguredTargetMessagePayload], dependencyScope: DependencyScopeMessagePayload, continueBuildingAfterErrors: Bool, hideShellScriptEnvironment: Bool, useParallelTargets: Bool, useImplicitDependencies: Bool, useDryRun: Bool, showNonLoggedProgress: Bool, recordBuildBacktraces: Bool?, generatePrecompiledModulesReport: Bool?, buildPlanDiagnosticsDirPath: Path?, buildCommand: BuildCommandMessagePayload, schemeCommand: SchemeCommandMessagePayload?, containerPath: Path?, buildDescriptionID: String?, qos: BuildQoSMessagePayload?, schedulerLaneWidthOverride: UInt32?, jsonRepresentation: Foundation.Data?) { self.parameters = parameters self.configuredTargets = configuredTargets self.dependencyScope = dependencyScope @@ -186,6 +187,7 @@ public struct BuildRequestMessagePayload: SerializableCodable, Equatable, Sendab self.containerPath = containerPath self.buildDescriptionID = buildDescriptionID self.qos = qos + self.schedulerLaneWidthOverride = schedulerLaneWidthOverride self.jsonRepresentation = jsonRepresentation } @@ -207,6 +209,7 @@ public struct BuildRequestMessagePayload: SerializableCodable, Equatable, Sendab case containerPath case buildDescriptionID case qos + case schedulerLaneWidthOverride case jsonRepresentation } @@ -230,6 +233,7 @@ public struct BuildRequestMessagePayload: SerializableCodable, Equatable, Sendab self.containerPath = try container.decodeIfPresent(Path.self, forKey: BuildRequestMessagePayload.CodingKeys.containerPath) self.buildDescriptionID = try container.decodeIfPresent(String.self, forKey: BuildRequestMessagePayload.CodingKeys.buildDescriptionID) self.qos = try container.decodeIfPresent(BuildQoSMessagePayload.self, forKey: BuildRequestMessagePayload.CodingKeys.qos) + self.schedulerLaneWidthOverride = try container.decodeIfPresent(UInt32.self, forKey: BuildRequestMessagePayload.CodingKeys.schedulerLaneWidthOverride) self.jsonRepresentation = try container.decodeIfPresent(Data.self, forKey: BuildRequestMessagePayload.CodingKeys.jsonRepresentation) } @@ -254,6 +258,7 @@ public struct BuildRequestMessagePayload: SerializableCodable, Equatable, Sendab try container.encodeIfPresent(self.containerPath, forKey: BuildRequestMessagePayload.CodingKeys.containerPath) try container.encodeIfPresent(self.buildDescriptionID, forKey: BuildRequestMessagePayload.CodingKeys.buildDescriptionID) try container.encodeIfPresent(self.qos, forKey: BuildRequestMessagePayload.CodingKeys.qos) + try container.encodeIfPresent(self.schedulerLaneWidthOverride, forKey: BuildRequestMessagePayload.CodingKeys.schedulerLaneWidthOverride) try container.encodeIfPresent(self.jsonRepresentation, forKey: BuildRequestMessagePayload.CodingKeys.jsonRepresentation) } } diff --git a/Sources/SwiftBuild/SWBBuildRequest.swift b/Sources/SwiftBuild/SWBBuildRequest.swift index a13c00b0..ba20964f 100644 --- a/Sources/SwiftBuild/SWBBuildRequest.swift +++ b/Sources/SwiftBuild/SWBBuildRequest.swift @@ -294,6 +294,9 @@ public struct SWBBuildRequest: Codable, Sendable { /// The QoS to use for the build operation. If not set then a default QoS, that can be configured with a UserDefault, will be selected. public var qos: SWBBuildQoS? = nil + /// Overrides the default number of scheduler lanes used by llbuild. + public var schedulerLaneWidthOverride: UInt32? = nil + /// Whether or not legacy build locations are being used. Currently, this flag is only relevant for clean build folder. public var useLegacyBuildLocations = false diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index 2378c2fe..fcacfc99 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -819,7 +819,7 @@ extension SWBBuildQoS { extension SWBBuildRequest { var messagePayloadRepresentation: BuildRequestMessagePayload { - return BuildRequestMessagePayload(parameters: parameters.messagePayloadRepresentation, configuredTargets: configuredTargets.map{ $0.messagePayloadRepresentation }, dependencyScope: dependencyScope.messagePayload, continueBuildingAfterErrors: continueBuildingAfterErrors, hideShellScriptEnvironment: hideShellScriptEnvironment, useParallelTargets: useParallelTargets, useImplicitDependencies: useImplicitDependencies, useDryRun: useDryRun, showNonLoggedProgress: showNonLoggedProgress, recordBuildBacktraces: recordBuildBacktraces, generatePrecompiledModulesReport: generatePrecompiledModulesReport, buildPlanDiagnosticsDirPath: buildPlanDiagnosticsDirPath.map(Path.init), buildCommand: buildCommand.messagePayloadRepresentation, schemeCommand: schemeCommand?.messagePayloadRepresentation, containerPath: containerPath.map(Path.init), buildDescriptionID: buildDescriptionID, qos: qos?.messagePayloadRepresentation, jsonRepresentation: try? jsonData()) + return BuildRequestMessagePayload(parameters: parameters.messagePayloadRepresentation, configuredTargets: configuredTargets.map{ $0.messagePayloadRepresentation }, dependencyScope: dependencyScope.messagePayload, continueBuildingAfterErrors: continueBuildingAfterErrors, hideShellScriptEnvironment: hideShellScriptEnvironment, useParallelTargets: useParallelTargets, useImplicitDependencies: useImplicitDependencies, useDryRun: useDryRun, showNonLoggedProgress: showNonLoggedProgress, recordBuildBacktraces: recordBuildBacktraces, generatePrecompiledModulesReport: generatePrecompiledModulesReport, buildPlanDiagnosticsDirPath: buildPlanDiagnosticsDirPath.map(Path.init), buildCommand: buildCommand.messagePayloadRepresentation, schemeCommand: schemeCommand?.messagePayloadRepresentation, containerPath: containerPath.map(Path.init), buildDescriptionID: buildDescriptionID, qos: qos?.messagePayloadRepresentation, schedulerLaneWidthOverride: schedulerLaneWidthOverride, jsonRepresentation: try? jsonData()) } } diff --git a/Tests/SWBProtocolTests/MessageSerializationTests.swift b/Tests/SWBProtocolTests/MessageSerializationTests.swift index c749db18..e3ba3878 100644 --- a/Tests/SWBProtocolTests/MessageSerializationTests.swift +++ b/Tests/SWBProtocolTests/MessageSerializationTests.swift @@ -55,7 +55,7 @@ import Testing ) ) - payload = BuildRequestMessagePayload(parameters: params, configuredTargets: [ConfiguredTargetMessagePayload(guid: "some other guid", parameters: params)], dependencyScope: .workspace, continueBuildingAfterErrors: true, hideShellScriptEnvironment: false, useParallelTargets: true, useImplicitDependencies: false, useDryRun: true, showNonLoggedProgress: false, recordBuildBacktraces: nil, generatePrecompiledModulesReport: nil, buildPlanDiagnosticsDirPath: Path("/tmp/foobar"), buildCommand: .prepareForIndexing(buildOnlyTheseTargets: nil, enableIndexBuildArena: false), schemeCommand: .profile, containerPath: Path("/tmp/foobar.xcodeproj"), buildDescriptionID: nil, qos: nil, jsonRepresentation: Data()) + payload = BuildRequestMessagePayload(parameters: params, configuredTargets: [ConfiguredTargetMessagePayload(guid: "some other guid", parameters: params)], dependencyScope: .workspace, continueBuildingAfterErrors: true, hideShellScriptEnvironment: false, useParallelTargets: true, useImplicitDependencies: false, useDryRun: true, showNonLoggedProgress: false, recordBuildBacktraces: nil, generatePrecompiledModulesReport: nil, buildPlanDiagnosticsDirPath: Path("/tmp/foobar"), buildCommand: .prepareForIndexing(buildOnlyTheseTargets: nil, enableIndexBuildArena: false), schemeCommand: .profile, containerPath: Path("/tmp/foobar.xcodeproj"), buildDescriptionID: nil, qos: nil, schedulerLaneWidthOverride: nil, jsonRepresentation: Data()) } @Test func basicMessagesRoundTrip() throws {