private RuntimeCacheMissAnalyzer( FingerprintStoreExecutionLogTarget logTarget, LoggingContext loggingContext, PipExecutionContext context, FingerprintStore previousFingerprintStore, IReadonlyDirectedGraph graph, IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance, CacheMissDiffFormat cacheMissDiffFormat, bool cacheMissBatch, FingerprintStoreTestHooks testHooks = null) { m_loggingContext = loggingContext; m_logTarget = logTarget; m_context = context; PreviousFingerprintStore = previousFingerprintStore; m_visitor = new NodeVisitor(graph); m_changedPips = new VisitationTracker(graph); m_pipCacheMissesDict = new ConcurrentDictionary <PipId, PipCacheMissInfo>(); m_runnablePipPerformance = runnablePipPerformance; m_cacheMissDiffFormat = cacheMissDiffFormat; m_maxCacheMissCanPerform = cacheMissBatch ? EngineEnvironmentSettings.MaxNumPipsForCacheMissAnalysis.Value * EngineEnvironmentSettings.MaxMessagesPerBatch : EngineEnvironmentSettings.MaxNumPipsForCacheMissAnalysis.Value; m_batchLoggingQueue = cacheMissBatch ? NagleQueue <JProperty> .Create( BatchLogging, maxDegreeOfParallelism : 1, interval : TimeSpan.FromMinutes(1), batchSize : EngineEnvironmentSettings.MaxMessagesPerBatch) : null; m_testHooks = testHooks; m_testHooks?.InitRuntimeCacheMisses(); }
private RuntimeCacheMissAnalyzer( FingerprintStoreExecutionLogTarget logTarget, LoggingContext loggingContext, PipExecutionContext context, FingerprintStore previousFingerprintStore, IReadonlyDirectedGraph graph, IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance, IConfiguration configuration, string downLoadedPreviousFingerprintStoreSavedPath, FingerprintStoreTestHooks testHooks = null) { m_loggingContext = loggingContext; m_logTarget = logTarget; m_context = context; PreviousFingerprintStore = previousFingerprintStore; m_visitor = new NodeVisitor(graph); m_changedPips = new VisitationTracker(graph); m_pipCacheMissesDict = new ConcurrentDictionary <PipId, PipCacheMissInfo>(); m_runnablePipPerformance = runnablePipPerformance; m_batchLoggingQueue = configuration.Logging.CacheMissBatch ? NagleQueue <JProperty> .Create( BatchLogging, maxDegreeOfParallelism : 1, interval : TimeSpan.FromMinutes(5), batchSize : 100) : null; m_testHooks = testHooks; m_testHooks?.InitRuntimeCacheMisses(); m_configuration = configuration; m_downLoadedPreviousFingerprintStoreSavedPath = downLoadedPreviousFingerprintStoreSavedPath; }
public void FingerprintStoreSession( ScheduleRunResult result, Action <FingerprintStoreClass> storeOps, bool cacheLookupStore = false, bool readOnly = true, FingerprintStoreTestHooks testHooks = null) { var storeDirectory = cacheLookupStore ? result.Config.Logging.CacheLookupFingerprintStoreLogDirectory.ToString(Context.PathTable) : result.Config.Layout.FingerprintStoreDirectory.ToString(Context.PathTable); using (var fingerprintStore = Open(storeDirectory, readOnly: readOnly, testHooks: testHooks).Result) { storeOps(fingerprintStore); } }
/// <summary> /// Creates a <see cref="FingerprintStoreExecutionLogTarget"/>. /// </summary> /// <returns> /// If successful, a <see cref="FingerprintStoreExecutionLogTarget"/> that logs to /// a <see cref="Tracing.FingerprintStore"/> at the provided directory; /// otherwise, null. /// </returns> public static FingerprintStoreExecutionLogTarget Create( PipExecutionContext context, PipTable pipTable, PipContentFingerprinter pipContentFingerprinter, string fingerprintStoreDirectory, LoggingContext loggingContext, IConfiguration configuration, EngineCache cache, IReadonlyDirectedGraph graph, IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance = null, FingerprintStoreTestHooks testHooks = null) { var maxEntryAge = new TimeSpan(hours: 0, minutes: configuration.Logging.FingerprintStoreMaxEntryAgeMinutes, seconds: 0); var possibleStore = FingerprintStore.Open( fingerprintStoreDirectory, maxEntryAge: maxEntryAge, mode: configuration.Logging.FingerprintStoreMode, loggingContext: loggingContext, testHooks: testHooks); if (possibleStore.Succeeded) { return(new FingerprintStoreExecutionLogTarget( loggingContext, context, pipTable, pipContentFingerprinter, possibleStore.Result, configuration, cache, graph, runnablePipPerformance)); } else { Logger.Log.FingerprintStoreUnableToOpen(loggingContext, possibleStore.Failure.DescribeIncludingInnerFailures()); } return(null); }
/// <summary> /// Creates a <see cref="FingerprintStoreExecutionLogTarget"/>. /// </summary> /// <returns> /// If successful, a <see cref="FingerprintStoreExecutionLogTarget"/> that logs to /// a <see cref="Tracing.FingerprintStore"/> at the provided directory; /// otherwise, null. /// </returns> public static FingerprintStoreExecutionLogTarget Create( PipExecutionContext context, PipTable pipTable, PipContentFingerprinter pipContentFingerprinter, LoggingContext loggingContext, IConfiguration configuration, EngineCache cache, IReadonlyDirectedGraph graph, CounterCollection <FingerprintStoreCounters> counters, IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance = null, FingerprintStoreTestHooks testHooks = null) { var fingerprintStorePathString = configuration.Layout.FingerprintStoreDirectory.ToString(context.PathTable); var cacheLookupFingerprintStorePathString = configuration.Logging.CacheLookupFingerprintStoreLogDirectory.ToString(context.PathTable); try { FileUtilities.CreateDirectoryWithRetry(fingerprintStorePathString); } catch (BuildXLException ex) { Logger.Log.FingerprintStoreUnableToCreateDirectory(loggingContext, fingerprintStorePathString, ex.Message); throw new BuildXLException("Unable to create fingerprint store directory: ", ex); } var maxEntryAge = new TimeSpan(hours: 0, minutes: configuration.Logging.FingerprintStoreMaxEntryAgeMinutes, seconds: 0); var possibleExecutionStore = FingerprintStore.Open( fingerprintStorePathString, maxEntryAge: maxEntryAge, mode: configuration.Logging.FingerprintStoreMode, loggingContext: loggingContext, counters: counters, testHooks: testHooks); Possible <FingerprintStore> possibleCacheLookupStore = new Failure <string>("No attempt to create a cache lookup fingerprint store yet."); if (configuration.Logging.FingerprintStoreMode != FingerprintStoreMode.ExecutionFingerprintsOnly) { try { FileUtilities.CreateDirectoryWithRetry(cacheLookupFingerprintStorePathString); } catch (BuildXLException ex) { Logger.Log.FingerprintStoreUnableToCreateDirectory(loggingContext, fingerprintStorePathString, ex.Message); throw new BuildXLException("Unable to create fingerprint store directory: ", ex); } possibleCacheLookupStore = FingerprintStore.Open( cacheLookupFingerprintStorePathString, maxEntryAge: maxEntryAge, mode: configuration.Logging.FingerprintStoreMode, loggingContext: loggingContext, counters: counters, testHooks: testHooks); } if (possibleExecutionStore.Succeeded && (possibleCacheLookupStore.Succeeded || configuration.Logging.FingerprintStoreMode == FingerprintStoreMode.ExecutionFingerprintsOnly)) { return(new FingerprintStoreExecutionLogTarget( loggingContext, context, pipTable, pipContentFingerprinter, possibleExecutionStore.Result, possibleCacheLookupStore.Succeeded ? possibleCacheLookupStore.Result : null, configuration, cache, graph, counters, runnablePipPerformance)); } else { if (!possibleExecutionStore.Succeeded) { Logger.Log.FingerprintStoreUnableToOpen(loggingContext, possibleExecutionStore.Failure.DescribeIncludingInnerFailures()); } if (!possibleCacheLookupStore.Succeeded) { Logger.Log.FingerprintStoreUnableToOpen(loggingContext, possibleCacheLookupStore.Failure.DescribeIncludingInnerFailures()); } } return(null); }
/// <summary> /// Encapsulates one "session" with a fingerprint store. /// </summary> /// <param name="storeDirectory"> /// Directory of the fingerprint store. /// </param> /// <param name="storeOps"> /// The store operations to execute. /// </param> public static CounterCollection <FingerprintStoreCounters> FingerprintStoreSession(string storeDirectory, Action <FingerprintStore> storeOps, bool readOnly = true, FingerprintStoreTestHooks testHooks = null) { using (var fingerprintStore = FingerprintStore.Open(storeDirectory, readOnly: readOnly, testHooks: testHooks).Result) { storeOps(fingerprintStore); return(fingerprintStore.Counters); } }
/// <summary> /// Initiates the task to load the fingerprint store that will be used for cache miss analysis /// </summary> public static async Task <RuntimeCacheMissAnalyzer> TryCreateAsync( FingerprintStoreExecutionLogTarget logTarget, LoggingContext loggingContext, PipExecutionContext context, IConfiguration configuration, EngineCache cache, IReadonlyDirectedGraph graph, IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance, FingerprintStoreTestHooks testHooks = null) { using (logTarget.Counters.StartStopwatch(FingerprintStoreCounters.InitializeCacheMissAnalysisDuration)) { var option = configuration.Logging.CacheMissAnalysisOption; if (option.Mode == CacheMissMode.Disabled) { return(null); } Possible <FingerprintStore> possibleStore; if (option.Mode == CacheMissMode.Local) { possibleStore = FingerprintStore.CreateSnapshot(logTarget.ExecutionFingerprintStore, loggingContext); } else { string path = null; if (option.Mode == CacheMissMode.CustomPath) { path = option.CustomPath.ToString(context.PathTable); } else { Contract.Assert(option.Mode == CacheMissMode.Remote); foreach (var key in option.Keys) { var cacheSavePath = configuration.Logging.FingerprintsLogDirectory .Combine(context.PathTable, Scheduler.FingerprintStoreDirectory + "." + key); #pragma warning disable AsyncFixer02 // This should explicitly happen synchronously since it interacts with the PathTable and StringTable var result = cache.TryRetrieveFingerprintStoreAsync(loggingContext, cacheSavePath, context.PathTable, key, configuration.Schedule.EnvironmentFingerprint).Result; #pragma warning restore AsyncFixer02 if (result.Succeeded && result.Result) { path = cacheSavePath.ToString(context.PathTable); break; } } if (string.IsNullOrEmpty(path)) { Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Could not find the fingerprint store for any given key: {string.Join(",", option.Keys)}")); return(null); } } // Unblock caller // WARNING: The rest can simultenously happen with saving the graph files to disk. // We should not create any paths or strings by using PathTable and StringTable. await Task.Yield(); possibleStore = FingerprintStore.Open(path, readOnly: true); } if (possibleStore.Succeeded) { Logger.Log.SuccessLoadFingerprintStoreToCompare(loggingContext, option.Mode.ToString(), possibleStore.Result.StoreDirectory); return(new RuntimeCacheMissAnalyzer( logTarget, loggingContext, context, possibleStore.Result, graph, runnablePipPerformance, configuration.Logging.CacheMissDiffFormat, configuration.Logging.CacheMissBatch, testHooks: testHooks)); } Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Failed to read the fingerprint store to compare. Mode: {option.Mode.ToString()} Failure: {possibleStore.Failure.DescribeIncludingInnerFailures()}")); return(null); } }
/// <summary> /// Initiates the task to load the fingerprint store that will be used for cache miss analysis /// </summary> public static async Task <RuntimeCacheMissAnalyzer> TryCreateAsync( FingerprintStoreExecutionLogTarget logTarget, LoggingContext loggingContext, PipExecutionContext context, IConfiguration configuration, EngineCache cache, IReadonlyDirectedGraph graph, IDictionary <PipId, RunnablePipPerformanceInfo> runnablePipPerformance, FingerprintStoreTestHooks testHooks = null) { // Unblock caller await Task.Yield(); using (logTarget.Counters.StartStopwatch(FingerprintStoreCounters.InitializeCacheMissAnalysisDuration)) { var option = configuration.Logging.CacheMissAnalysisOption; string downLoadedPriviousFingerprintStoreSavedPath = null; if (option.Mode == CacheMissMode.Disabled) { return(null); } Possible <FingerprintStore> possibleStore; PathTable newPathTable = new PathTable(); if (option.Mode == CacheMissMode.Local) { possibleStore = FingerprintStore.CreateSnapshot(logTarget.ExecutionFingerprintStore, loggingContext); } else { string path = null; if (option.Mode == CacheMissMode.CustomPath) { path = option.CustomPath.ToString(context.PathTable); } else { Contract.Assert(option.Mode == CacheMissMode.Remote); foreach (var key in option.Keys) { var fingerprintsLogDirectoryStr = configuration.Logging.FingerprintsLogDirectory.ToString(context.PathTable); var fingerprintsLogDirectory = AbsolutePath.Create(newPathTable, fingerprintsLogDirectoryStr); var cacheSavePath = fingerprintsLogDirectory.Combine(newPathTable, Scheduler.FingerprintStoreDirectory + "." + key); var result = await cache.TryRetrieveFingerprintStoreAsync(loggingContext, cacheSavePath, newPathTable, key, configuration, context.CancellationToken); if (result.Succeeded && result.Result) { path = cacheSavePath.ToString(newPathTable); downLoadedPriviousFingerprintStoreSavedPath = path; break; } } if (string.IsNullOrEmpty(path)) { Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Could not find the fingerprint store for any given key: {string.Join(",", option.Keys)}")); return(null); } } possibleStore = FingerprintStore.Open(path, readOnly: true); } if (possibleStore.Succeeded) { Logger.Log.SuccessLoadFingerprintStoreToCompare(loggingContext, option.Mode.ToString(), possibleStore.Result.StoreDirectory); return(new RuntimeCacheMissAnalyzer( logTarget, loggingContext, context, possibleStore.Result, graph, runnablePipPerformance, configuration, downLoadedPriviousFingerprintStoreSavedPath, testHooks: testHooks)); } Logger.Log.GettingFingerprintStoreTrace(loggingContext, I($"Failed to read the fingerprint store to compare. Mode: {option.Mode.ToString()} Failure: {possibleStore.Failure.DescribeIncludingInnerFailures()}")); return(null); } }