예제 #1
0
 private bool TryGetFingerprintStoreEntry(Process process, out FingerprintStoreEntry entry)
 {
     using (Counters.StartStopwatch(FingerprintStoreCounters.CacheMissFindOldEntriesTime))
     {
         process.TryComputePipUniqueOutputHash(m_context.PathTable, out var pipUniqueOutputHash, m_logTarget.PipContentFingerprinter.PathExpander);
         return(PreviousFingerprintStore.TryGetFingerprintStoreEntry(pipUniqueOutputHash.ToString(), process.FormattedSemiStableHash, out entry));
     }
 }
예제 #2
0
        private void Analyze(FingerprintStoreEntry newEntry, Process pip, bool fromCacheLookup)
        {
            using (var watch = new CacheMissTimer(pip.PipId, this))
            {
                if (!IsCacheMissEligible(pip.PipId))
                {
                    return;
                }

                TryGetFingerprintStoreEntry(pip, out FingerprintStoreEntry oldEntry);
                PerformCacheMissAnalysis(pip, oldEntry, newEntry, fromCacheLookup);
            }
        }
예제 #3
0
        private void PerformCacheMissAnalysis(Process pip, FingerprintStoreEntry oldEntry, FingerprintStoreEntry newEntry, bool fromCacheLookup)
        {
            string pipDescription = pip.GetDescription(m_context);

            try
            {
                if (!m_pipCacheMissesDict.TryRemove(pip.PipId, out var missInfo))
                {
                    return;
                }

                MarkPipAsChanged(pip.PipId);

                if (Interlocked.Increment(ref m_numCacheMissPerformed) >= s_maxCacheMissCanPerform)
                {
                    return;
                }

                if (fromCacheLookup)
                {
                    Counters.IncrementCounter(FingerprintStoreCounters.CacheMissAnalysisAnalyzeCacheLookUpCount);
                }
                else
                {
                    Counters.IncrementCounter(FingerprintStoreCounters.CacheMissAnalysisAnalyzeExecutionCount);
                }

                using (var pool = Pools.StringBuilderPool.GetInstance())
                    using (var writer = new StringWriter(pool.Instance))
                        using (Counters.StartStopwatch(FingerprintStoreCounters.CacheMissAnalysisAnalyzeDuration))
                        {
                            CacheMissAnalysisUtilities.AnalyzeCacheMiss(
                                writer,
                                missInfo,
                                () => new FingerprintStoreReader.PipRecordingSession(PreviousFingerprintStore, oldEntry),
                                () => new FingerprintStoreReader.PipRecordingSession(m_logTarget.ExecutionFingerprintStore, newEntry),
                                m_cacheMissDiffFormat);

                            // The diff sometimes contains several empty new lines at the end.
                            var reason = writer.ToString().TrimEnd(Environment.NewLine.ToCharArray());

                            pipDescription = pip.GetDescription(m_context);
                            Logger.Log.CacheMissAnalysis(m_loggingContext, pipDescription, reason, fromCacheLookup);
                        }
            }
            catch (Exception ex)
            {
                // Cache miss analysis shouldn't fail the build
                Logger.Log.CacheMissAnalysisException(m_loggingContext, pipDescription, ex.ToString(), oldEntry?.PipToFingerprintKeys.ToString(), newEntry?.PipToFingerprintKeys.ToString());
            }
        }
예제 #4
0
            /// <summary>
            /// Constructor
            /// </summary>
            public PipRecordingSession(FingerprintStore store, FingerprintStoreEntry entry, TextWriter textWriter = null)
            {
                m_store = store;
                m_entry = entry;

                PipWriter = textWriter;

                if (EntryExists && textWriter != null)
                {
                    // Write all pip fingerprint information to a file, except for directory memberships.
                    // Directory memberships are skipped unless there is a strong fingerprint miss
                    // to avoid parsing the strong fingerprint entry.
                    m_entry.Print(PipWriter);
                }
            }
예제 #5
0
        internal void AnalyzeForExecution(FingerprintStoreEntry newEntry, Process pip)
        {
            using (var watch = new CacheMissTimer(pip.PipId, this))
            {
                if (!IsCacheMissEligible(pip.PipId))
                {
                    return;
                }

                if (!TryGetFingerprintStoreEntry(pip, out FingerprintStoreEntry oldEntry))
                {
                    return;
                }

                PerformCacheMissAnalysis(pip, oldEntry, newEntry, false);
            }
        }
예제 #6
0
        public void EnsureCacheLookupStoreIsFirst()
        {
            // Read only mount
            var sealDir = CreateUniqueDirectory(ReadonlyRoot);
            // Set up absent file under source seal directory
            var absentFile = CreateSourceFile(sealDir);

            File.Delete(ArtifactToString(absentFile));
            var absentFileDir = CreateAndScheduleSealDirectoryArtifact(sealDir, SealDirectoryKind.SourceAllDirectories);

            // Create a pip that will have a strong fingerprint miss if absentFile is created
            var ops = new Operation[]
            {
                Operation.Probe(absentFile, doNotInfer: true),
                Operation.WriteFile(CreateOutputFileArtifact())
            };

            var builder = CreatePipBuilder(ops);

            builder.AddInputDirectory(absentFileDir);

            var pipA = SchedulePipBuilder(builder).Process;

            var srcB = CreateSourceFile();
            var pipB = CreateAndSchedulePipBuilder(new Operation[]
            {
                Operation.ReadFile(srcB),
                Operation.WriteFile(CreateOutputFileArtifact())
            }).Process;

            var build1 = RunScheduler().AssertCacheMiss(pipA.PipId);

            // Create /absentFile
            File.WriteAllText(ArtifactToString(absentFile), "asdf");
            var build2 = RunScheduler().AssertCacheMiss(pipA.PipId);

            var correctOut1 = RunAnalyzer(build1, build2).AssertPipMiss(
                pipA,
                PipCacheMissType.MissForDescriptorsDueToStrongFingerprints,
                ArtifactToPrint(absentFile),
                ObservedInputConstants.AbsentPathProbe,
                ObservedInputConstants.FileContentRead).FileOutput;

            FingerprintStoreEntry pipAEntry = default;

            FingerprintStoreSession(ResultToStoreDirectory(build2), store =>
            {
                // Remove pipA's entry from the execution-time fingerprintStore, and replace it with a dummy entry (pipB's) that will diff incorrectly if used
                store.TryGetFingerprintStoreEntryBySemiStableHash(pipA.FormattedSemiStableHash, out pipAEntry);
                store.RemoveFingerprintStoreEntryForTesting(pipAEntry);

                store.TryGetFingerprintStoreEntryBySemiStableHash(pipB.FormattedSemiStableHash, out var pipBEntry);
                // Route's pipA's key to point to the same fingerprint info as pipB's
                // If this store is used now to analyze pipA, the analysis will be incorrect
                pipBEntry.PipToFingerprintKeys = new System.Collections.Generic.KeyValuePair <string, PipFingerprintKeys>(pipA.FormattedSemiStableHash, pipBEntry.PipToFingerprintKeys.Value);
                store.PutFingerprintStoreEntry(pipBEntry);
            },
                                    readOnly: false);

            // Make sure the diff is still correct, which implies the cache lookup fingerprint store is still being used
            var correctOut2 = RunAnalyzer(build1, build2).AssertPipMiss(
                pipA,
                PipCacheMissType.MissForDescriptorsDueToStrongFingerprints,
                ArtifactToPrint(absentFile),
                ObservedInputConstants.AbsentPathProbe,
                ObservedInputConstants.FileContentRead).FileOutput;

            XAssert.AreEqual(correctOut1, correctOut2);

            // Remove pipA's entry from the cache lookup store
            FingerprintStoreSession(ResultToStoreDirectory(build2, cacheLookupStore: true), store =>
            {
                store.RemoveFingerprintStoreEntryForTesting(pipAEntry);
            },
                                    readOnly: false);

            // Ensure that the analyzer falls-back on the execution-time store when the cache-lookup store is missing entries
            // srcB from pipB's dependencies will show up in the analysis because of earlier manipulation of the execution-time store
            var incorrectOut = RunAnalyzer(build1, build2).AssertAnalyzerPipMiss(
                pipA,
                PipCacheMissType.MissForDescriptorsDueToStrongFingerprints,
                ArtifactToPrint(srcB)).FileOutput;

            XAssert.AreNotEqual(correctOut2, incorrectOut);
        }
예제 #7
0
 internal void AnalyzeForExecution(FingerprintStoreEntry newEntry, Process pip)
 {
     Analyze(newEntry, pip, fromCacheLookup: false);
 }
예제 #8
0
 internal void AnalyzeForCacheLookup(FingerprintStoreEntry newEntry, Process pip)
 {
     Analyze(newEntry, pip, fromCacheLookup: true);
 }
예제 #9
0
        private void PerformCacheMissAnalysis(Process pip, FingerprintStoreEntry oldEntry, FingerprintStoreEntry newEntry, bool fromCacheLookup)
        {
            Contract.Requires(pip != null);
            string pipDescription = pip.GetDescription(m_context);

            try
            {
                if (!m_pipCacheMissesDict.TryRemove(pip.PipId, out var missInfo))
                {
                    return;
                }

                MarkPipAsChanged(pip.PipId);

                if (fromCacheLookup)
                {
                    Counters.IncrementCounter(FingerprintStoreCounters.CacheMissAnalysisAnalyzeCacheLookUpCount);
                }
                else
                {
                    Counters.IncrementCounter(FingerprintStoreCounters.CacheMissAnalysisAnalyzeExecutionCount);
                }

                using (var pool = Pools.StringBuilderPool.GetInstance())
                    using (Counters.StartStopwatch(FingerprintStoreCounters.CacheMissAnalysisAnalyzeDuration))
                    {
                        var resultAndDetail = CacheMissAnalysisUtilities.AnalyzeCacheMiss(
                            missInfo,
                            () => new FingerprintStoreReader.PipRecordingSession(PreviousFingerprintStore, oldEntry),
                            () => new FingerprintStoreReader.PipRecordingSession(m_logTarget.ExecutionFingerprintStore, newEntry),
                            m_cacheMissDiffFormat);

                        pipDescription = pip.GetDescription(m_context);

                        if (m_batchLoggingQueue != null)
                        {
                            m_batchLoggingQueue.Enqueue(resultAndDetail.Detail.ToJObjectWithPipInfo(pip.FormattedSemiStableHash, pipDescription, fromCacheLookup));
                        }
                        else
                        {
                            var detail = new JObject(
                                new JProperty(nameof(resultAndDetail.Detail.ActualMissType), resultAndDetail.Detail.ActualMissType),
                                new JProperty(nameof(resultAndDetail.Detail.ReasonFromAnalysis), resultAndDetail.Detail.ReasonFromAnalysis),
                                new JProperty(nameof(resultAndDetail.Detail.Info), resultAndDetail.Detail.Info)).ToString();
                            Logger.Log.CacheMissAnalysis(m_loggingContext, pipDescription, detail, fromCacheLookup);
                        }

                        m_testHooks?.AddCacheMiss(
                            pip.PipId,
                            new FingerprintStoreTestHooks.CacheMissData
                        {
                            DetailAndResult   = resultAndDetail,
                            IsFromCacheLookUp = fromCacheLookup
                        });
                    }
            }
            catch (Exception ex)
            {
                // Cache miss analysis shouldn't fail the build
                Logger.Log.CacheMissAnalysisException(m_loggingContext, pipDescription, ex.ToString(), oldEntry?.PipToFingerprintKeys.ToString(), newEntry?.PipToFingerprintKeys.ToString());
            }
        }