/// <inheritdoc/> public override T?GetAdaptedValue(PipelineDiagnostics source, Envelope envelope) { var receiver = source?.GetAllReceiverDiagnostics()?.FirstOrDefault(rd => rd.Id == this.receiverId); if (receiver == null) { return(null); } else { return(this.memberFunc(receiver)); } }
/// <summary> /// Update diagnostics graph. /// </summary> /// <param name="graph">Current diagnostics graph.</param> /// <param name="forceRelayout">Force re-layout of graph (otherwise, updates labels, colors, etc. in place).</param> public void UpdateGraph(PipelineDiagnostics graph, bool forceRelayout) { this.model.Graph = graph; if (graph == null) { this.VisualGraph = null; } else { var pipelineIdToPipelineDiagnostics = graph.GetAllPipelineDiagnostics().ToDictionary(p => p.Id); var currentGraph = this.Breadcrumbs.Count() > 0 ? pipelineIdToPipelineDiagnostics[this.Breadcrumbs.Last()] : graph; this.VisualGraph = this.BuildVisualGraph(currentGraph, pipelineIdToPipelineDiagnostics); } this.view.Update(forceRelayout); }
/// <summary> /// Update diagnostics graph. /// </summary> /// <param name="graph">Current diagnostics graph.</param> public void UpdateGraph(PipelineDiagnostics graph) { this.model.Graph = graph; foreach (var view in this.Breadcrumbs) { if (!graph.Subpipelines.TryGetValue(view, out PipelineDiagnostics subgraph)) { graph = null; break; } graph = subgraph; } this.VisualGraph = graph != null?this.BuildVisualGraph(graph) : null; this.view.Update(); }
private Graph BuildVisualGraph(PipelineDiagnostics diagnostics, Dictionary <int, PipelineDiagnostics> pipelineIdToPipelineDiagnostics) { var subpipelineIdToPipelineDiagnostics = diagnostics.SubpipelineDiagnostics.ToDictionary(p => p.Id); var graph = new Graph($"{diagnostics.Name} (running={diagnostics.IsPipelineRunning})", $"g{diagnostics.Id}"); switch (this.model.VisualizationObject.LayoutDirection) { case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.LeftToRight: graph.Attr.LayerDirection = LayerDirection.LR; break; case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.TopToBottom: graph.Attr.LayerDirection = LayerDirection.TB; break; case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.RightToLeft: graph.Attr.LayerDirection = LayerDirection.RL; break; case PipelineDiagnosticsVisualizationObject.GraphLayoutDirection.BottomToTop: graph.Attr.LayerDirection = LayerDirection.BT; break; } graph.UserData = diagnostics.Id; graph.Attr.BackgroundColor = Color.Transparent; var subpipelineNodes = new Dictionary <int, PipelineDiagnostics.PipelineElementDiagnostics>(); var connectorsWithinSubpipelines = new Dictionary <int, PipelineDiagnostics.PipelineElementDiagnostics>(); var statsSelector = this.StatsSelector(false); // add nodes foreach (var node in diagnostics.PipelineElements.Where(n => !this.IsConnectorBridge(n))) { var vis = this.BuildVisualNode(node); if (node.Kind == PipelineElementKind.Subpipeline && node.RepresentsSubpipeline != null) { vis.UserData = node.RepresentsSubpipeline; subpipelineNodes.Add(node.RepresentsSubpipeline.Id, node); foreach (var n in node.RepresentsSubpipeline.PipelineElements.Where(n => n.Kind == PipelineElementKind.Connector)) { connectorsWithinSubpipelines.Add(n.Id, n); } } else if (node.Kind == PipelineElementKind.Connector) { this.SetConnectorVisualAttributes(vis, node.Name); } graph.AddNode(vis); } // add connectors foreach (var node in diagnostics.PipelineElements.Where(this.IsConnectorBridge)) { var connectsToSubpipeline = subpipelineNodes.ContainsKey(node.ConnectorBridgeToPipelineElement.PipelineId); if (!connectsToSubpipeline) { if (!this.ShowExporterConnections && IsBridgeToExporter(node)) { continue; } var connector = new Node($"n{node.Id}"); var bridgedPipeline = pipelineIdToPipelineDiagnostics[node.ConnectorBridgeToPipelineElement.PipelineId]; this.SetConnectorVisualAttributes(connector, $"{node.Name} ({bridgedPipeline.Name})"); graph.AddNode(connector); } } // add edges var selectedEdgeUpdated = false; foreach (var n in diagnostics.PipelineElements) { foreach (var i in n.Receivers) { if (i.Source != null) { if (this.AddVisualEdge(i.Source.PipelineElement.Id, n.Id, i, graph, statsSelector)) { selectedEdgeUpdated = true; } } } } // add connector bridge edges foreach (var n in diagnostics.PipelineElements.Where(this.IsConnectorBridge)) { if (!this.ShowExporterConnections && IsBridgeToExporter(n)) { continue; } // connector bridging to subpipeline? if (subpipelineNodes.TryGetValue(n.ConnectorBridgeToPipelineElement.PipelineId, out PipelineDiagnostics.PipelineElementDiagnostics subNode)) { // edges from connector source directly to bridge target (subpipeline) var sub = graph.FindNode($"n{subNode.Id}"); if (sub != null) { foreach (var i in n.Receivers) { if (i.Source != null) { var source = graph.FindNode($"n{i.Source.PipelineElement.Id}"); if (source != null) { if (this.AddVisualEdge(source, sub, i, graph, statsSelector)) { selectedEdgeUpdated = true; } } } } // edges from connector bridge source (subpipeline) to connector targets foreach (var o in n.Emitters) { foreach (var t in o.Targets) { var target = graph.FindNode($"n{t.PipelineElement.Id}"); if (target != null) { if (this.AddVisualEdge(sub, target, t, graph, statsSelector)) { selectedEdgeUpdated = true; } } } } } } else { // connector bridging graphs var bridgedPipeline = pipelineIdToPipelineDiagnostics[n.ConnectorBridgeToPipelineElement.PipelineId]; var connector = graph.FindNode($"n{n.Id}"); // add dotted line edge representing connector bridged to descendant pipeline var targetPipeline = bridgedPipeline; while (targetPipeline != null) { if (subpipelineIdToPipelineDiagnostics.ContainsKey(targetPipeline.Id)) { var targetNode = graph.FindNode($"n{subpipelineNodes[targetPipeline.Id].Id}"); graph.AddPrecalculatedEdge(this.BuildVisualEdge(connector, targetNode, n.Name, bridgedPipeline.Name, string.Empty, string.Empty, Style.Dotted)); break; } // walk up ancestor chain until we're at a direct child subpipeline targetPipeline = targetPipeline.ParentPipelineDiagnostics; } } } // add connector bridge edges between descendants (shown between current-level subpiplines) int?TryFindCurrentLevelAncestorSubpipelineId(int id) { foreach (var ancestor in pipelineIdToPipelineDiagnostics[id].AncestorPipelines) { if (subpipelineNodes.TryGetValue(ancestor.Id, out PipelineDiagnostics.PipelineElementDiagnostics subpipeline)) { return(subpipeline.Id); } } return(null); } foreach (var descendantConnector in diagnostics.GetAllPipelineElementDiagnostics().Where(this.IsConnectorBridge)) { if (descendantConnector.Emitters.Length == 0 /* source-side of connector pair */) { var sourceId = descendantConnector.PipelineId; var targetId = descendantConnector.ConnectorBridgeToPipelineElement.PipelineId; var sourceCurrentLevelId = TryFindCurrentLevelAncestorSubpipelineId(sourceId); var targetCurrentLevelId = TryFindCurrentLevelAncestorSubpipelineId(targetId); if (sourceCurrentLevelId != null && targetCurrentLevelId != null && sourceCurrentLevelId != targetCurrentLevelId) { var sourceNode = graph.FindNode($"n{sourceCurrentLevelId}"); var targetNode = graph.FindNode($"n{targetCurrentLevelId}"); graph.AddPrecalculatedEdge(this.BuildVisualEdge(sourceNode, targetNode, string.Empty, descendantConnector.Name, string.Empty, string.Empty, Style.Dotted)); } } } // add direct connections from one subpipeline (connector) to another foreach (var c in connectorsWithinSubpipelines.Values) { if (c.ConnectorBridgeToPipelineElement != null) { if (c.ConnectorBridgeToPipelineElement.PipelineId == diagnostics.Id && c.ConnectorBridgeToPipelineElement.Receivers.Length == 1) { var i = c.ConnectorBridgeToPipelineElement.Receivers[0]; if (i.Source != null && i.Source.PipelineElement.PipelineId == diagnostics.Id && i.Source.PipelineElement.ConnectorBridgeToPipelineElement != null) { if (subpipelineNodes.TryGetValue(i.Source.PipelineElement.ConnectorBridgeToPipelineElement.PipelineId, out PipelineDiagnostics.PipelineElementDiagnostics source) && subpipelineNodes.TryGetValue(c.PipelineId, out PipelineDiagnostics.PipelineElementDiagnostics target)) { if (this.AddVisualEdge(source.Id, target.Id, i, graph, statsSelector)) { selectedEdgeUpdated = true; } } } } } } if (!selectedEdgeUpdated && this.model.SelectedEdgeId != -1) { // hide while in subpipeline this.model.SelectedEdgeDetails = string.Empty; } this.VisualizeEdgeColoring(graph); return(graph); }
private Graph BuildVisualGraph(PipelineDiagnostics diagnostics) { var graph = new Graph($"{diagnostics.Name} (running={diagnostics.IsPipelineRunning})", $"g{diagnostics.Id}"); switch (this.model.Config.LayoutDirection) { case Config.DiagnosticsVisualizationObjectConfiguration.GraphLayoutDirection.LeftToRight: graph.Attr.LayerDirection = LayerDirection.LR; break; case Config.DiagnosticsVisualizationObjectConfiguration.GraphLayoutDirection.TopToBottom: graph.Attr.LayerDirection = LayerDirection.TB; break; case Config.DiagnosticsVisualizationObjectConfiguration.GraphLayoutDirection.RightToLeft: graph.Attr.LayerDirection = LayerDirection.RL; break; case Config.DiagnosticsVisualizationObjectConfiguration.GraphLayoutDirection.BottomToTop: graph.Attr.LayerDirection = LayerDirection.BT; break; } graph.UserData = diagnostics.Id; graph.Attr.BackgroundColor = Color.Transparent; var subpipelineNodes = new Dictionary <int, PipelineDiagnostics.PipelineElementDiagnostics>(); var connectorsWithinSubpipelines = new Dictionary <int, PipelineDiagnostics.PipelineElementDiagnostics>(); var statsSelector = this.StatsSelector(false); // add nodes var nodes = diagnostics.PipelineElements.Select(n => n.Value).Where(n => !this.IsConnectorBridge(n)); foreach (var node in nodes) { var vis = this.BuildVisualNode(node); if (node.Kind == PipelineDiagnostics.PipelineElementDiagnostics.PipelineElementKind.Subpipeline) { vis.UserData = node.RepresentsSubpipeline; subpipelineNodes.Add(node.RepresentsSubpipeline.Id, node); foreach (var n in node.RepresentsSubpipeline.PipelineElements.Values.Where(n => n.Kind == PipelineDiagnostics.PipelineElementDiagnostics.PipelineElementKind.Connector)) { connectorsWithinSubpipelines.Add(n.Id, n); } } else if (node.Kind == PipelineDiagnostics.PipelineElementDiagnostics.PipelineElementKind.Connector) { vis.Attr.Color = this.ConnectorColor; vis.Attr.FillColor = this.ConnectorColor; vis.Attr.Shape = Shape.Circle; vis.LabelText = string.Empty; } graph.AddNode(vis); } // add edges var selectedEdgeUpdated = false; foreach (var n in diagnostics.PipelineElements) { foreach (var i in n.Value.Receivers) { if (i.Value.Source != null) { if (this.AddVisualEdge(i.Value.Source.PipelineElement.Id, n.Value.Id, i.Value, graph, statsSelector)) { selectedEdgeUpdated = true; } } } } // add connectors foreach (var n in diagnostics.PipelineElements.Where(n => this.IsConnectorBridge(n.Value))) { // connector bridging to subpipeline? if (subpipelineNodes.TryGetValue(n.Value.ConnectorBridgeToPipelineElement.ParentPipeline.Id, out PipelineDiagnostics.PipelineElementDiagnostics subNode)) { // edges from connector source directly to bridge target (subpipeline) var sub = graph.FindNode($"n{subNode.Id}"); if (sub != null) { foreach (var i in n.Value.Receivers) { if (i.Value.Source != null) { var source = graph.FindNode($"n{i.Value.Source.PipelineElement.Id}"); if (source != null) { graph.AddPrecalculatedEdge(this.BuildVisualEdge(source, sub, i.Value, statsSelector)); } } } // edges from connector bridge source (subpipeline) to connector targets foreach (var o in n.Value.Emitters) { foreach (var t in o.Value.Targets) { var target = graph.FindNode($"n{t.Value.PipelineElement.Id}"); if (target != null) { graph.AddPrecalculatedEdge(this.BuildVisualEdge(sub, target, t.Value, statsSelector)); } } } } } else { // connector bridging to parent graph var connector = new Node($"n{n.Value.Id}"); connector.Attr.Color = this.ConnectorColor; connector.Attr.FillColor = this.ConnectorColor; connector.Attr.Shape = Shape.Circle; connector.LabelText = string.Empty; graph.AddNode(connector); // edges from connector to target node foreach (var o in n.Value.Emitters) { foreach (var t in o.Value.Targets) { var target = graph.FindNode($"n{t.Value.PipelineElement.Id}"); if (target != null) { graph.AddPrecalculatedEdge(this.BuildVisualEdge(connector, target, t.Value, statsSelector)); } } } // edges to connector from source node foreach (var i in n.Value.Receivers) { if (i.Value.Source != null) { var source = graph.FindNode($"n{i.Value.Source.PipelineElement.Id}"); if (source != null) { graph.AddPrecalculatedEdge(this.BuildVisualEdge(source, connector, i.Value, statsSelector)); } } } } } // add direct connections from one subpipeline (connector) to another foreach (var c in connectorsWithinSubpipelines.Values) { if (c.ConnectorBridgeToPipelineElement != null) { if (c.ConnectorBridgeToPipelineElement.ParentPipeline == diagnostics && c.ConnectorBridgeToPipelineElement.Receivers.Count == 1) { var i = c.ConnectorBridgeToPipelineElement.Receivers.Values.First(); if (i.Source != null && i.Source.PipelineElement.ParentPipeline == diagnostics && i.Source.PipelineElement.ConnectorBridgeToPipelineElement != null) { if (subpipelineNodes.TryGetValue(i.Source.PipelineElement.ConnectorBridgeToPipelineElement.ParentPipeline.Id, out PipelineDiagnostics.PipelineElementDiagnostics source) && subpipelineNodes.TryGetValue(c.ParentPipeline.Id, out PipelineDiagnostics.PipelineElementDiagnostics target)) { if (this.AddVisualEdge(source.Id, target.Id, i, graph, statsSelector)) { selectedEdgeUpdated = true; } } } } } } if (!selectedEdgeUpdated && this.selectedEdgeId != -1) { // hide while in subpipeline this.SelectedEdgeDetails = string.Empty; } this.VisualizeHeatmap(graph); return(graph); }