From d565ef9bac380d3cb37057a3904f2847806f0319 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 5 Nov 2017 16:54:30 +0000 Subject: [PATCH] Rewrite ProcessRenderer/MapEndpoint2Process as a single Renderer This is much more efficient as we skip creating then merging all intermediate Nodes --- render/process.go | 95 ++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/render/process.go b/render/process.go index c2aafd3715..9ccca829e4 100644 --- a/render/process.go +++ b/render/process.go @@ -26,15 +26,7 @@ var EndpointRenderer = SelectEndpoint // ProcessRenderer is a Renderer which produces a renderable process // graph by merging the endpoint graph and the process topology. -var ProcessRenderer = ConditionalRenderer(renderProcesses, - MakeReduce( - MakeMap( - MapEndpoint2Process, - EndpointRenderer, - ), - SelectProcess, - ), -) +var ProcessRenderer = Memoise(endpoints2Processes{}) // ColorConnectedProcessRenderer colors connected nodes from // ProcessRenderer. Since the process topology views only show @@ -110,40 +102,67 @@ func pseudoNodeID(n report.Node, local report.Networks) (string, bool) { return "", false } -// MapEndpoint2Process maps endpoint Nodes to process -// Nodes. -// -// If this function is given a pseudo node, then it will just return it; -// Pseudo nodes will never have pids in them, and therefore will never -// be able to be turned into a Process node. -// -// Otherwise, this function will produce a node with the correct ID -// format for a process, but without any Major or Minor labels. -// It does not have enough info to do that, and the resulting graph -// must be merged with a process graph to get that info. -func MapEndpoint2Process(n report.Node, local report.Networks) report.Nodes { - // Nodes without a hostid are treated as pseudo nodes - if _, ok := n.Latest.Lookup(report.HostNodeID); !ok { - return MapEndpoint2Pseudo(n, local) - } +// endpoints2Processes joins the endpoint topology to the process +// topology, matching on hostID and pid. +type endpoints2Processes struct { +} - pid, timestamp, ok := n.Latest.LookupEntry(process.PID) - if !ok { +func (e endpoints2Processes) Render(rpt report.Report, dct Decorator) report.Nodes { + if len(rpt.Process.Nodes) == 0 { return report.Nodes{} } - - if len(n.Adjacency) > 1 { - // We cannot be sure that the pid is associated with all the - // connections. It is better to drop such an endpoint than - // risk rendering bogus connections. - return report.Nodes{} + processes := SelectProcess.Render(rpt, dct) + endpoints := SelectEndpoint.Render(rpt, dct) + local := LocalNetworks(rpt) + + var ret = make(report.Nodes) + var mapped = map[string]string{} // input node ID -> output node ID + for _, n := range endpoints { + // Nodes without a hostid are treated as pseudo nodes + if hostNodeID, ok := n.Latest.Lookup(report.HostNodeID); !ok { + if id, ok := pseudoNodeID(n, local); ok { + addToResults(n, id, ret, mapped, func() report.Node { + return report.MakeNode(id).WithTopology(Pseudo) + }) + } + } else { + pid, timestamp, ok := n.Latest.LookupEntry(process.PID) + if !ok { + continue + } + + if len(n.Adjacency) > 1 { + // We cannot be sure that the pid is associated with all the + // connections. It is better to drop such an endpoint than + // risk rendering bogus connections. + continue + } + + hostID, _, _ := report.ParseNodeID(hostNodeID) + id := report.MakeProcessNodeID(hostID, pid) + addToResults(n, id, ret, mapped, func() report.Node { + if processNode, found := processes[id]; found { + return processNode + } else { + return report.MakeNode(id).WithTopology(report.Process). + WithLatest(process.PID, timestamp, pid) + } + }) + } } + // Copy through any unmatched process nodes + for _, n := range processes { + if _, found := ret[n.ID]; !found { + ret[n.ID] = n + } + } + fixupAdjancencies(processes, ret, mapped) + fixupAdjancencies(endpoints, ret, mapped) + return ret +} - id := report.MakeProcessNodeID(report.ExtractHostID(n), pid) - node := NewDerivedNode(id, n).WithTopology(report.Process) - node.Latest = node.Latest.Set(process.PID, timestamp, pid) - node.Counters = node.Counters.Add(n.Topology, 1) - return report.Nodes{id: node} +func (e endpoints2Processes) Stats(rpt report.Report, _ Decorator) Stats { + return Stats{} // nothing to report } // MapProcess2Name maps process Nodes to Nodes