private KeyValuePair <DirectoryArtifact, Node> TryFindSealDirectoryEntryContainingFileArtifact(PipTable pipTable, FileArtifact artifact) { KeyValuePair <DirectoryArtifact, Node> smallestMatchingSeal = default(KeyValuePair <DirectoryArtifact, Node>); int smallestMatchingSealSize = int.MaxValue; int next = GetHeadNodeIndex(artifact); while (next >= 0) { var directoryAndSeal = m_seals.BackingSet[next]; var sealDirectory = (SealDirectory) pipTable.HydratePip( directoryAndSeal.Value.PipId, PipQueryContext.SealedDirectoryTableTryFindDirectoryArtifactContainingFileArtifact); if (sealDirectory.Contents.Contains(artifact)) { if (!smallestMatchingSeal.Key.IsValid || smallestMatchingSealSize > sealDirectory.Contents.Length) { smallestMatchingSealSize = sealDirectory.Contents.Length; smallestMatchingSeal = directoryAndSeal; } } next = directoryAndSeal.Value.Next; } return(smallestMatchingSeal); }
/// <summary> /// Hooks into the log target for pip execution performance data which will be called /// when a pip fails. This will then dump relevant information on the failing pip /// to a JSON file specified under <see cref="m_logPath"/>. /// The maximum number of logs generated can be specified using the /// /DumpFailedPipsLogCount parameter. /// </summary> /// <remarks> /// If an error occurs while serializing/dumping the specified pip, /// then this analyzer will be disabled for the remainder of this build and /// a warning will be logged with more details. /// </remarks> public override void PipExecutionPerformance(PipExecutionPerformanceEventData data) { if (data.ExecutionPerformance.ExecutionLevel == PipExecutionLevel.Failed && !m_loggingErrorOccured) { var currentNumLogFiles = Interlocked.Increment(ref m_numLogFilesGenerated); if (currentNumLogFiles <= m_maxLogFiles) { var pip = m_pipTable.HydratePip(data.PipId, PipQueryContext.DumpPipLiteAnalyzer); ProcessExecutionMonitoringReportedEventData?dynamicData = null; if (m_shouldDumpDynamicData) { m_dynamicDataDictionary.TryRemove(data.PipId, out dynamicData); } DumpPip(pip, dynamicData, currentNumLogFiles); } } else { // If m_loggingErrorOccured is set to true, then no data is being added to the dictionary anyway, so there is no need to remove if (!m_loggingErrorOccured && m_shouldDumpDynamicData) { // The pip is not in a failed state, so it does not need to be dumped. m_dynamicDataDictionary.TryRemove(data.PipId, out _); } } }
public DumpPipLiteAnalyzer(AnalysisInput input, string outputDirectory, long semiStableHash, bool dumpObservedFileAccesses) : base(input) { if (string.IsNullOrEmpty(outputDirectory)) { // Use the execution log path m_logPath = Path.Combine(Path.GetDirectoryName(input.ExecutionLogPath), "FailedPips"); } else { m_logPath = Path.Combine(outputDirectory, "FailedPips"); } m_pipTable = input.CachedGraph.PipTable; m_pipGraph = input.CachedGraph.PipGraph; m_dumpObservedFileAccesses = dumpObservedFileAccesses; m_dynamicData = null; foreach (var pipId in m_pipTable.StableKeys) { var possibleMatch = m_pipTable.GetPipSemiStableHash(pipId); if (possibleMatch == semiStableHash) { m_pip = m_pipTable.HydratePip(pipId, PipQueryContext.DumpPipLiteAnalyzer); break; } } if (m_pip == null) { // If no matches were found, then we likely got some bad input from the user. throw new InvalidArgumentException($"Specified Pip 'Pip{semiStableHash:X}' does not exist."); } }
private IEnumerable <Pip> HydratePipsByType(PipTable pipTable, IEnumerable <PipType> relevantTypes) { return(pipTable .Keys .Where(pipId => relevantTypes.Any(pipType => pipType == pipTable.GetPipType(pipId))) .Select(pipId => pipTable.HydratePip(pipId, PipQueryContext.Test)) .ToList()); }
/// <summary> /// Gets the process pip by semistable hash /// </summary> /// <param name="semistableHash"></param> /// <returns></returns> public Process GetProcessPip(long semistableHash) { if (m_semiStableHashProcessPips.ContainsKey(semistableHash)) { var pipId = m_semiStableHashProcessPips[semistableHash]; return((Process)m_pipTable.HydratePip(pipId, PipQueryContext.ViewerAnalyzer)); } return(null); }
public XElement CreateRow(string key, IEnumerable <PipId> values) { var allPips = values .Select(pipId => m_pipTable.HydratePip(pipId, PipQueryContext.ViewerAnalyzer)) .Select( pip => new { PipType = pip.PipType.ToString(), Hash = Pip.FormatSemiStableHash(pip.Provenance?.SemiStableHash ?? 0), FullName = pip.Provenance?.OutputValueSymbol.ToString(m_symbolTable), Spec = pip.Provenance?.Token.Path.ToString(m_pathTable), Details = GetPipDetails(pip), }) .OrderBy(obj => obj.PipType) .ThenBy(obj => obj.FullName) .Select(obj => string.Format("[{0}] <{1}> {2} - {3} {4}", obj.Hash, obj.PipType, obj.FullName, obj.Spec, obj.Details)); return(CreateRow(key, allPips)); }
/// <summary> /// Hooks into the log target for pip execution performance data which will be called /// when a pip fails. This will then dump relevant information on the failing pip /// to a JSON file specified under <see cref="m_logPath"/>. /// The maximum number of logs generated can be specified using the /// /DumpFailedPipsLogCount parameter. /// </summary> /// <remarks> /// If an error occurs while serializing/dumping the specified pip, /// then this analyzer will be disabled for the remainder of this build and /// a warning will be logged with more details. /// </remarks> public override void PipExecutionPerformance(PipExecutionPerformanceEventData data) { if (data.ExecutionPerformance.ExecutionLevel == PipExecutionLevel.Failed && !m_loggingErrorOccured) { var currentNumLogFiles = Interlocked.Increment(ref m_numLogFilesGenerated); if (currentNumLogFiles <= m_maxLogFiles) { var dumpPipResult = false; if (!m_logPathCreated) { // A log entry should have been generated already if this fails m_logPathCreated = DumpPipLiteAnalysisUtilities.CreateLoggingDirectory(m_logPath.ToString(m_pipExecutionContext.PathTable), m_loggingContext); } if (m_logPathCreated) { var pip = m_pipTable.HydratePip(data.PipId, PipQueryContext.DumpPipLiteAnalyzer); // A log entry should have been generated already if this fails dumpPipResult = DumpPipLiteAnalysisUtilities.DumpPip(pip, m_logPath.ToString(m_pipExecutionContext.PathTable), m_pipExecutionContext.PathTable, m_pipExecutionContext.StringTable, m_pipExecutionContext.SymbolTable, m_pipGraph); } if (!(m_logPathCreated && dumpPipResult)) { // This failure was already logged in DumpPipLiteAnalysisUtilies m_loggingErrorOccured = true; } if (currentNumLogFiles >= m_maxLogFiles) { // Log limit reached, log this once Logger.Log.RuntimeDumpPipLiteLogLimitReached(m_loggingContext, m_maxLogFiles); } } } }
/// <inheritdoc /> public override int Analyze() { PipBasicInfoList.Clear(); m_moduleIdToFriendlyName.Clear(); foreach (var pipId in m_pipTable.Keys) { var pipType = m_pipTable.GetPipType(pipId); if (pipType == PipType.Process || pipType == PipType.CopyFile) { var pipBasicInfo = new PipBasicInfo(); pipBasicInfo.pipId = pipId.Value.ToString("X16", CultureInfo.InvariantCulture).TrimStart(new[] { '0' }); pipBasicInfo.semiStableHash = m_pipTable.GetPipSemiStableHash(pipId).ToString("X"); pipBasicInfo.pipType = pipType.ToString(); var pip = m_pipTable.HydratePip(pipId, PipQueryContext.ViewerAnalyzer); pipBasicInfo.shortDescription = pip.GetShortDescription(Input.CachedGraph.PipGraph.Context); PipBasicInfoList.Add(pipBasicInfo); } } return(0); }
/// <summary> /// Generates the PipMetadata for a given Pip /// </summary> public PipMetadata GeneratePipMetadata(Pip pip) { PipMetadata pipMetadata = new PipMetadata { PipId = pip.PipId.Value, SemiStableHash = pip.FormattedSemiStableHash, PipType = pip.PipType, Tags = pip.Tags.IsValid ? pip.Tags.Select(tag => tag.ToString(StringTable)).ToList() : null }; pipMetadata.Tags = pipMetadata.Tags.Any() ? pipMetadata.Tags : null; PipProvenance provenance = pip.Provenance; pipMetadata.Qualifier = PipGraph.Context.QualifierTable.GetCanonicalDisplayString(provenance.QualifierId); pipMetadata.Usage = provenance.Usage.IsValid ? provenance.Usage.ToString(PathTable) : null; pipMetadata.SpecFilePath = provenance.Token.Path.ToString(PathTable); pipMetadata.OutputValueSymbol = provenance.OutputValueSymbol.ToString(SymbolTable); pipMetadata.ModuleId = provenance.ModuleId.Value; pipMetadata.SpecFilePath = provenance.Token.Path.ToString(PathTable); pipMetadata.PipDependencies = PipGraph.RetrievePipReferenceImmediateDependencies(pip.PipId, null) .Where(pipRef => pipRef.PipType != PipType.HashSourceFile) .Select(pipRef => pipRef.PipId) .Select(pipId => PipTable.HydratePip(pipId, PipQueryContext.ViewerAnalyzer)) .Select(pipHash => pipHash.FormattedSemiStableHash) .ToList(); pipMetadata.PipDependents = PipGraph.RetrievePipReferenceImmediateDependents(pip.PipId, null) .Select(pipRef => pipRef.PipId) .Select(pipId => PipTable.HydratePip(pipId, PipQueryContext.ViewerAnalyzer)) .Select(pipData => pipData.FormattedSemiStableHash) .ToList(); pipMetadata.PipDependencies = pipMetadata.PipDependencies.Any() ? pipMetadata.PipDependencies : null; pipMetadata.PipDependents = pipMetadata.PipDependents.Any() ? pipMetadata.PipDependents : null; return(pipMetadata); }
/// <summary> /// Dumps all failing pips is the /dumpAllFailedPips flag is set. /// </summary> /// <param name="data"></param> public override void PipExecutionPerformance(PipExecutionPerformanceEventData data) { if (m_dumpAllFailedPips && data.ExecutionPerformance.ExecutionLevel == PipExecutionLevel.Failed) { if (!m_isLogDirectoryCreated) { m_isLogDirectoryCreated = DumpPipLiteAnalysisUtilities.CreateLoggingDirectory(m_logPath, LoggingContext); } if (m_isLogDirectoryCreated) { var pip = m_pipTable.HydratePip(data.PipId, PipQueryContext.DumpPipLiteAnalyzer); // A log entry should have been generated already if this fails DumpPipLiteAnalysisUtilities.DumpPip(pip, m_logPath, PathTable, StringTable, SymbolTable, m_pipGraph); } } }
private IEnumerable <Pip> HydrateAllPips(PipTable pipTable) { return(pipTable.Keys.Select(pipId => pipTable.HydratePip(pipId, PipQueryContext.Test)).ToList()); }
private Process HydratePip(PipId pipId) { return((Process)PipTable.HydratePip(pipId, PipQueryContext.ViewerAnalyzer)); }