private GraphReuseResult ReloadEngineSchedule( EngineSerializer serializer, CacheInitializationTask cacheInitializationTask, JournalState journalState, LoggingContext loggingContext, EngineState engineState, InputTracker.InputChanges inputChanges, string buildEngineFingerprint) { Tuple <EngineSchedule, EngineContext, IConfiguration> t = null; try { t = EngineSchedule.LoadAsync( Context, serializer, cacheInitializationTask, FileContentTable, journalState, Configuration, loggingContext, m_collector, m_directoryTranslator, engineState, tempCleaner: m_tempCleaner, buildEngineFingerprint).GetAwaiter().GetResult(); } catch (BuildXLException e) { Logger.Log.FailedReloadPipGraph(loggingContext, e.ToString()); } if (t == null) { return(GraphReuseResult.CreateForNoReuse(inputChanges)); } // Invalidate the old context to ensure nothing uses it anymore // Update engine state to deserialized state Context.Invalidate(); Context = t.Item2; // Update configuration state to deserialized state Configuration = t.Item3; // Copy the graph files to the session output if (Configuration.Distribution.BuildRole != DistributedBuildRoles.Worker) { // No need to link these files to the logs directory on workers since they are redundant with what's on the orchestrator m_executionLogGraphCopy = TryCreateHardlinksToScheduleFilesInSessionFolder(loggingContext, serializer); m_previousInputFilesCopy = TryCreateHardlinksToPreviousInputFilesInSessionFolder(loggingContext, serializer); } return(GraphReuseResult.CreateForFullReuse(t.Item1, inputChanges)); }
private GraphReuseResult ReloadPipGraphOnly( EngineSerializer serializer, LoggingContext loggingContext, EngineState engineState, InputTracker.InputChanges inputChanges) { Tuple <PipGraph, EngineContext> t = null; try { t = EngineSchedule.LoadPipGraphAsync( Context, serializer, Configuration, loggingContext, engineState).GetAwaiter().GetResult(); } catch (BuildXLException e) { Logger.Log.FailedReloadPipGraph(loggingContext, e.ToString()); } if (t == null) { return(GraphReuseResult.CreateForNoReuse(inputChanges)); } var newContext = t.Item2; if (!ShouldReuseReloadedEngineContextGivenHistoricData(loggingContext, newContext.NextHistoricTableSizes)) { return(GraphReuseResult.CreateForNoReuse(inputChanges)); } var newPathTable = newContext.PathTable; var pathRemapper = new PathRemapper(Context.PathTable, newPathTable); Configuration = new ConfigurationImpl(Configuration, pathRemapper); m_initialCommandLineConfiguration = new CommandLineConfiguration(m_initialCommandLineConfiguration, pathRemapper); // Invalidate the old context to ensure nothing uses it anymore // Update engine state to deserialized state Context.Invalidate(); Context = newContext; // Additionally recreate front end controller, because the old one uses the invalidated context. // - to fully initialize the front end, we have to go through all the steps that have already been // executed on the old controller; those steps are (1) InitializeHost, and (2) ParseConfig FrontEndController = m_frontEndControllerFactory.Create(Context.PathTable, Context.SymbolTable); FrontEndController.InitializeHost(Context.ToFrontEndContext(loggingContext), m_initialCommandLineConfiguration); FrontEndController.ParseConfig(m_initialCommandLineConfiguration); return(GraphReuseResult.CreateForPartialReuse(t.Item1, inputChanges)); }
private GraphReuseResult ReloadEngineSchedule( EngineSerializer serializer, CacheInitializationTask cacheInitializationTask, JournalState journalState, LoggingContext loggingContext, EngineState engineState, InputTracker.InputChanges inputChanges, string buildEngineFingerprint) { Tuple <EngineSchedule, EngineContext, IConfiguration> t = EngineSchedule.LoadAsync( Context, serializer, cacheInitializationTask, FileContentTable, journalState, Configuration, loggingContext, m_collector, m_directoryTranslator, engineState, symlinkDefinitionFile: IsDistributedWorker ? m_workerSymlinkDefinitionFile.Value : Configuration.Layout.SymlinkDefinitionFile, tempCleaner: m_tempCleaner, buildEngineFingerprint).GetAwaiter().GetResult(); if (t == null) { return(GraphReuseResult.CreateForNoReuse(inputChanges)); } // Invalidate the old context to ensure nothing uses it anymore // Update engine state to deserialized state Context.Invalidate(); Context = t.Item2; // Update configuration state to deserialized state Configuration = t.Item3; // Copy the graph files to the session output m_executionLogGraphCopy = TryCreateHardlinksToScheduleFilesInSessionFolder(loggingContext, serializer); m_previousInputFilesCopy = TryCreateHardlinksToPreviousInputFilesInSessionFolder(loggingContext, serializer); return(GraphReuseResult.CreateForFullReuse(t.Item1, inputChanges)); }
/// <summary> /// Attempt to reuse the pip graph from a previous run /// </summary> private GraphReuseResult AttemptToReuseGraph( LoggingContext outerLoggingContext, int maxDegreeOfParallelism, GraphFingerprint graphFingerprint, IReadOnlyDictionary <string, string> properties, CacheInitializationTask cacheInitializationTask, JournalState journalState, EngineState engineState) { Contract.Ensures(Contract.Result <GraphReuseResult>() != null); GraphCacheCheckStatistics cacheGraphStats = CheckGraphCacheReuse( outerLoggingContext, maxDegreeOfParallelism, graphFingerprint, properties, cacheInitializationTask, journalState, out var serializer, out var inputChanges); // There are 3 cases in which we should reload the graph // - we have a graph cache hit // - the build is configured to reload the graph no matter what // - graph patching is enabled and the reason for cache miss was 'SpecFileChanges' var shouldReload = cacheGraphStats.WasHit || Configuration.Cache.CachedGraphPathToLoad.IsValid || PartialReloadCondition(Configuration.FrontEnd, cacheGraphStats); if (!shouldReload) { return(GraphReuseResult.CreateForNoReuse(inputChanges)); } bool fullReload = !PartialReloadCondition(Configuration.FrontEnd, cacheGraphStats); // Now we actually reload the graph var reloadStats = default(GraphCacheReloadStatistics); using (var tb = TimedBlock <EmptyStruct, GraphCacheReloadStatistics> .Start( outerLoggingContext, Statistics.GraphCacheReload, (context, emptyStruct) => { if (fullReload) { Logger.Log.ReloadingPipGraphStart(context); } else { Logger.Log.PartiallyReloadingEngineState(context); } }, default(EmptyStruct), (context, graphCacheCheckStatistics) => { Logger.Log.PartiallyReloadingEngineStateComplete(context, graphCacheCheckStatistics); m_enginePerformanceInfo.GraphReloadDurationMs = graphCacheCheckStatistics.ElapsedMilliseconds; }, () => reloadStats)) { var reuseResult = fullReload ? ReloadEngineSchedule( serializer, cacheInitializationTask, journalState, tb.LoggingContext, engineState, inputChanges, graphFingerprint?.ExactFingerprint.BuildEngineHash.ToString()) : ReloadPipGraphOnly(serializer, tb.LoggingContext, engineState, inputChanges); // Set telemetry statistics reloadStats.SerializedFileSizeBytes = serializer.BytesDeserialized; reloadStats.Success = !reuseResult.IsNoReuse; return(reuseResult); } }