in Public/Src/Engine/Dll/Engine.cs [867:1310]
public static bool PopulateAndValidateConfiguration(
ConfigurationImpl mutableConfig,
ICommandLineConfiguration initialCommandLineConfiguration,
PathTable pathTable,
LoggingContext loggingContext)
{
bool success = true;
foreach (var property in initialCommandLineConfiguration.Startup.Properties)
{
EngineEnvironmentSettings.SetVariable(property.Key, property.Value);
}
// Customer builds may involve a lot of large strings that can fill up the string table.
// Adding a non-zero overflow buffer count increases the capacity of the string table.
// Large string buffer is a secondary table used when the strings are large. By adjusting the threshold for
// the string size, some of the large strings that used to go to the string table can go to the large string buffer.
StringTable.OverrideStringTableDefaults(EngineEnvironmentSettings.LargeStringBufferThresholdBytes);
if (mutableConfig.Export.SnapshotFile.IsValid && mutableConfig.Export.SnapshotMode != SnapshotMode.None)
{
// Note: the /CleanOnly also overrides the Phase. In this case it is safe. An evaluation snapshot 'can' work with the 'schedule' phase in case both are set.
mutableConfig.Engine.Phase = mutableConfig.Export.SnapshotMode == SnapshotMode.Full
? EnginePhases.Schedule
: EnginePhases.Evaluate;
// TODO: Snapshot mode does not work when loading cached graph. Can input tracker be used to capture/load the same information as
// the snapshot collector so snapshot works with graph caching.
mutableConfig.Cache.CacheGraph = false;
}
// The /cleanonly option should override the phase to only schedule and not perform execution
if (mutableConfig.Engine.CleanOnly)
{
// Note: the snapshot option also sets the phase. In this case it is safe. An evaluation snapshot 'can' work with the 'schedule' phase in case both are set.
mutableConfig.Engine.Phase = EnginePhases.Schedule;
}
// Distribution overrides
if (mutableConfig.Distribution.BuildRole.IsOrchestrator())
{
if (!mutableConfig.Distribution.BuildWorkers.Any())
{
// Disable the distribution if no remote worker is given.
mutableConfig.Distribution.BuildRole = DistributedBuildRoles.None;
mutableConfig.Distribution.LowWorkersWarningThreshold = 0;
}
else
{
var remoteWorkerCount = mutableConfig.Distribution.BuildWorkers.Count;
if (mutableConfig.Distribution.LowWorkersWarningThreshold == null)
{
mutableConfig.Distribution.LowWorkersWarningThreshold = remoteWorkerCount/2;
}
else
{
mutableConfig.Distribution.LowWorkersWarningThreshold = Math.Min(remoteWorkerCount + 1, mutableConfig.Distribution.LowWorkersWarningThreshold.Value);
}
// Force graph caching because the orchestrator needs to communicate it to the worker.
mutableConfig.Cache.CacheGraph = true;
}
}
else
{
mutableConfig.Distribution.LowWorkersWarningThreshold = 0;
}
if (!mutableConfig.Distribution.BuildRole.IsOrchestrator() || mutableConfig.Schedule.ModuleAffinityEnabled())
{
// No additional choose worker threads needed in single machine builds, workers, or orchestrators when module affinity is enabled
mutableConfig.Schedule.MaxChooseWorkerCpu = 1;
mutableConfig.Schedule.MaxChooseWorkerCacheLookup = 1;
}
// Caching overrides
if (mutableConfig.Cache.CachedGraphLastBuildLoad)
{
mutableConfig.Cache.CachedGraphPathToLoad = mutableConfig.Layout.EngineCacheDirectory;
mutableConfig.Cache.CachedGraphLastBuildLoad = false;
}
// Cache config file path.
if (!mutableConfig.Cache.CacheConfigFile.IsValid)
{
// Use default cache config file if nothing is specified.
Assembly executingAssembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly();
var executingAssemblyDirectory = Path.GetDirectoryName(AssemblyHelper.GetAssemblyLocation(executingAssembly));
Contract.Assert(!string.IsNullOrEmpty(executingAssemblyDirectory));
var defaultCacheConfigFile = AbsolutePath.Create(pathTable, Path.Combine(executingAssemblyDirectory, DefaultCacheConfigFileName));
mutableConfig.Cache.CacheConfigFile = defaultCacheConfigFile;
}
// There is funny handling in the configuration for these two settings in conjuction with allowlist settings:
// * Turning off UnexpectedFileAccessesAreErrors (this code), or
// * Declaring a allowlist in config.
// (story 169157) Tracks cleaning this up.
mutableConfig.Sandbox.FailUnexpectedFileAccesses = mutableConfig.Sandbox.UnsafeSandboxConfiguration.UnexpectedFileAccessesAreErrors;
// New semantics of /unsafe_DisableDetours --> fully disables sandboxing and runs processes using the plain .NET Process class.
// This effectively means that MonitorFileAccesses should be disabled.
if (mutableConfig.Sandbox.UnsafeSandboxConfiguration.DisableDetours())
{
mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.MonitorFileAccesses = false;
}
foreach (var variable in mutableConfig.AllowedEnvironmentVariables)
{
if (DisallowedTempVariables.Contains(variable))
{
Logger.Log.EnvironmentValueForTempDisallowed(
loggingContext,
mutableConfig.Layout.PrimaryConfigFile.ToString(pathTable),
0,
0,
variable);
success = false;
}
}
mutableConfig.Location = new LocationData(mutableConfig.Layout.PrimaryConfigFile, 0, 0);
// Validate the global module configuration from the config file
success &= ValidateModuleConfig(mutableConfig, pathTable, loggingContext, mutableConfig.Sandbox);
foreach (var moduleConfiguration in mutableConfig.ModulePolicies.Values)
{
// Validate the module specific configurations
success &= ValidateModuleConfig(moduleConfiguration, pathTable, loggingContext, mutableConfig.Sandbox);
}
// Directory translation.
success &= ValidateSubstAndDirectoryTranslation(mutableConfig, pathTable, loggingContext);
// Configure Ide Generation if it is enabled
if (mutableConfig.Ide.IsEnabled)
{
IdeGenerator.Configure(mutableConfig, initialCommandLineConfiguration.Startup, pathTable);
}
var frontEndConfig = mutableConfig.FrontEnd;
// Incremental frontend is turned off for office.
if (frontEndConfig.UseLegacyOfficeLogic == true)
{
frontEndConfig.EnableIncrementalFrontEnd = false;
}
// Reusing ast and public facade implies that the binding fingerprint is saved
// It also implies that we need to partially reload the engine state, since consistent
// tables across builds are needed
if (frontEndConfig.UseSpecPublicFacadeAndAstWhenAvailable())
{
frontEndConfig.ConstructAndSaveBindingFingerprint = true;
frontEndConfig.ReloadPartialEngineStateWhenPossible = true;
}
if (mutableConfig.Schedule.ForceSkipDependencies != ForceSkipDependenciesMode.Disabled)
{
// Lazy materialization is not compatible with force skip dependencies
mutableConfig.Schedule.EnableLazyOutputMaterialization = false;
}
if (mutableConfig.Schedule.AdaptiveIO)
{
Contract.Assert(mutableConfig.Logging.LogCounters, "AdaptiveIO requires the logCounters flag");
// If the adaptive IO is enabled and the user does not pass a custom maxIO value, then use the number of processors as the IO limit.
mutableConfig.Schedule.MaxIO = Environment.ProcessorCount;
// If the adaptive IO is enabled and the user does not pass a custom statusFrequencyMs, then use 1000ms as a statusFrequency.
// In the interval of 1000ms, both status messages will be printed on console and the maximum limit for the IO will be adjusted.
if (mutableConfig.Logging.StatusFrequencyMs == 0)
{
mutableConfig.Logging.StatusFrequencyMs = 1000;
}
}
if (!mutableConfig.Logging.FailPipOnFileAccessError)
{
mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.UnexpectedFileAccessesAreErrors = false;
}
if (mutableConfig.Schedule.UnsafeLazySODeletion &&
mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.SandboxKind == SandboxKind.None)
{
mutableConfig.Schedule.UnsafeLazySODeletion = false;
}
if (mutableConfig.Schedule.UnsafeLazySODeletion)
{
// must compute static fingerprints when using lazy shared opaque output deletion
mutableConfig.Schedule.ComputePipStaticFingerprints = true;
}
// Turn off incremental scheduling when incompatible features are enabled.
if (mutableConfig.Schedule.IncrementalScheduling)
{
if (!mutableConfig.Cache.Incremental)
{
// If incremental is turned off, incremental scheduling should be too. Don't bother logging.
mutableConfig.Schedule.IncrementalScheduling = false;
}
if (!mutableConfig.Engine.ScanChangeJournal)
{
// If scan change journal is turned off, incremental scheduling should be too. Don't bother logging.
mutableConfig.Schedule.IncrementalScheduling = false;
}
if (mutableConfig.Cache.FileChangeTrackingExclusionRoots.Count != 0)
{
mutableConfig.Schedule.IncrementalScheduling = false;
Logger.Log.ConfigIncompatibleIncrementalSchedulingDisabled(loggingContext, "/fileChangeTrackingExclusionRoot");
}
if (mutableConfig.Cache.FileChangeTrackingInclusionRoots.Count != 0)
{
mutableConfig.Schedule.IncrementalScheduling = false;
Logger.Log.ConfigIncompatibleIncrementalSchedulingDisabled(loggingContext, "/fileChangeTrackingInclusionRoot");
}
if (mutableConfig.Schedule.SkipHashSourceFile)
{
mutableConfig.Schedule.IncrementalScheduling = false;
Logger.Log.ConfigIncompatibleIncrementalSchedulingDisabled(loggingContext, "/skipHashSourceFile");
}
// If incremental scheduling is still on, then we need to compute the static fingerprints.
if (mutableConfig.Schedule.IncrementalScheduling)
{
mutableConfig.Schedule.ComputePipStaticFingerprints = true;
}
}
// Environment-specific defaults/behaviors
mutableConfig.Schedule.EnvironmentFingerprint = I($"RunningEnvironment:{mutableConfig.Logging.Environment}|InCloudBuild:{mutableConfig.InCloudBuild()}");
// Distributed build overrides (including all CB builds because one worker CB builds are configured as distributed)
if (mutableConfig.Distribution.BuildRole != DistributedBuildRoles.None)
{
mutableConfig.Schedule.ScheduleMetaPips = false;
if (!mutableConfig.Schedule.StoreOutputsToCache)
{
mutableConfig.Schedule.StoreOutputsToCache = true;
Logger.Log.ConfigIncompatibleOptionWithDistributedBuildWarn(
loggingContext,
"/storeOutputsToCache",
mutableConfig.Schedule.StoreOutputsToCache.ToString(CultureInfo.InvariantCulture),
true.ToString(CultureInfo.InvariantCulture));
}
if (mutableConfig.Sandbox.UnsafeSandboxConfiguration.PreserveOutputs != PreserveOutputsMode.Disabled)
{
mutableConfig.Sandbox.UnsafeSandboxConfigurationMutable.PreserveOutputs = PreserveOutputsMode.Disabled;
Logger.Log.ConfigIncompatibleOptionWithDistributedBuildWarn(
loggingContext,
"/unsafe_PreserveOutputs",
mutableConfig.Sandbox.UnsafeSandboxConfiguration.PreserveOutputs.ToString(),
PreserveOutputsMode.Disabled.ToString());
}
}
if (mutableConfig.Sandbox.UnsafeSandboxConfiguration.IgnorePreserveOutputsPrivatization
&& mutableConfig.Sandbox.UnsafeSandboxConfiguration.PreserveOutputs != PreserveOutputsMode.Disabled
&& mutableConfig.Schedule.StoreOutputsToCache)
{
Logger.Log.ConfigIncompatibleOptionIgnorePreserveOutputsPrivatization(loggingContext);
success = false;
}
// CloudBuild overrides
if (mutableConfig.InCloudBuild())
{
if (mutableConfig.Schedule.MinimumDiskSpaceForPipsGb == null)
{
mutableConfig.Schedule.MinimumDiskSpaceForPipsGb = 5;
}
if (mutableConfig.Distribution.NumRetryFailedPipsOnAnotherWorker == null)
{
mutableConfig.Distribution.NumRetryFailedPipsOnAnotherWorker = 3;
}
// Enable fail fast for null reference exceptions caught by
// ExceptionUtilities.IsUnexpectedException
EngineEnvironmentSettings.FailFastOnNullReferenceException.Value = true;
EngineEnvironmentSettings.SkipExtraneousPins.TrySet(true);
mutableConfig.Engine.ScanChangeJournal = false;
mutableConfig.Schedule.IncrementalScheduling = false;
// lazy scrubbing is only meant for speeding up single-machine dev builds
mutableConfig.Schedule.UnsafeLazySODeletion = false;
// Disable viewer
mutableConfig.Viewer = ViewerMode.Disable;
// Enable historic ram and CPU based throttling in CloudBuild by default if it is not explicitly disabled.
mutableConfig.Schedule.UseHistoricalRamUsageInfo = initialCommandLineConfiguration.Schedule.UseHistoricalRamUsageInfo ?? true;
mutableConfig.Schedule.UseHistoricalCpuUsageInfo = initialCommandLineConfiguration.Schedule.UseHistoricalCpuUsageInfo ?? true;
mutableConfig.Cache.FileContentTableEntryTimeToLive = mutableConfig.Cache.FileContentTableEntryTimeToLive ?? 100;
// Minimize output materialization in cloudbuild
mutableConfig.Schedule.EnableLazyWriteFileMaterialization = true;
mutableConfig.Schedule.WriteIpcOutput = false;
if (!mutableConfig.Logging.ReplayWarnings.HasValue)
{
mutableConfig.Logging.ReplayWarnings = false;
}
// Use compression for graph files to greatly reduce the size
mutableConfig.Engine.CompressGraphFiles = true;
// Ensure that historic perf data is retrieved from cache because engine cache
// can be reused for multiple locations
mutableConfig.Schedule.ForceUseEngineInfoFromCache = true;
mutableConfig.Cache.HistoricMetadataCache = initialCommandLineConfiguration.Cache.HistoricMetadataCache ?? true;
// In CB we don't actually want this to become a parameter that is actively used, so make it large enough
mutableConfig.Schedule.MinimumTotalAvailableRamMb = initialCommandLineConfiguration.Schedule.MinimumTotalAvailableRamMb ?? 100000000;
mutableConfig.Schedule.ScheduleMetaPips = false;
// In CloudBuild always place EngineCache under object directory
mutableConfig.Layout.EngineCacheDirectory = mutableConfig.Layout.ObjectDirectory.Combine(pathTable, Strings.Layout_DefaultEngineCacheFolderName);
// Add additional context to environment fingerprint
foreach (var entry in mutableConfig.Logging.TraceInfo)
{
if (entry.Key.Equals(TraceInfoExtensions.CustomFingerprint, StringComparison.OrdinalIgnoreCase))
{
mutableConfig.Schedule.EnvironmentFingerprint += I($"|{TraceInfoExtensions.CustomFingerprint}:{entry.Value}");
}
else if (entry.Key.Equals(TraceInfoExtensions.CloudBuildQueue, StringComparison.OrdinalIgnoreCase))
{
mutableConfig.Schedule.EnvironmentFingerprint += I($"|{TraceInfoExtensions.CloudBuildQueue}:{entry.Value}");
}
}
if (mutableConfig.Logging.CacheMissAnalysisOption.Mode == CacheMissMode.Local)
{
// BuildXL should not use local fingerprintstore for cache miss analysis.
// Because you do not know how old is that fingerprintstore, the data is not really useful.
mutableConfig.Logging.CacheMissAnalysisOption.Mode = CacheMissMode.Disabled;
}
mutableConfig.Logging.StoreFingerprints = initialCommandLineConfiguration.Logging.StoreFingerprints ?? false;
mutableConfig.Sandbox.RetryOnAzureWatsonExitCode = true;
// Spec cache is disabled as most builds are happening on SSDs.
mutableConfig.Cache.CacheSpecs = SpecCachingOption.Disabled;
if (mutableConfig.Logging.Environment == ExecutionEnvironment.OsgLab)
{
// For Cosine builds in CloudBuild, enable delayedCacheLookup by default.
if (mutableConfig.Schedule.DelayedCacheLookupMaxMultiplier == null &&
mutableConfig.Schedule.DelayedCacheLookupMinMultiplier == null)
{
mutableConfig.Schedule.DelayedCacheLookupMaxMultiplier = 2;
mutableConfig.Schedule.DelayedCacheLookupMinMultiplier = 1;
}
// For Cosine builds, IsObsoleteCheck is very expensive, so we disable it.
// Cosine specs are automatically generated, so that check was not necessary.
mutableConfig.FrontEnd.DisableIsObsoleteCheckDuringConversion = true;
// Early worker release gives very small benefit (1-2%) to Cosine builds,
// so it is disabled.
mutableConfig.Distribution.EarlyWorkerRelease = false;
}
if (mutableConfig.Schedule.ManageMemoryMode == null)
{
// If ManageMemoryMode is unset for CB builds, we use EmptyWorkingSet option due to the large page file size in CB machines.
mutableConfig.Schedule.ManageMemoryMode = ManageMemoryMode.EmptyWorkingSet;
}
// Since VFS lives inside BXL process currently. Disallow on office enlist and meta build because
// they materialize files which would be needed by subsequent invocations and thus requires VFS to
// span multiple invocations. Just starting at Product build is sufficient.
if (mutableConfig.Logging.Environment == ExecutionEnvironment.OfficeMetaBuildLab
|| mutableConfig.Logging.Environment == ExecutionEnvironment.OfficeEnlistmentBuildLab)
{
mutableConfig.Cache.VfsCasRoot = AbsolutePath.Invalid;
}
// Unless otherwise specified, distributed metabuilds in CloudBuild should replicate outputs to all machines
// TODO: Remove this once reduced metabuild materialization is fully tested
if (mutableConfig.Distribution.ReplicateOutputsToWorkers == null
&& mutableConfig.Logging.Environment == ExecutionEnvironment.OfficeMetaBuildLab
&& mutableConfig.Distribution.BuildRole.IsOrchestrator())
{
mutableConfig.Distribution.ReplicateOutputsToWorkers = true;
}
// When running in cloudbuild we want to ignore the user setting the interactive flag
// and force it to be false since we never want to pop up UI there.
mutableConfig.Interactive = false;
// Fire forget materialize output is enabled by default in CloudBuild as it improves the perf during meta build.
mutableConfig.Distribution.FireForgetMaterializeOutput = initialCommandLineConfiguration.Distribution.FireForgetMaterializeOutput ?? true;
}
else
{
mutableConfig.Logging.StoreFingerprints = initialCommandLineConfiguration.Logging.StoreFingerprints ?? true;
}
// If graph patching is requested, we need to reload the engine state when possible
if (frontEndConfig.UseGraphPatching())
{
frontEndConfig.ReloadPartialEngineStateWhenPossible = true;
}
// If incremental is turned off, HistoricMetadataCache should also be turned off.
if (!mutableConfig.Cache.Incremental)
{
mutableConfig.Cache.HistoricMetadataCache = false;
}
// If runtime cache miss analysis is enabled, the fingerprint store is required.
if (mutableConfig.Logging.CacheMissAnalysisOption.Mode != CacheMissMode.Disabled)
{
mutableConfig.Logging.StoreFingerprints = true;
}
// When replicating outputs to workers, workers cannot be released early.
if (mutableConfig.Distribution.ReplicateOutputsToWorkers == true)
{
mutableConfig.Distribution.EarlyWorkerRelease = false;
}
if (mutableConfig.Cache.VfsCasRoot.IsValid)
{
// VFS CAS root should be untracked for purposes of sandboxing.
mutableConfig.Sandbox.GlobalUnsafeUntrackedScopes.Add(mutableConfig.Cache.VfsCasRoot);
}
return success;
}