blob: 538a892f4a5ab5411d1ebdd4758f2f051db8f8a1 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
opletColor = {
"org.apache.edgent.metrics.oplets.CounterOp": "#c7c7c7",
"org.apache.edgent.metrics.oplets.RateMeter": "#1f77b4",
"org.apache.edgent.oplet.core.FanIn": "#aec7e8",
"org.apache.edgent.oplet.core.FanOut": "#ff7f0e",
"org.apache.edgent.oplet.core.Peek": "#ffbb78",
"org.apache.edgent.oplet.core.PeriodicSource": "#bcbd22",
"org.apache.edgent.oplet.core.Pipe": "#98df8a",
"org.apache.edgent.oplet.core.ProcessSource": "#d62728",
"org.apache.edgent.oplet.core.Sink": "#ff9896",
"org.apache.edgent.oplet.core.Source": "#9467bd",
"org.apache.edgent.oplet.core.Split": "#c5b0d5",
"org.apache.edgent.oplet.core.Union": "#c49c94",
"org.apache.edgent.oplet.functional.Filter": "#e377c2",
"org.apache.edgent.oplet.functional.Isolate": "#f7b6d2",
"org.apache.edgent.oplet.functional.Map": "#f2d979",
"org.apache.edgent.oplet.functional.Peek": "#dbdb8d",
"org.apache.edgent.oplet.functional.SupplierPeriodicSource": "#17becf",
"org.apache.edgent.oplet.functional.SupplierSource": "#9edae5",
"org.apache.edgent.oplet.plumbing.Isolate": "#79a7f2",
"org.apache.edgent.oplet.plumbing.PressureReliever": "#2ca02c",
"org.apache.edgent.oplet.plumbing.TextFileReader": "#c0f279",
"org.apache.edgent.oplet.plumbing.UnorderedIsolate": "#e279f2",
"org.apache.edgent.streamscope.oplets.StreamScope": "#c7c7c7"
};
colorMap = {};
addValuesToEdges = function(graph, counterMetrics) {
var edges = graph.edges;
var vertices = graph.vertices;
var max = d3.max(counterMetrics, function(cm){
return parseInt(cm.value, 10);
});
var quartile1 = parseInt(max * 0.25, 10);
if (!graph.edgeMap) {
// fwiw, at this time, graph is new object on every call so these
// are rebuilt every time. ugh.
graph.edgeMap = makeEdgeMap(edges); // edgeKey(edge) -> edge; {incoming,outgoing}EdgesKey(opId) -> edges[]
graph.vertexMap = makeVertexMap(vertices); // id -> vertex
graph.equivMetricEdgeMap = makeEquivMetricEdgeMap(graph, counterMetrics); // metricEdge -> equivEdges[]
}
// assign the counter metric value to the edge that has the oplet id as a source or target
// and set value in equivalent edges
counterMetrics.forEach(function(cm){
var edges = graph.edgeMap[incomingEdgesKey(cm.opId)];
if (edges === undefined) {
// EDGENT-20 TopologyTestBasic has cm with no incoming edges???
edges = [];
}
pushArray(edges, graph.edgeMap[outgoingEdgesKey(cm.opId)]);
edges.forEach(function(edge){
edge.value = cm.value;
setEquivalentMetricEdges(graph, edge);
});
});
// if there is no counter metric, assign it a mean value, along with a flag that says it is a derived value
edges.forEach(function(edge){
if (!edge.value) {
edge.value = quartile1;
edge.derived = true;
} else if (edge.value === "0") {
edge.value = 0.45;
edge.realValue = 0;
}
});
return graph;
};
// augment arr with arr2's items
function pushArray(arr, arr2) {
if (arr2) {
arr.push.apply(arr, arr2);
}
}
// edgeMap key for edge
function edgeKey(edge) {
return edge.sourceId + "," + edge.targetId;
}
// edgeMap key for all edges whose targetId === opId
function incomingEdgesKey(opId) {
return "*," + opId;
}
// edgeMap key for all edges whose sourceId === opId
function outgoingEdgesKey(opId) {
return opId + ",*";
}
// make edge map of:
// - edgeKey(edge) -> edge
// - incomingEdgesKey(edge.targetId) -> edge.targetId incoming edges[]
// - outgoingEdgesKey(edge.sourceId) -> edge.sourceId outgoing edges[]
//
function makeEdgeMap(edges) {
var edgeMap = {};
edges.forEach(function(edge){
edgeMap[edgeKey(edge)] = edge;
addToEdges(edgeMap, edge, incomingEdgesKey(edge.targetId));
addToEdges(edgeMap, edge, outgoingEdgesKey(edge.sourceId));
});
return edgeMap;
}
// add edge to edgeMap[key]'s edges[]
function addToEdges(edgeMap, edge, key) {
var edges = edgeMap[key];
if (edges == null) {
edges = [];
edgeMap[key] = edges;
}
edges.push(edge);
}
// make vertex map of opId -> vertex
function makeVertexMap(vertices) {
var vertexMap = {};
vertices.forEach(function(vertex){
vertexMap[vertex.id] = vertex;
});
return vertexMap;
}
// make edge map of:
// - cmOutputEdge -> equiv downstream edges[]
// - cmInputEdge -> equiv upstream edges[]
function makeEquivMetricEdgeMap(graph, counterMetrics) {
var map = {};
counterMetrics.forEach(function(cm){
// N.B. a non-injected cm (e.g., a RateMeter or CounterOp)
// may be present at the end of a flow - with no outgoing edges
var edges = graph.edgeMap[outgoingEdgesKey(cm.opId)];
if (edges) {
var edge = edges[0];
map[edgeKey(edge)] = collectEquivMetricEdges(graph, edge, true);
}
var edges = graph.edgeMap[incomingEdgesKey(cm.opId)];
if (edges) {
// EDGENT-20 TopologyTestBasic has cm with no incoming edges???
var edge = edges[0];
map[edgeKey(edge)] = collectEquivMetricEdges(graph, edge, false);
}
});
return map;
}
// traverse downstream/upstream from "edge" collecting "equivalent" edges.
// Traverses through non-counter-metric peek ops.
// Also includes a FanOut oplet's outputs when traversing downstream
// because the runtime doesn't add CounterOps to them.
// requires graph.edgeMap, graph.vertexMap
function collectEquivMetricEdges(graph, edge, isDownstream) {
var equivEdges = [];
var vertex = graph.vertexMap[isDownstream ? edge.targetId : edge.sourceId];
if (shouldTraverseVertex(vertex)) {
var key = isDownstream ? outgoingEdgesKey(vertex.id) : incomingEdgesKey(vertex.id);
var edges = graph.edgeMap[key];
pushArray(equivEdges, edges);
edges.forEach(function(e2){
pushArray(equivEdges, collectEquivMetricEdges(graph, e2, isDownstream));
});
}
else if (isDownstream
&& vertex.invocation.kind == "org.apache.edgent.oplet.core.FanOut") {
pushArray(equivEdges, graph.edgeMap[outgoingEdgesKey(vertex.id)]);
}
return equivEdges;
}
// set the metricEdge's value in all edges equivalent to it.
// requires graph.equivMetricEdgeMap
function setEquivalentMetricEdges(graph, metricEdge) {
var edges = graph.equivMetricEdgeMap[edgeKey(metricEdge)];
edges.forEach(function(edge){
edge.value = metricEdge.value;
});
}
function shouldTraverseVertex(vertex) {
// TODO need an oplet tag or something to generalize this
var kind = vertex.invocation.kind;
return kind === "org.apache.edgent.streamscope.oplets.StreamScope"
|| kind === "org.apache.edgent.oplet.functional.Peek"
// the following metric oplets are returned as "counter metrics" hence
// have their own counter metric value (a contiguous set of them
// should nominally have the same value)
// || kind === "org.apache.edgent.metrics.oplet.RateMeter"
// || kind === "org.apache.edgent.metrics.oplet.CounterOp"
// || kind === "org.apache.edgent.metrics.oplet.a-Histogram-Op"
// || kind === "org.apache.edgent.metrics.oplet.a-Timer-Op"
;
}
getVertexFillColor = function(layer, data, cMetrics) {
if (layer === "opletColor" || layer === "static") {
return opletColor[data.invocation.kind];
} else if (layer === "flow") {
var tupleValue = parseInt(data.value, 10);
var derived = data.derived ? true : false;
var isZero = data.realValue === 0 && d.value === 0.45 ? true : false;
var tupleBucketsIdx = getTupleCountBucketsIndex(cMetrics, tupleValue, derived, isZero);
var myScale = d3.scale.linear().domain([0,tupleBucketsIdx.buckets.length -1]).range(tupleColorRange);
if (data.invocation.kind.toUpperCase().endsWith("COUNTEROP")) {
return "#c7c7c7";
} else if (data.invocation.kind.toUpperCase().endsWith("STREAMSCOPE")) {
return "#c7c7c7";
} else {
return myScale(tupleBucketsIdx.bucketIdx);
}
} else {
return colorMap[data.id.toString()];
}
};
getFormattedTagLegend = function(tArray) {
var items = [];
tArray.forEach(function(t){
var obj = {};
obj.name = t;
if (t === MULTIPLE_TAGS_TEXT) {
obj.fill = MULTIPLE_TAGS_COLOR;
obj.stroke = MULTIPLE_TAGS_COLOR;
} else {
obj.fill = color20(t) === "#c7c7c7" ? "#008080" : color20(t);
obj.stroke = color20(t) === "#c7c7c7" ? "#008080" : color20(t);
}
items.push(obj);
});
return items;
};
getFormattedTupleLegend = function(metricBuckets, scale) {
var items = [];
var buckets = metricBuckets.buckets;
buckets.forEach(function(b){
var obj = {};
obj.name = b.name;
obj.fill = scale(b.id);
obj.stroke = scale(b.id);
obj.idx = b.id;
items.push(obj);
});
var sortFunction = function(a, b) {
if (a.idx < b.idx) {
return -1;
} else if (a.idx > b.idx) {
return 1;
} else {
return 0;
}
};
return items.sort(sortFunction);
};
getLegendText = function(layer, data) {
if (layer === "opletColor" || layer === "static") {
return parseOpletKind(data.invocation.kind);
} else {
return "";
}
};
parseOpletKind = function(kind) {
var returnName = kind;
var newNames = kind.split(".");
if (newNames.length > 1) {
returnName = newNames[newNames.length - 1];
returnName += " (";
for (var i = 0; i < newNames.length -1; i++) {
returnName += newNames[i] + ".";
}
returnName = returnName.substring(0, returnName.length -1);
returnName += ")";
}
return returnName;
};
getLegendColor = function(layer, d, cMetrics) {
return getVertexFillColor(layer, d, cMetrics);
};
setVertexColorByFlowRate = function() {
};
makeStaticFlowValues = function(numValues) {
var littleVal = 0.001;
var data = d3.range(numValues).map(function() {
return littleVal;
});
return data;
};
makeRandomFlowValues = function(numValues) {
var random = d3.random.normal(5000, 2000);
var data = d3.range(numValues).map(random);
return data;
};
hideElement = function(elementId){
var id = "#" + elementId;
d3.select(id).style("display", "none");
};
showElement = function(elementId) {
var id = "#" + elementId;
d3.select(id).style("display", "block");
};