Thomas Vachuska

GUI -- Fixed intent perf GUI styling.

Change-Id: I552d3a50f7f4dd5bb1df7115c15eb6a04f538378
...@@ -37,10 +37,8 @@ import java.util.HashMap; ...@@ -37,10 +37,8 @@ import java.util.HashMap;
37 import java.util.LinkedList; 37 import java.util.LinkedList;
38 import java.util.List; 38 import java.util.List;
39 import java.util.Map; 39 import java.util.Map;
40 -import java.util.concurrent.ExecutorService;
41 -import java.util.concurrent.Executors;
42 40
43 -import static org.onlab.util.Tools.groupedThreads; 41 +import static org.onlab.util.SharedExecutors.getPoolThreadExecutor;
44 import static org.slf4j.LoggerFactory.getLogger; 42 import static org.slf4j.LoggerFactory.getLogger;
45 43
46 /** 44 /**
...@@ -78,18 +76,13 @@ public class IntentPerfCollector { ...@@ -78,18 +76,13 @@ public class IntentPerfCollector {
78 private Map<NodeId, Integer> nodeToIndex; 76 private Map<NodeId, Integer> nodeToIndex;
79 77
80 private NodeId nodeId; 78 private NodeId nodeId;
81 - private ExecutorService messageHandlingExecutor;
82 79
83 @Activate 80 @Activate
84 public void activate() { 81 public void activate() {
85 nodeId = clusterService.getLocalNode().id(); 82 nodeId = clusterService.getLocalNode().id();
86 83
87 - // TODO: replace with shared executor
88 - messageHandlingExecutor = Executors.newSingleThreadExecutor(
89 - groupedThreads("onos/perf", "message-handler"));
90 -
91 communicationService.addSubscriber(SAMPLE, new InternalSampleCollector(), 84 communicationService.addSubscriber(SAMPLE, new InternalSampleCollector(),
92 - messageHandlingExecutor); 85 + getPoolThreadExecutor());
93 86
94 nodes = clusterService.getNodes().toArray(new ControllerNode[]{}); 87 nodes = clusterService.getNodes().toArray(new ControllerNode[]{});
95 Arrays.sort(nodes, (a, b) -> a.id().toString().compareTo(b.id().toString())); 88 Arrays.sort(nodes, (a, b) -> a.id().toString().compareTo(b.id().toString()));
...@@ -99,14 +92,13 @@ public class IntentPerfCollector { ...@@ -99,14 +92,13 @@ public class IntentPerfCollector {
99 nodeToIndex.put(nodes[i].id(), i); 92 nodeToIndex.put(nodes[i].id(), i);
100 } 93 }
101 94
102 - ui.setHeaders(getSampleHeaders());
103 clearSamples(); 95 clearSamples();
96 + ui.setCollector(this);
104 log.info("Started"); 97 log.info("Started");
105 } 98 }
106 99
107 @Deactivate 100 @Deactivate
108 public void deactivate() { 101 public void deactivate() {
109 - messageHandlingExecutor.shutdown();
110 communicationService.removeSubscriber(SAMPLE); 102 communicationService.removeSubscriber(SAMPLE);
111 log.info("Stopped"); 103 log.info("Stopped");
112 } 104 }
......
...@@ -156,7 +156,7 @@ public class IntentPerfInstaller { ...@@ -156,7 +156,7 @@ public class IntentPerfInstaller {
156 private ExecutorService workers; 156 private ExecutorService workers;
157 private ApplicationId appId; 157 private ApplicationId appId;
158 private Listener listener; 158 private Listener listener;
159 - private boolean stopped; 159 + private boolean stopped = true;
160 160
161 private Timer reportTimer; 161 private Timer reportTimer;
162 162
...@@ -247,14 +247,19 @@ public class IntentPerfInstaller { ...@@ -247,14 +247,19 @@ public class IntentPerfInstaller {
247 } 247 }
248 248
249 public void start() { 249 public void start() {
250 + if (stopped) {
251 + stopped = false;
250 communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, START.getBytes())); 252 communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, START.getBytes()));
251 startTestRun(); 253 startTestRun();
252 } 254 }
255 + }
253 256
254 public void stop() { 257 public void stop() {
258 + if (!stopped) {
255 communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, STOP.getBytes())); 259 communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, STOP.getBytes()));
256 stopTestRun(); 260 stopTestRun();
257 } 261 }
262 + }
258 263
259 private void logConfig(String prefix) { 264 private void logConfig(String prefix) {
260 log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}", 265 log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}",
...@@ -282,7 +287,6 @@ public class IntentPerfInstaller { ...@@ -282,7 +287,6 @@ public class IntentPerfInstaller {
282 } 287 }
283 288
284 private void stopTestRun() { 289 private void stopTestRun() {
285 - stopped = true;
286 if (reporterTask != null) { 290 if (reporterTask != null) {
287 reporterTask.cancel(); 291 reporterTask.cancel();
288 reporterTask = null; 292 reporterTask = null;
...@@ -293,6 +297,11 @@ public class IntentPerfInstaller { ...@@ -293,6 +297,11 @@ public class IntentPerfInstaller {
293 } catch (InterruptedException e) { 297 } catch (InterruptedException e) {
294 log.warn("Failed to stop worker", e); 298 log.warn("Failed to stop worker", e);
295 } 299 }
300 +
301 + sampleCollector.recordSample(0, 0);
302 + sampleCollector.recordSample(0, 0);
303 + stopped = true;
304 +
296 log.info("Stopped test run"); 305 log.info("Stopped test run");
297 } 306 }
298 307
......
...@@ -36,9 +36,7 @@ import org.onosproject.ui.UiView; ...@@ -36,9 +36,7 @@ import org.onosproject.ui.UiView;
36 import java.util.Collection; 36 import java.util.Collection;
37 import java.util.HashSet; 37 import java.util.HashSet;
38 import java.util.List; 38 import java.util.List;
39 -import java.util.Random;
40 import java.util.Set; 39 import java.util.Set;
41 -import java.util.TimerTask;
42 40
43 import static java.util.Collections.synchronizedSet; 41 import static java.util.Collections.synchronizedSet;
44 42
...@@ -58,25 +56,11 @@ public class IntentPerfUi { ...@@ -58,25 +56,11 @@ public class IntentPerfUi {
58 private UiExtension uiExtension = new UiExtension(views, this::newHandlers, 56 private UiExtension uiExtension = new UiExtension(views, this::newHandlers,
59 getClass().getClassLoader()); 57 getClass().getClassLoader());
60 58
61 - private List<String> headers = ImmutableList.of("One", "Two", "Three", "Four", "Five"); 59 + private IntentPerfCollector collector;
62 -
63 - private Random random = new Random();
64 - private TimerTask task;
65 60
66 @Activate 61 @Activate
67 protected void activate() { 62 protected void activate() {
68 uiExtensionService.register(uiExtension); 63 uiExtensionService.register(uiExtension);
69 -// task = new TimerTask() {
70 -// @Override
71 -// public void run() {
72 -// Sample sample = new Sample(System.currentTimeMillis(), headers.size());
73 -// for (int i = 0; i < headers.size(); i++) {
74 -// sample.data[i] = 25_000 + random.nextInt(20_000) - 5_000;
75 -// }
76 -// reportSample(sample);
77 -// }
78 -// };
79 -// SharedExecutors.getTimer().scheduleAtFixedRate(task, 1000, 1000);
80 } 64 }
81 65
82 @Deactivate 66 @Deactivate
...@@ -96,12 +80,12 @@ public class IntentPerfUi { ...@@ -96,12 +80,12 @@ public class IntentPerfUi {
96 } 80 }
97 81
98 /** 82 /**
99 - * Sets the headers for the subsequently reported samples. 83 + * Binds the sample collector.
100 * 84 *
101 - * @param headers list of headers for future samples 85 + * @param collector list of headers for future samples
102 */ 86 */
103 - public void setHeaders(List<String> headers) { 87 + public void setCollector(IntentPerfCollector collector) {
104 - this.headers = headers; 88 + this.collector = collector;
105 } 89 }
106 90
107 // Creates and returns session specific message handler. 91 // Creates and returns session specific message handler.
...@@ -122,22 +106,10 @@ public class IntentPerfUi { ...@@ -122,22 +106,10 @@ public class IntentPerfUi {
122 public void process(ObjectNode message) { 106 public void process(ObjectNode message) {
123 streamingEnabled = message.path("event").asText("unknown").equals("intentPerfStart"); 107 streamingEnabled = message.path("event").asText("unknown").equals("intentPerfStart");
124 if (streamingEnabled) { 108 if (streamingEnabled) {
125 - sendHeaders(); 109 + sendInitData();
126 } 110 }
127 } 111 }
128 112
129 - private void sendHeaders() {
130 - ArrayNode an = mapper.createArrayNode();
131 - for (String header : headers) {
132 - an.add(header);
133 - }
134 -
135 - ObjectNode sn = mapper.createObjectNode();
136 - sn.set("headers", an);
137 -
138 - connection().sendMessage("intentPerfHeaders", 0, sn);
139 - }
140 -
141 @Override 113 @Override
142 public void init(UiConnection connection, ServiceDirectory directory) { 114 public void init(UiConnection connection, ServiceDirectory directory) {
143 super.init(connection, directory); 115 super.init(connection, directory);
...@@ -152,18 +124,34 @@ public class IntentPerfUi { ...@@ -152,18 +124,34 @@ public class IntentPerfUi {
152 124
153 private void send(Sample sample) { 125 private void send(Sample sample) {
154 if (streamingEnabled) { 126 if (streamingEnabled) {
127 + connection().sendMessage("intentPerfSample", 0, sampleNode(sample));
128 + }
129 + }
130 +
131 + private void sendInitData() {
132 + ObjectNode rootNode = mapper.createObjectNode();
155 ArrayNode an = mapper.createArrayNode(); 133 ArrayNode an = mapper.createArrayNode();
156 - for (double d : sample.data) { 134 + ArrayNode sn = mapper.createArrayNode();
157 - an.add(d); 135 + rootNode.set("headers", an);
136 + rootNode.set("samples", sn);
137 +
138 + collector.getSampleHeaders().forEach(an::add);
139 + collector.getSamples().forEach(s -> sn.add(sampleNode(s)));
140 + connection().sendMessage("intentPerfInit", 0, rootNode);
158 } 141 }
159 142
160 - ObjectNode sn = mapper.createObjectNode(); 143 + private ObjectNode sampleNode(Sample sample) {
161 - sn.put("time", sample.time); 144 + ObjectNode sampleNode = mapper.createObjectNode();
162 - sn.set("data", an); 145 + ArrayNode an = mapper.createArrayNode();
146 + sampleNode.put("time", sample.time);
147 + sampleNode.set("data", an);
163 148
164 - connection().sendMessage("intentPerfSample", 0, sn); 149 + for (double d : sample.data) {
150 + an.add(d);
165 } 151 }
152 + return sampleNode;
166 } 153 }
154 +
167 } 155 }
168 156
169 } 157 }
......
1 -date,value,node
2 -00:55:15,68.38,node1
3 -00:55:15,55.61,node2
4 -00:55:15,74.00,node3
5 -00:55:30,74.20,node1
6 -00:55:30,77.60,node2
7 -00:55:30,74.80,node3
8 -00:55:45,74.60,node1
9 -00:55:45,72.80,node2
10 -00:55:45,77.00,node3
11 -00:56:00,73.60,node1
12 -00:56:00,75.00,node2
13 -00:56:00,76.98,node3
14 -00:56:15,75.82,node1
15 -00:56:15,75.40,node2
16 -00:56:15,76.00,node3
17 -00:56:30,75.60,node1
18 -00:56:30,74.59,node2
19 -00:56:30,74.01,node3
...\ No newline at end of file ...\ No newline at end of file
1 -key,value,date
2 -Group1,37,00:23:00
3 -Group2,12,00:23:00
4 -Group3,46,00:23:00
5 -Group1,32,00:23:05
6 -Group2,19,00:23:05
7 -Group3,42,00:23:05
8 -Group1,45,00:23:10
9 -Group2,16,00:23:10
10 -Group3,44,00:23:10
11 -Group1,24,00:23:15
12 -Group2,52,00:23:15
13 -Group3,64,00:23:15
14 -Group1,34,00:23:20
15 -Group2,62,00:23:20
16 -Group3,74,00:23:20
17 -Group1,34,00:23:25
18 -Group2,62,00:23:25
19 -Group3,74,00:23:25
...\ No newline at end of file ...\ No newline at end of file
...@@ -22,9 +22,8 @@ svg { ...@@ -22,9 +22,8 @@ svg {
22 font: 12px sans-serif; 22 font: 12px sans-serif;
23 } 23 }
24 24
25 -.line { 25 +.line,.lineTotal {
26 fill: none; 26 fill: none;
27 - stroke: #000;
28 stroke-width: 2px; 27 stroke-width: 2px;
29 } 28 }
30 29
...@@ -37,16 +36,20 @@ svg { ...@@ -37,16 +36,20 @@ svg {
37 36
38 .light .axis path, 37 .light .axis path,
39 .light .axis line, 38 .light .axis line,
39 +.light .lineTotal {
40 + stroke: #333;
41 +}
42 +
40 .light .axis text { 43 .light .axis text {
41 - stroke: #999; 44 + fill: #333;
42 } 45 }
43 46
44 .dark .axis path, 47 .dark .axis path,
45 .dark .axis line, 48 .dark .axis line,
46 -.dark .axis text { 49 +.dark .lineTotal {
47 stroke: #eee; 50 stroke: #eee;
48 } 51 }
49 52
50 -.axis text { 53 +.dark .axis text {
51 - stroke-width: 0.3; 54 + fill: #eee;
52 } 55 }
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
31 31
32 // ========================== 32 // ==========================
33 33
34 - function createGraph(h) { 34 + function createGraph(h, samples) {
35 var stopped = false, 35 var stopped = false,
36 n = 243, 36 n = 243,
37 duration = 750, 37 duration = 750,
...@@ -75,7 +75,27 @@ ...@@ -75,7 +75,27 @@
75 headers.forEach(function (h, li) { 75 headers.forEach(function (h, li) {
76 // Prime the data to match the headers and zero it out. 76 // Prime the data to match the headers and zero it out.
77 data[li] = d3.range(n).map(function() { return 0 }); 77 data[li] = d3.range(n).map(function() { return 0 });
78 - theSample[li] = 0; 78 +
79 + if (li < headers.length - 1) {
80 + samples.forEach(function (s, i) {
81 + var di = dataIndex(s.time);
82 + if (di >= 0) {
83 + data[li][di] = s.data[li];
84 + }
85 + });
86 +
87 + data[li].forEach(function (d, i) {
88 + if (!d && i > 0) {
89 + data[li][i] = data[li][i - 1];
90 + }
91 + });
92 + } else {
93 + data[li].forEach(function (t, i) {
94 + for (var si = 0; si < headers.length - 1; si++) {
95 + data[li][i] = data[si][i];
96 + }
97 + });
98 + }
79 99
80 // Create the lines 100 // Create the lines
81 lines[li] = d3.svg.line() 101 lines[li] = d3.svg.line()
...@@ -88,15 +108,24 @@ ...@@ -88,15 +108,24 @@
88 .attr("clip-path", "url(#intent-perf-clip)") 108 .attr("clip-path", "url(#intent-perf-clip)")
89 .append("path") 109 .append("path")
90 .datum(function () { return data[li]; }) 110 .datum(function () { return data[li]; })
91 - .attr("id", "line" + li) 111 + .attr("id", "line" + li);
92 - .style("stroke", lineColor(li)) 112 +
93 - .attr("class", "line"); 113 + if (li < headers.length - 1) {
114 + paths[li].attr("class", "line").style("stroke", lineColor(li));
115 + } else {
116 + paths[li].attr("class", "lineTotal");
117 + }
94 }); 118 });
95 119
120 + function dataIndex(time) {
121 + var delta = now.getTime() - time;
122 + var di = Math.round(n - 2 - (delta / duration));
123 + // $log.info('now=' + now.getTime() + '; then=' + time + '; delta=' + delta + '; di=' + di + ';');
124 + return di >= n || di < 0 ? -1 : di;
125 + }
126 +
96 function lineColor(li) { 127 function lineColor(li) {
97 - return li < headers.length - 1 ? 128 + return sus.cat7().getColor(li, false, ts.theme());
98 - sus.cat7().getColor(li, false, ts.theme()) :
99 - ts.theme() === 'light' ? '#333' : '#eee';
100 } 129 }
101 130
102 function tick() { 131 function tick() {
...@@ -130,13 +159,17 @@ ...@@ -130,13 +159,17 @@
130 function start() { 159 function start() {
131 stopped = false; 160 stopped = false;
132 headers.forEach(function (h, li) { 161 headers.forEach(function (h, li) {
133 - theSample[li] = 0; 162 + theSample[li] = data[li][n-1];
134 }); 163 });
135 tick(); 164 tick();
136 } 165 }
137 166
138 function stop() { 167 function stop() {
139 - stopped = true; 168 + headers.forEach(function (h, li) {
169 + theSample[li] = 0;
170 + });
171 + // Schedule delayed stop to allow 0s to render.
172 + setTimeout(function () { stopped = true; }, 1000);
140 } 173 }
141 174
142 function resize(dim) { 175 function resize(dim) {
...@@ -190,7 +223,7 @@ ...@@ -190,7 +223,7 @@
190 function createAndInitGraph(d) { 223 function createAndInitGraph(d) {
191 if (!graph) { 224 if (!graph) {
192 d.headers.push("total"); 225 d.headers.push("total");
193 - graph = createGraph(d.headers); 226 + graph = createGraph(d.headers, d.samples);
194 } 227 }
195 graph.start(); 228 graph.start();
196 } 229 }
...@@ -213,7 +246,7 @@ ...@@ -213,7 +246,7 @@
213 246
214 function createHandlerMap() { 247 function createHandlerMap() {
215 handlerMap = { 248 handlerMap = {
216 - intentPerfHeaders: createAndInitGraph, 249 + intentPerfInit: createAndInitGraph,
217 intentPerfSample: recordSample 250 intentPerfSample: recordSample
218 }; 251 };
219 } 252 }
......
1 -<!DOCTYPE html>
2 -<meta charset="utf-8">
3 -<style>
4 -
5 - svg {
6 - font: 10px sans-serif;
7 - }
8 -
9 - .line {
10 - fill: none;
11 - stroke: darkgreen;
12 - stroke-width: 2px;
13 - }
14 -
15 - .axis path,
16 - .axis line {
17 - fill: none;
18 - stroke: #999;
19 - stroke-width: 2px;
20 - shape-rendering: crispEdges;
21 - }
22 -
23 -</style>
24 -<body>
25 -<script src="http://d3js.org/d3.v3.min.js"></script>
26 -<script>
27 - (function () {
28 - var cs = 0,
29 - samples = [
30 - 89.53,
31 - 37515.81,
32 - 104609.6,
33 - 113105.11,
34 - 103194.74,
35 - 122151.63,
36 - 128623.9,
37 - 137325.33,
38 - 154897.31,
39 - 161235.07,
40 - 162025.4,
41 - 164902.64,
42 - 158196.26,
43 - 161072.44,
44 - 160792.54,
45 - 164692.44,
46 - 161979.74,
47 - 162137.4,
48 - 159325.19,
49 - 170465.44,
50 - 168186.46,
51 - 171152.34,
52 - 168221.02,
53 - 167440.73,
54 - 165003.39,
55 - 166855.18,
56 - 157268.79,
57 - 164087.54,
58 - 162265.21,
59 - 165990.16,
60 - 176364.01,
61 - 172064.07,
62 - 184872.24,
63 - 183249.8,
64 - 182282.47,
65 - 171475.11,
66 - 158880.58,
67 - 166016.69,
68 - 168233.16,
69 - 177759.92,
70 - 179742.87,
71 - 170819.44,
72 - 167577.73,
73 - 169479.9,
74 - 175544.89,
75 - 183792.01,
76 - 184689.52,
77 - 178503.87,
78 - 173219.27,
79 - 179085.49,
80 - 179700.54,
81 - 174281.17,
82 - 181353.08,
83 - 180173.14,
84 - 184093.16,
85 - 186011.5,
86 - 176952.79,
87 - 175319.2,
88 - 169001.05,
89 - 174545.12,
90 - 169156.29,
91 - 171804.3,
92 - 159155.54,
93 - 154709.96,
94 - 157263.97
95 - ],
96 - theSample,
97 - headers = [ "Whole", "Half", "Third" ];
98 -
99 - var n = 243,
100 - duration = 750,
101 - now = new Date(Date.now() - duration),
102 - data = [];
103 -
104 - headers.forEach(function (d, li) {
105 - data[li] = d3.range(n).map(function () { return 0; });
106 - });
107 -
108 - var margin = {top: 20, right: 100, bottom: 20, left: 100},
109 - width = 960 - margin.right,
110 - height = 512 - margin.top - margin.bottom;
111 -
112 - var x = d3.time.scale()
113 - .domain([now - (n - 2) * duration, now - duration])
114 - .range([0, width]);
115 -
116 - var y = d3.scale.linear()
117 - .domain([0, 200000])
118 - .range([height, 0]);
119 -
120 - var svg = d3.select("body").append("p").append("svg")
121 - .attr("width", width + margin.left + margin.right)
122 - .attr("height", height + margin.top + margin.bottom)
123 - .append("g")
124 - .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
125 -
126 - svg.append("defs").append("clipPath")
127 - .attr("id", "clip")
128 - .append("rect")
129 - .attr("width", width)
130 - .attr("height", height);
131 -
132 - var axis = svg.append("g")
133 - .attr("class", "x axis")
134 - .attr("transform", "translate(0," + height + ")")
135 - .call(x.axis = d3.svg.axis().scale(x).orient("bottom"));
136 -
137 - svg.append("g")
138 - .attr("class", "y axis")
139 - .call(d3.svg.axis().scale(y).orient("left"));
140 -
141 - svg.append("g")
142 - .attr("class", "y axis")
143 - .attr("transform", "translate(" + width + " ,0)")
144 - .call(d3.svg.axis().scale(y).orient("right"));
145 -
146 - var lines = [], paths = [];
147 - data.forEach(function (p, li) {
148 - lines[li]= d3.svg.line()
149 - .interpolate("basis")
150 - .x(function (d, i) {
151 - return x(now - (n - 1 - i) * duration);
152 - })
153 - .y(function (d, i) {
154 - return y(d);
155 - });
156 -
157 - paths[li] = svg.append("g")
158 - .attr("clip-path", "url(#clip)")
159 - .append("path")
160 - .datum(function () { return data[li]; })
161 - .attr("id", "line" + li)
162 - .attr("class", "line");
163 - });
164 -
165 - var transition = d3.select({}).transition()
166 - .duration(750)
167 - .ease("linear");
168 -
169 - function tick() {
170 - transition = transition.each(function () {
171 - // update the domains
172 - now = new Date();
173 - x.domain([now - (n - 2) * duration, now - duration]);
174 -
175 - data.forEach(function (d, li) {
176 - // push the new most recent sample onto the back
177 - d.push(theSample[li]);
178 -
179 - // redraw the line and slide it left
180 - paths[li].attr("d", lines[li]).attr("transform", null);
181 - paths[li].transition().attr("transform", "translate(" + x(now - (n - 1) * duration) + ")");
182 -
183 - // pop the old data point off the front
184 - d.shift();
185 - });
186 -
187 - // slide the x-axis left
188 - axis.call(x.axis);
189 -
190 - }).transition().each("start", tick);
191 - }
192 -
193 - function setSample() {
194 - var v = samples[cs++];
195 - theSample = [ v, v/2, v/3 ];
196 - }
197 -
198 - setSample();
199 - setInterval(setSample, 1000);
200 - tick();
201 -
202 - })()
203 -</script>
204 -</body>
205 -</html>