diff --git a/app/src/components/callflowEnsemble.js b/app/src/components/callflowEnsemble.js index 18300cfe..8a3bea59 100644 --- a/app/src/components/callflowEnsemble.js +++ b/app/src/components/callflowEnsemble.js @@ -549,7 +549,7 @@ export default { else if (this.selectedFormat == "CCT") { this.initComponents(this.currentEnsembleCCTComponents); } - EventHandler.$emit("ensemble-auxiliary", {}); + EventHandler.$emit("ensemble-refresh-boxplot", {}); }, reset() { @@ -679,15 +679,6 @@ export default { }); }, - updateCompareMode() { - this.$store.selectedCompareMode = this.selectedCompareMode; - this.$socket.emit("compare", { - targetDataset: this.$store.selectedTargetDataset, - compareDataset: this.$store.selectedCompareDataset, - selectedMetric: this.$store.selectedMetric - }); - }, - updateProp() { this.$store.selectedProp = this.selectedProp; this.clearLocal(); diff --git a/app/src/components/callflowSingle.js b/app/src/components/callflowSingle.js index 1367e99e..4c49cc23 100644 --- a/app/src/components/callflowSingle.js +++ b/app/src/components/callflowSingle.js @@ -494,7 +494,7 @@ export default { else if (this.selectedFormat == "CCT") { this.initComponents(this.currentSingleCCTComponents); } - EventHandler.$emit("single-auxiliary", {}); + EventHandler.$emit("single-refresh-boxplot", {}); }, reset() { @@ -523,6 +523,7 @@ export default { this.clear(); this.$store.selectedTargetDataset = this.selectedTargetDataset; console.debug("[Update] Target Dataset: ", this.selectedTargetDataset); + d3.selectAll(".tick").remove(); this.init(); }, diff --git a/app/src/components/callsiteCorrespondence/boxplot.js b/app/src/components/callsiteCorrespondence/boxplot.js index 610d715c..7975aee1 100644 --- a/app/src/components/callsiteCorrespondence/boxplot.js +++ b/app/src/components/callsiteCorrespondence/boxplot.js @@ -62,7 +62,7 @@ export default { mounted() { this.init(); let self = this; - EventHandler.$on("ensemble-auxiliary", (data) => { + EventHandler.$on("ensemble-refresh-boxplot", (data) => { self.clear(); self.init(); }); diff --git a/app/src/components/callsiteCorrespondence/callsiteCorrespondence.js b/app/src/components/callsiteCorrespondence/callsiteCorrespondence.js index 3e89ac9b..dcd12f67 100644 --- a/app/src/components/callsiteCorrespondence/callsiteCorrespondence.js +++ b/app/src/components/callsiteCorrespondence/callsiteCorrespondence.js @@ -70,29 +70,26 @@ export default { }), mounted() { let self = this; + + EventHandler.$on("highlight-dataset", (data) => { + let dataset = data["dataset"]; + if (self.$store.showTarget) { + self.highlightCallsitesByDataset(dataset); + } + }); + EventHandler.$on("highlight-datasets", (datasets) => { console.log("[Interaction] Highlighting the datasets :", datasets); self.highlight(datasets); }); - EventHandler.$on("update-auxiliary-sort-by", (sortBy) => { - self.updateSortBy(sortBy); - }); - - EventHandler.$on("select-module", (data) => { + EventHandler.$on("ensemble-select-module", (data) => { let thismodule = data["module"]; // self.selectCallsitesByModule(thismodule) this.isModuleSelected = true; self.selectModule(thismodule); }); - EventHandler.$on("highlight-dataset", (data) => { - let dataset = data["dataset"]; - if (self.$store.showTarget) { - self.highlightCallsitesByDataset(dataset); - } - }); - EventHandler.$on("callsite-information-sort", (data) => { let attribute = self.$store.selectedRuntimeSortBy; self.differenceCallsites = self.sortByAttribute(self.knc["difference"], attribute); @@ -309,6 +306,7 @@ export default { event.stopPropagation(); let callsite = event.currentTarget.id; this.$socket.emit("reveal_callsite", { + mode: this.$store.selectedMode, reveal_callsites: this.revealCallsites, datasets: this.$store.selectedDatasets, }); @@ -427,17 +425,19 @@ export default { split() { if (this.isEntryFunctionSelected == "select-callsite") { this.$socket.emit("split_by_entry_callsites", { + mode: this.$store.selectedMode, selectedModule: this.$store.selectedModule, datasets: this.$store.selectedDatasets, }); - EventHandler.$emit("split-by-entry-callsites"); + EventHandler.$emit("reveal-callsite"); } else if (this.isCalleeSelected == "select-callsite") { this.$socket.emit("split_by_callees", { + mode: this.$store.selectedMode, selectedModule: this.$store.selectedModule, datasets: this.$store.selectedDatasets, }); - EventHandler.$emit("split-by-callees"); + EventHandler.$emit("reveal-callsite"); } } } diff --git a/app/src/components/callsiteCorrespondence/markers.js b/app/src/components/callsiteCorrespondence/markers.js index a330f61e..1f83eaef 100644 --- a/app/src/components/callsiteCorrespondence/markers.js +++ b/app/src/components/callsiteCorrespondence/markers.js @@ -67,13 +67,13 @@ export default { this.targetData = this.targetq; this.data = this.q; - this.minMaxEnsembleMarker(); + // this.minMaxEnsembleMarker(); if (this.$store.showTarget) { this.minMaxTargetMarker(); } - this.minText(); - this.maxText(); - this.medianText(); + // this.minText(); + // this.maxText(); + // this.medianText(); }, minMaxEnsembleMarker() { diff --git a/app/src/components/callsiteInformation/box.js b/app/src/components/callsiteInformation/box.js index 23b1506a..9fd420ef 100644 --- a/app/src/components/callsiteInformation/box.js +++ b/app/src/components/callsiteInformation/box.js @@ -48,8 +48,8 @@ export default { }); this.box(); - this.centerLine(); this.axis(); + this.centerLine(); this.$parent.$refs.ToolTip.init("boxplot-" + callsite.id); }, @@ -112,7 +112,7 @@ export default { let exponent_string = this.superscript[this.x_max_exponent]; let label = "(e+" + this.x_max_exponent + ") " + "Exclusive Runtime (" + "\u03BCs)"; this.g.append("text") - .attr("class", "axis-label") + .attr("class", "boxplot-axis-label") .attr("x", this.$parent.boxWidth - 20) .attr("y", this.$parent.centerLinePosition * 3.8) .style("font-size", "12px") @@ -134,8 +134,7 @@ export default { const xAxisLine = this.g.append("g") .attrs({ - "class": "axis", - "id": "xAxis", + "class": "boxplot-axis", "transform": "translate(" + 0 + "," + 2.5 * this.$parent.centerLinePosition + ")" }) .call(xAxis); @@ -162,8 +161,8 @@ export default { clear() { this.g.selectAll(".box").remove(); this.g.selectAll(".centerLine").remove(); - this.g.selectAll(".axis-label").remove(); - this.g.selectAll(".axis").remove(); + this.g.selectAll(".boxplot-axis-label").remove(); + this.g.selectAll(".boxplot-axis").remove(); } } }; \ No newline at end of file diff --git a/app/src/components/callsiteInformation/boxplot.js b/app/src/components/callsiteInformation/boxplot.js index 5de95f09..485569d3 100644 --- a/app/src/components/callsiteInformation/boxplot.js +++ b/app/src/components/callsiteInformation/boxplot.js @@ -63,7 +63,7 @@ export default { this.init(); let self = this; - EventHandler.$on("single-auxiliary", (data) => { + EventHandler.$on("single-refresh-boxplot", (data) => { self.clear(); self.init(); }); @@ -91,6 +91,7 @@ export default { this.svg = d3.select("#boxplot-" + this.callsite.id) .attrs({ + "class": "boxplot", "width": this.containerWidth, "height": this.containerHeight }); diff --git a/app/src/components/callsiteInformation/callsiteInformation.js b/app/src/components/callsiteInformation/callsiteInformation.js index 92e599f1..882788ec 100644 --- a/app/src/components/callsiteInformation/callsiteInformation.js +++ b/app/src/components/callsiteInformation/callsiteInformation.js @@ -65,7 +65,8 @@ export default { /** * Event handler when a user selects a supernode. */ - EventHandler.$on("select_module", (data) => { + EventHandler.$on("single-select-module", (data) => { + this.isModuleSelected = true; self.selectModule(data["module"]); }); @@ -156,7 +157,6 @@ export default { this.mean[callsite] = utils.formatRuntimeWithoutUnits(data["mean_time"]); this.variance[callsite] = utils.formatRuntimeWithoutUnits(data["variance"]); this.stdDeviation[callsite] = utils.formatRuntimeWithoutUnits(data["std_deviation"]); - this.selectClassName[callsite] = "unselect-callsite"; } }, @@ -217,7 +217,6 @@ export default { else { this.switchIsSelectedCallsite(true); } - console.debug("Selected callsites: ", this.revealCallsites); }, /** @@ -309,12 +308,12 @@ export default { * * @param {*} event */ - clickCallsite(event) { + revealCallsite(event) { event.stopPropagation(); - let callsite = event.currentTarget.id; this.$socket.emit("reveal_callsite", { + mode: this.$store.selectedMode, reveal_callsites: this.revealCallsites, - datasets: this.$store.selectedDatasets, + dataset: this.$store.selectedTargetDataset, }); EventHandler.$emit("reveal-callsite"); @@ -363,18 +362,18 @@ export default { this.numberOfCallsites = Object.keys(callsites_in_module).length; - // Clear up the current callsites map. - this.callsites = {}; - // Set display: none to all .callsite-information-node. // This hides the nodes when a supernode is selected. - d3.selectAll(".callsite-information-node").style("display", "none"); + for(let callsite in this.callsites){ + d3.select("#callsite-information-" + callsite.id).style("display", "none"); + } + + // Clear up the current callsites map. + this.callsites = {}; // Set the data and render each callsite. callsites_in_module.forEach((callsite) => { - if (callsites_in_module.indexOf(callsite) > -1) { - this.callsites[callsite] = this.$store.callsites[this.$store.selectedTargetDataset][callsite]; - } + this.callsites[callsite] = this.$store.callsites[this.$store.selectedTargetDataset][callsite]; d3.select("#callsite-information-" + this.callsites[callsite].id).style("display", "block"); }); }, @@ -420,14 +419,14 @@ export default { if (this.isEntryFunctionSelected == "select-callsite") { this.$socket.emit("split_by_entry_callsites", { selectedModule: this.$store.selectedModule, - datasets: this.$store.selectedDatasets, + dataset: this.$store.selectedTargetDataset, }); EventHandler.$emit("split-by-entry-callsites"); } else if (this.isCalleeSelected == "select-callsite") { this.$socket.emit("split_by_callees", { selectedModule: this.$store.selectedModule, - datasets: this.$store.selectedDatasets, + dataset: this.$store.selectedTargetDataset, }); EventHandler.$emit("split-by-callees"); } diff --git a/app/src/components/callsiteInformation/markers.js b/app/src/components/callsiteInformation/markers.js index 80f65a4c..8bb4d08e 100644 --- a/app/src/components/callsiteInformation/markers.js +++ b/app/src/components/callsiteInformation/markers.js @@ -79,9 +79,9 @@ export default { this.data = this.q; this.minMaxTargetMarker(); - this.minText(); - this.maxText(); - this.medianText(); + // this.minText(); + // this.maxText(); + // this.medianText(); }, diff --git a/app/src/components/singleHistogram/singleHistogram.js b/app/src/components/singleHistogram/singleHistogram.js index b726aeaf..2e1100e2 100644 --- a/app/src/components/singleHistogram/singleHistogram.js +++ b/app/src/components/singleHistogram/singleHistogram.js @@ -126,7 +126,6 @@ export default { d3.selectAll(".histogram-axis-label").remove(); d3.selectAll(".binRank").remove(); d3.selectAll(".lineRank").remove(); - d3.selectAll(".tick").remove(); d3.selectAll(".brush").remove(); this.$refs.ToolTip.clear(); }, diff --git a/app/src/components/supergraph/encodings/meanGradients.js b/app/src/components/supergraph/encodings/meanGradients.js index e62a72cf..39607341 100644 --- a/app/src/components/supergraph/encodings/meanGradients.js +++ b/app/src/components/supergraph/encodings/meanGradients.js @@ -31,14 +31,14 @@ export default { gradients() { for (let node of this.nodes) { - var defs = d3.select("#" + this.id) + const defs = d3.select("#" + this.id) .append("defs"); - this.linearGradient = defs.append("linearGradient") + const linearGradient = defs.append("linearGradient") .attr("id", "mean-gradient" + node.client_idx) .attr("class", "mean-gradient"); - this.linearGradient + linearGradient .attr("x1", "0%") .attr("y1", "0%") .attr("x2", "0%") @@ -53,7 +53,6 @@ export default { else if (node.type == "component-node") { grid = this.$store.callsites["ensemble"][node.name][this.$store.selectedMetric]["gradients"]["hist"]["x"]; val = this.$store.callsites["ensemble"][node.name][this.$store.selectedMetric]["gradients"]["hist"]["y"]; - } else if (node.type == "intermediate") { grid = []; @@ -63,7 +62,7 @@ export default { for (let i = 0; i < grid.length; i += 1) { let x = (i + i + 1) / (2 * grid.length); let current_value = (val[i]); - this.linearGradient.append("stop") + linearGradient.append("stop") .attr("offset", 100 * x + "%") .attr("stop-color", this.$store.distributionColor.getColorByValue(current_value)); } @@ -143,7 +142,7 @@ export default { }, clear() { - this.containerG.selectAll(".mean-gradient").remove(); + // this.containerG.selectAll(".mean-gradient").remove(); }, } }; \ No newline at end of file diff --git a/app/src/components/supergraph/nodes.js b/app/src/components/supergraph/nodes.js index 247318e6..85767050 100644 --- a/app/src/components/supergraph/nodes.js +++ b/app/src/components/supergraph/nodes.js @@ -208,65 +208,68 @@ export default { click(node) { event.stopPropagation(); - // Set the data. - this.$store.selectedNode = node; - this.$store.selectedModule = node.module; - this.$store.selectedName = node.name; - - const nodeSVG = this.containerG.select("#callsite-" + node.client_idx); - - // Make appropriate event requests (Single and Ensemble). - if (this.$store.selectedMode == "Ensemble") { - if (!this.drawGuidesMap[node.id]) { - this.$refs.Guides.visualize(node, "permanent", nodeSVG); - this.drawGuidesMap[node.id] = true; - } - - this.$socket.emit("module_hierarchy", { - module: this.$store.selectedModule, - name: this.$store.selectedName, - datasets: this.$store.selectedDatasets, - }); - - EventHandler.$emit("ensemble-histogram", { - module: this.$store.selectedModule, - datasets: this.$store.selectedDatasets, - }); - - EventHandler.$emit("ensemble-distribution", { - module: this.$store.selectedModule, - datasets: this.$store.selectedDatasets, - }); - - EventHandler.$emit("ensemble-scatterplot", { - module: this.$store.selectedModule, - dataset1: this.$store.selectedDatasets, - }); + if (node !== this.$store.selectedNode) { + // Set the data. + this.$store.selectedNode = node; + this.$store.selectedModule = node.module; + this.$store.selectedName = node.name; + + const nodeSVG = this.containerG.select("#callsite-" + node.client_idx); + + // Make appropriate event requests (Single and Ensemble). + if (this.$store.selectedMode == "Ensemble") { + if (!this.drawGuidesMap[node.id]) { + this.$refs.Guides.visualize(node, "permanent", nodeSVG); + this.drawGuidesMap[node.id] = true; + } - this.$socket.emit("ensemble_auxiliary", { - module: this.$store.selectedModule, - datasets: this.$store.selectedDatasets, - sortBy: this.$store.auxiliarySortBy, - }); - } - else if (this.$store.selectedMode == "Single") { - EventHandler.$emit("single-histogram", { - module: this.$store.selectedModule, - groupBy: this.$store.selectedGroupBy, - dataset: this.$store.selectedTargetDataset, - }); + this.$socket.emit("module_hierarchy", { + module: this.$store.selectedModule, + name: this.$store.selectedName, + datasets: this.$store.selectedDatasets, + }); + + this.$socket.emit("ensemble_auxiliary", { + module: this.$store.selectedModule, + datasets: this.$store.selectedDatasets, + sortBy: this.$store.auxiliarySortBy, + }); + + EventHandler.$emit("ensemble-histogram", { + module: this.$store.selectedModule, + datasets: this.$store.selectedDatasets, + }); + + EventHandler.$emit("ensemble-scatterplot", { + module: this.$store.selectedModule, + dataset1: this.$store.selectedDatasets, + }); + + EventHandler.$emit("ensemble-select-module", { + module: this.$store.selectedModule, + }); + } + else if (this.$store.selectedMode == "Single") { + EventHandler.$emit("single-histogram", { + module: this.$store.selectedModule, + groupBy: this.$store.selectedGroupBy, + dataset: this.$store.selectedTargetDataset, + }); + + EventHandler.$emit("single-scatterplot", { + module: this.$store.selectedModule, + dataset: this.$store.selectedTargetDataset, + }); + + EventHandler.$emit("single-select-module", { + module: this.$store.selectedModule, + }); + } - EventHandler.$emit("single-scatterplot", { - module: this.$store.selectedModule, - dataset: this.$store.selectedTargetDataset, - }); + // EventHandler.$emit("show-target-auxiliary", {}); } - EventHandler.$emit("select-module", { - module: this.$store.selectedModule, - }); - EventHandler.$emit("show-target-auxiliary", {}); }, mouseover(node) { diff --git a/app/src/components/supergraph/supergraph.js b/app/src/components/supergraph/supergraph.js index 7ae10c71..43566faa 100644 --- a/app/src/components/supergraph/supergraph.js +++ b/app/src/components/supergraph/supergraph.js @@ -61,15 +61,7 @@ export default { self.clear(); }); - EventHandler.$on("reveal_callsite", function () { - self.clear(); - }); - - EventHandler.$on("split_by_entry_callsites", function () { - self.clear(); - }); - - EventHandler.$on("split_by_callees", function () { + EventHandler.$on("reveal-callsite", function () { self.clear(); }); diff --git a/app/src/css/callsiteCorrespondence.css b/app/src/css/callsiteCorrespondence.css index 086f080a..d1ead83c 100644 --- a/app/src/css/callsiteCorrespondence.css +++ b/app/src/css/callsiteCorrespondence.css @@ -38,7 +38,7 @@ .reveal-button { float: right; margin: 1px; - color: #009688 !important; + /* color: #009688 !important; */ font-size: 75%; padding: 2px; } diff --git a/app/src/html/callflowEnsemble.html b/app/src/html/callflowEnsemble.html index afc9a318..8f3d8196 100644 --- a/app/src/html/callflowEnsemble.html +++ b/app/src/html/callflowEnsemble.html @@ -376,11 +376,11 @@ > - - Projection view + Projection view - + --> -
+
Std. Dev. : {{targetStandardDeviation[callsite.name]}}
@@ -154,13 +154,13 @@ -
+
Mean : {{ensembleMeans[callsite.name]}}
-
+
Std. Dev. : {{ensembleStandardDeviation[callsite.name]}}
diff --git a/app/src/html/callsiteInformation.html b/app/src/html/callsiteInformation.html index fc1fbc14..c38a9cb3 100644 --- a/app/src/html/callsiteInformation.html +++ b/app/src/html/callsiteInformation.html @@ -12,7 +12,7 @@ - + Reveal diff --git a/callflow/callflow.py b/callflow/callflow.py index 486929ae..9db9483a 100644 --- a/callflow/callflow.py +++ b/callflow/callflow.py @@ -276,8 +276,27 @@ def request_single(self, operation): return self.supergraphs[operation["dataset"]].auxiliary_data elif operation_name == "supergraph": + if "reveal_callsites" in operation: + reveal_callsites = operation["reveal_callsites"] + else: + reveal_callsites = [] + + if "split_entry_module" in operation: + split_entry_module = operation["split_entry_module"] + else: + split_entry_module = "" + + if "split_callee_module" in operation: + split_callee_module = operation["split_callee_module"] + else: + split_callee_module = "" + single_supergraph = SankeyLayout( - supergraph=self.supergraphs[operation["dataset"]], path="group_path" + supergraph=self.supergraphs[operation["dataset"]], + path="group_path", + reveal_callsites=reveal_callsites, + split_entry_module=split_entry_module, + split_callee_module=split_callee_module, ) return single_supergraph.nxg diff --git a/callflow/layout/sankey.py b/callflow/layout/sankey.py index ed1efa7e..58ed3aa0 100644 --- a/callflow/layout/sankey.py +++ b/callflow/layout/sankey.py @@ -6,6 +6,7 @@ import pandas as pd import networkx as nx import numpy as np +from ast import literal_eval as make_list # CallFlow imports try: @@ -34,6 +35,9 @@ class SankeyLayout: "entry_function", ] + _PRIMARY_GROUPBY_COLUMN = "name" + _SECONDARY_GROUPBY_COLUMN = "module" + def __init__( self, supergraph, @@ -54,14 +58,36 @@ def __init__( self.runs = self.supergraph.gf.df["dataset"].unique() + self.reveal_callsites = reveal_callsites + self.split_entry_module = split_entry_module + self.split_callee_module = split_callee_module + LOGGER.info( "Creating the Single SankeyLayout for {0}.".format(self.supergraph.tag) ) + self.primary_group_df = self.supergraph.gf.df.groupby( + [SankeyLayout._PRIMARY_GROUPBY_COLUMN] + ) + self.secondary_group_df = self.supergraph.gf.df.groupby( + [SankeyLayout._SECONDARY_GROUPBY_COLUMN] + ) + self.secondary_primary_group_df = self.supergraph.gf.df.groupby( + [ + SankeyLayout._SECONDARY_GROUPBY_COLUMN, + SankeyLayout._PRIMARY_GROUPBY_COLUMN, + ] + ) + with self.timer.phase("Construct Graph"): self.nxg = SankeyLayout._create_nxg_from_paths( self.supergraph.gf.df, self.path ) + self.add_reveal_paths(self.reveal_callsites) + if self.split_entry_module != "": + self.add_entry_callsite_paths(self.split_entry_module) + if self.split_callee_module != "": + self.add_exit_callees_paths() with self.timer.phase("Add graph attributes"): self._add_node_attributes() @@ -69,6 +95,209 @@ def __init__( LOGGER.debug(self.timer) + # -------------------------------------------------------------------------- + # Split by reveal callsite. + def create_source_targets(self, component_path): + module = "" + edges = [] + for idx, callsite in enumerate(component_path): + if idx == 0: + module = component_path[0] + edges.append( + { + "module": module, + "source": module, + "target": module + "=" + component_path[idx + 1], + } + ) + pass + elif idx == len(component_path) - 1: + pass + else: + edges.append( + { + "module": module, + "source": module + "=" + component_path[idx], + "target": module + "=" + component_path[idx + 1], + } + ) + + return edges + + def callsitePathInformation(self, callsites): + paths = [] + for callsite in callsites: + df = self.primary_group_df.get_group(callsite) + paths.append( + { + "group_path": make_list(df["group_path"].unique()[0]), + "path": make_list(df["path"].unique()[0]), + "component_path": make_list(df["component_path"].unique()[0]), + } + ) + return paths + + def add_reveal_paths(self, reveal_callsites): + paths = self.callsitePathInformation(reveal_callsites) + + for path in paths: + component_edges = self.create_source_targets(path["component_path"]) + for idx, edge in enumerate(component_edges): + module = edge["module"] + + # format module + '=' + callsite + source = edge["source"] + target = edge["target"] + + if not self.nxg.has_edge(source, target): + if idx == 0: + source_callsite = source + # source_df = self.secondary_group_df.get_group((module)) + source_node_type = "super-node" + else: + source_callsite = source.split("=")[1] + # source_df = self.secondary_primary_group_df.get_group( + # (module, source_callsite) + # ) + source_node_type = "component-node" + + target_callsite = target.split("=")[1] + target_df = self.secondary_primary_group_df.get_group( + (module, target_callsite) + ) + target_node_type = "component-node" + + # source_weight = source_df["time (inc)"].max() + target_weight = target_df["time (inc)"].max() + + print(f"Adding edge: {source_callsite}, {target_callsite}") + self.nxg.add_node(source, attr_dict={"type": source_node_type}) + self.nxg.add_node(target, attr_dict={"type": target_node_type}) + self.nxg.add_edge( + source, + target, + attr_dict=[ + { + "source_callsite": source_callsite, + "target_callsite": target_callsite, + "weight": target_weight, + "edge_type": "reveal_edge", + } + ], + ) + + # -------------------------------------------------------------------------- + # Add callsites based on split by entry function interactions. + def module_entry_functions_map(self, graph): + entry_functions = {} + for edge in graph.edges(data=True): + attr_dict = edge[2]["attr_dict"] + edge_tuple = (edge[0], edge[1]) + print(edge_tuple) + for edge_attr in attr_dict: + if edge_tuple[1] not in entry_functions: + entry_functions[edge_tuple[1]] = [] + entry_functions[edge_tuple[1]].append(edge_attr["target_callsite"]) + return entry_functions + + def create_source_targets_from_group_path(self, path): + edges = [] + for idx, callsite in enumerate(path): + if idx == len(path) - 1: + break + source = path[idx].split("=") + target = path[idx + 1].split("=") + edges.append( + { + "source": source[0], + "target": target[0], + "source_callsite": source[1], + "target_callsite": target[1], + } + ) + return edges + + def same_source_edges(self, component_edges, reveal_module): + ret = [] + for idx, edge in enumerate(component_edges): + source = edge["source"] + + if source == reveal_module: + ret.append(edge) + return ret + + def same_target_edges(self, component_edges, reveal_module): + ret = [] + for idx, edge in enumerate(component_edges): + target = edge["target"] + + if target == reveal_module: + ret.append(edge) + return ret + + def add_entry_callsite_paths(self, reveal_module): + entry_functions_map = self.module_entry_functions_map(self.nxg) + reveal_callsites = entry_functions_map[reveal_module] + paths = self.callsitePathInformation(reveal_callsites) + + for path in paths: + component_edges = self.create_source_targets_from_group_path( + path["group_path"] + ) + source_edges_to_remove = self.same_source_edges( + component_edges, reveal_module + ) + target_edges_to_remove = self.same_target_edges( + component_edges, reveal_module + ) + + if len(source_edges_to_remove) != 0: + for edge in source_edges_to_remove: + if self.nxg.has_edge(edge["source"], edge["target"]): + self.nxg.remove_edge((edge["source"], edge["target"])) + self.nxg.add_node( + reveal_module + "=" + edge["source_callsite"], + attr_dict={"type": "component-node"}, + ) + self.nxg.add_edge( + (reveal_module + "=" + edge["source_callsite"], edge["target"]), + attr_dict=[ + { + "source_callsite": edge["source_callsite"], + "target_callsite": edge["target_callsite"], + "weight": self.module_name_group_df.get_group( + (reveal_module, edge["source_callsite"]) + )["time (inc)"].max(), + "edge_type": "reveal_edge", + } + ], + ) + + if len(target_edges_to_remove) != 0: + for edge in target_edges_to_remove: + if self.nxg.has_edge(edge["source"], edge["target"]): + self.nxg.remove_edge(edge["source"], edge["target"]) + self.nxg.add_node( + reveal_module + "=" + edge["target_callsite"], + attr_dict={"type": "component-node"}, + ) + self.nxg.add_edge( + edge["source"], + reveal_module + "=" + edge["target_callsite"], + attr_dict=[ + { + "source_callsite": edge["source_callsite"], + "target_callsite": edge["target_callsite"], + "weight": self.secondary_primary_group_df.get_group( + (edge["target"], edge["target_callsite"]) + )["time (inc)"].max(), + "edge_type": "reveal_edge", + } + ], + ) + + self.nxg.remove_node(reveal_module) + # -------------------------------------------------------------------------- # Node attribute methods. def _add_node_attributes(self): diff --git a/server/main.py b/server/main.py index 33bee5a0..87bfb88b 100644 --- a/server/main.py +++ b/server/main.py @@ -157,17 +157,30 @@ def reveal_callsite(data): :return: networkx graph (JSON) """ LOGGER.debug(f"[Socket request] reveal_callsite: {data}") - nxg = self.callflow.request( - { - "name": "supergraph", - "groupBy": "module", - "datasets": data["datasets"], - "reveal_callsites": data["reveal_callsites"], - } - ) - result = json_graph.node_link_data(nxg) - json_result = json.dumps(result) - emit("ensemble_supergraph", json_result, json=True) + if data["mode"] == "Single": + nxg = self.callflow.request_single( + { + "name": "supergraph", + "groupBy": "module", + "dataset": data["dataset"], + "reveal_callsites": data["reveal_callsites"], + } + ) + result = json_graph.node_link_data(nxg) + json_result = json.dumps(result) + emit("single_supergraph", json_result, json=True) + elif data["mode"] == "Ensemble": + nxg = self.callflow.request_ensemble( + { + "name": "supergraph", + "groupBy": "module", + "datasets": data["datasets"], + "reveal_callsites": data["reveal_callsites"], + } + ) + result = json_graph.node_link_data(nxg) + json_result = json.dumps(result) + emit("ensemble_supergraph", json_result, json=True) @sockets.on("split_by_entry_callsites", namespace="/") def split_by_entry_callsites(data): @@ -176,17 +189,30 @@ def split_by_entry_callsites(data): :return: networkx graph (JSON) """ LOGGER.debug("Split by entry: {}".format(data)) - nxg = self.callflow.request( - { - "name": "supergraph", - "groupBy": "module", - "datasets": data["datasets"], - "split_entry_module": data["selectedModule"], - } - ) - result = json_graph.node_link_data(nxg) - json_result = json.dumps(result) - emit("ensemble_supergraph", json_result, json=True) + if data["mode"] == "Single": + nxg = self.callflow.request_single( + { + "name": "supergraph", + "groupBy": "module", + "dataset": data["dataset"], + "split_entry_module": data["selectedModule"], + } + ) + result = json_graph.node_link_data(nxg) + json_result = json.dumps(result) + emit("single_supergraph", json_result, json=True) + elif data["mode"] == "Ensemble": + nxg = self.callflow.request_ensemble( + { + "name": "supergraph", + "groupBy": "module", + "datasets": data["datasets"], + "split_entry_module": data["selectedModule"], + } + ) + result = json_graph.node_link_data(nxg) + json_result = json.dumps(result) + emit("ensemble_supergraph", json_result, json=True) @sockets.on("split_by_callees", namespace="/") def split_by_callees(data): @@ -195,17 +221,31 @@ def split_by_callees(data): :return: networkx graph (JSON) """ LOGGER.debug("Split by callees: {}".format(data)) - nxg = self.callflow.request( - { - "name": "supergraph", - "groupBy": "module", - "datasets": data["datasets"], - "split_by_callees": data["selectedModule"], - } - ) - result = json_graph.node_link_data(nxg) - json_result = json.dumps(result) - emit("ensemble_supergraph", json_result, json=True) + if data["mode"] == "Single": + nxg = self.callflow.request_single( + { + "name": "supergraph", + "groupBy": "module", + "dataset": data["dataset"], + "split_by_callees": data["selectedModule"], + } + ) + result = json_graph.node_link_data(nxg) + json_result = json.dumps(result) + emit("single_supergraph", json_result, json=True) + + elif data["mode"] == "Ensemble": + nxg = self.callflow.request_ensemble( + { + "name": "supergraph", + "groupBy": "module", + "datasets": data["datasets"], + "split_by_callees": data["selectedModule"], + } + ) + result = json_graph.node_link_data(nxg) + json_result = json.dumps(result) + emit("ensemble_supergraph", json_result, json=True) def _request_handler_single(self): @sockets.on("single_callsite_data", namespace="/")