/// <summary> /// Generates the PipInfo for a given pip, and then serializes it /// </summary> /// <param name="pipReference">PipReference to hydrate into a complete Pip</param> /// <param name="writer">Writer to write data to</param> /// <param name="serializer">Serializer to serialize with</param> public void GenerateAndSerializePipInfo(PipReference pipReference, JsonWriter writer, JsonSerializer serializer) { Pip pip = pipReference.HydratePip(); // All PipInfos will have metadata PipInfo generatedPipInfo = new PipInfo { PipMetadata = GeneratePipMetadata(pip) }; if (Filters.OnlyMetadata) { serializer.Serialize(writer, generatedPipInfo); return; } // Fill the data depending on the type of Pip switch (pip.PipType) { case PipType.CopyFile: generatedPipInfo.CopyFilePipDetails = GenerateCopyFilePipDetails((CopyFile)pip); break; case PipType.Process: generatedPipInfo.ProcessPipDetails = GenerateProcessPipDetails((Process)pip); break; case PipType.Ipc: generatedPipInfo.IpcPipDetails = GenerateIpcPipDetails((IpcPip)pip); break; case PipType.Value: generatedPipInfo.ValuePipDetails = GenerateValuePipDetails((ValuePip)pip); break; case PipType.SpecFile: generatedPipInfo.SpecFilePipDetails = GenerateSpecFilePipDetails((SpecFilePip)pip); break; case PipType.Module: generatedPipInfo.ModulePipDetails = GenerateModulePipDetails((ModulePip)pip); break; case PipType.HashSourceFile: generatedPipInfo.HashSourceFilePipDetails = GenerateHashSourceFilePipDetails((HashSourceFile)pip); break; case PipType.SealDirectory: generatedPipInfo.SealDirectoryPipDetails = GenerateSealDirectoryPipDetails((SealDirectory)pip); break; case PipType.WriteFile: generatedPipInfo.WriteFilePipDetails = GenerateWriteFilePipDetails((WriteFile)pip); break; default: throw new ArgumentOutOfRangeException(); } serializer.Serialize(writer, generatedPipInfo); }
private async Task HandlePipStepAsync(SinglePipBuildRequest pipBuildRequest, Possible <Unit> reportInputsResult) { // Do not block the caller. await Task.Yield(); var pipId = new PipId(pipBuildRequest.PipIdValue); var pip = m_pipTable.HydratePip(pipId, PipQueryContext.LoggingPipFailedOnWorker); var pipType = pip.PipType; var step = (PipExecutionStep)pipBuildRequest.Step; if (!(pipType == PipType.Process || pipType == PipType.Ipc || step == PipExecutionStep.MaterializeOutputs)) { throw Contract.AssertFailure(I($"Workers can only execute process or IPC pips for steps other than MaterializeOutputs: Step={step}, PipId={pipId}, Pip={pip.GetDescription(m_environment.Context)}")); } m_pendingBuildRequests[pipId] = pipBuildRequest; var pipCompletionData = new ExtendedPipCompletionData(new PipCompletionData() { PipIdValue = pipId.Value, Step = (int)step }) { SemiStableHash = m_pipTable.GetPipSemiStableHash(pipId) }; m_pendingPipCompletions[pipId] = pipCompletionData; using (var operationContext = m_operationTracker.StartOperation(PipExecutorCounter.WorkerServiceHandlePipStepDuration, pipId, pipType, m_appLoggingContext)) using (operationContext.StartOperation(step)) { var pipInfo = new PipInfo(pip, m_environment.Context); if (!reportInputsResult.Succeeded) { // Could not report inputs due to input mismatch. Fail the pip BuildXL.Scheduler.Tracing.Logger.Log.PipMaterializeDependenciesFailureUnrelatedToCache( m_appLoggingContext, pipInfo.Description, ArtifactMaterializationResult.VerifySourceFilesFailed.ToString(), reportInputsResult.Failure.DescribeIncludingInnerFailures()); ReportResult( operationContext, pip, ExecutionResult.GetFailureNotRunResult(m_appLoggingContext), step); return; } if (step == PipExecutionStep.CacheLookup) { // Directory dependencies need to be registered for cache lookup. // For process execution, the input materialization guarantees the registration. m_environment.State.FileContentManager.RegisterDirectoryDependencies(pipInfo.UnderlyingPip); } m_workerPipStateManager.Transition(pipId, WorkerPipState.Queued); m_scheduler.HandlePipRequest(pipId, m_workerRunnablePipObserver, step, pipBuildRequest.Priority); // Track how much time the request spent queued using (var op = operationContext.StartOperation(PipExecutorCounter.WorkerServiceQueuedPipStepDuration)) { await pipCompletionData.StepExecutionStarted.Task; pipCompletionData.SerializedData.QueueTicks = op.Duration.Value.Ticks; } ExecutionResult executionResult; // Track how much time the request spent executing using (operationContext.StartOperation(PipExecutorCounter.WorkerServiceExecutePipStepDuration)) { executionResult = await pipCompletionData.StepExecutionCompleted.Task; } ReportResult( operationContext, pip, executionResult, step); } }
private string GetRunningPipsMessage(string standardStatus, string perfInfo) { lock (m_runningPipsLock) { // First, bail out if the visualizer data isn't available if (EngineModel.VisualizationInformation == null || EngineModel.VisualizationInformation.Scheduler.State != Engine.Visualization.VisualizationValueState.Available || EngineModel.VisualizationInformation.Context.State != Engine.Visualization.VisualizationValueState.Available || EngineModel.VisualizationInformation.PipGraph.State != Engine.Visualization.VisualizationValueState.Available) { return(null); } var context = EngineModel.VisualizationInformation.Context.Value; var stringTable = context.StringTable; var pathTable = context.PathTable; var symbolTable = context.SymbolTable; if (m_runningPips == null) { m_runningPips = new Dictionary <PipId, PipInfo>(); } DateTime thisCollection = DateTime.UtcNow; // Use the viewer's interface to fetch the info about which pips are currently running. foreach (var pip in EngineModel.VisualizationInformation.Scheduler.Value.RetrieveExecutingProcessPips()) { PipInfo runningInfo; if (!m_runningPips.TryGetValue(pip.PipId, out runningInfo)) { // This is a new pip that wasn't running the last time the currently running pips were queried Pip p = pip.HydratePip(); runningInfo = new PipInfo() { PipDescription = p.GetShortDescription(context), FirstSeen = DateTime.UtcNow, }; m_runningPips.Add(pip.PipId, runningInfo); } runningInfo.LastSeen = DateTime.UtcNow; } // Build up a string based on the snapshot of what pips are being running using (var pooledWrapper = Pools.StringBuilderPool.GetInstance()) { StringBuilder sb = pooledWrapper.Instance; sb.Append(TimeSpanToString(TimeDisplay.Seconds, DateTime.UtcNow - BaseTime)); sb.Append(' '); sb.Append(standardStatus); if (!string.IsNullOrWhiteSpace(perfInfo)) { sb.Append(". " + perfInfo); } // Display the log file location if there have been errors logged. This allows the user to open the // log files while the build is running to see errors that have scrolled off the console var errors = Interlocked.Read(ref m_errorsLogged); if (errors > 0 && m_logsDirectory != null) { sb.AppendLine(); sb.AppendFormat(Strings.App_Errors_LogsDirectory, errors, m_logsDirectory); } int pipCount = 0; foreach (var item in m_runningPips.ToArray().OrderBy(kvp => kvp.Value.FirstSeen)) { if (item.Value.LastSeen < thisCollection) { // If the pip was last seen before this collection it is no longer running and should be removed m_runningPips.Remove(item.Key); } else { pipCount++; if (pipCount <= m_maxStatusPips) { // Otherwise include it in the string string info = string.Format(CultureInfo.InvariantCulture, " {0} {1}", TimeSpanToString(TimeDisplay.Seconds, item.Value.LastSeen - item.Value.FirstSeen), item.Value.PipDescription); // Don't have a trailing newline for the last message; if (sb.Length > 0) { sb.AppendLine(); } sb.Append(info); } } } if (pipCount > m_maxStatusPips) { sb.AppendLine(); sb.AppendFormat(Strings.ConsoleListener_AdditionalPips, pipCount - m_maxStatusPips); } return(sb.ToString()); } } }