blob: c76c97d97823a3c604433d3a303b35255cfe3fbb [file] [log] [blame]
Georgios Katsikas973a2652018-06-28 08:45:47 +02001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.drivers.server.gui;
18
19import com.fasterxml.jackson.databind.node.ObjectNode;
20import com.google.common.base.Strings;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
24import com.google.common.primitives.Floats;
25
26import org.onosproject.drivers.server.behavior.MonitoringStatisticsDiscovery;
27import org.onosproject.drivers.server.devices.RestServerSBDevice;
28import org.onosproject.drivers.server.stats.CpuStatistics;
29import org.onosproject.drivers.server.stats.MonitoringStatistics;
30import org.onosproject.drivers.server.stats.MonitoringUnit.LatencyUnit;
31import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.device.DeviceService;
34import org.onosproject.ui.RequestHandler;
35import org.onosproject.ui.chart.ChartModel;
36
37import org.apache.commons.lang3.ArrayUtils;
38import org.joda.time.LocalDateTime;
39import org.slf4j.Logger;
40
41import java.util.Arrays;
42import java.util.Collection;
43import java.util.Map;
44import java.util.Set;
45
46import static org.slf4j.LoggerFactory.getLogger;
47import static org.onosproject.drivers.server.gui.MetricType.LATENCY;
48import static com.google.common.base.Preconditions.checkNotNull;
49
50/**
51 * Message handler for passing latency data to the Web UI.
52 */
53public class LatencyViewMessageHandler extends BaseViewMessageHandler {
54
55 private static final Logger log = getLogger(LatencyViewMessageHandler.class);
56
57 private static final String LATENCY_DATA_REQ = "latencyDataRequest";
58 private static final String LATENCY_DATA_RESP = "latencyDataResponse";
59 private static final String LATENCY_LABEL = "latencys";
60
61 @Override
62 protected Collection<RequestHandler> createRequestHandlers() {
63 return ImmutableSet.of(new LatencyMessageRequest());
64 }
65
66 private final class LatencyMessageRequest extends BaseViewMessageHandler.ControlMessageRequest {
67
68 private LatencyMessageRequest() {
69 super(LATENCY_DATA_REQ, LATENCY_DATA_RESP, LATENCY_LABEL);
70 }
71
72 @Override
73 protected String[] getSeries() {
74 return createSeries(LATENCY, MAX_COLUMNS_NB);
75 }
76
77 @Override
78 protected void populateChart(ChartModel cm, ObjectNode payload) {
79 DeviceService ds = get(DeviceService.class);
80 if ((ds == null) || (ds.getAvailableDeviceCount() == 0)) {
81 fillDataWhenNoDevicePresent(cm, LATENCY, MAX_COLUMNS_NB);
82 return;
83 }
84
85 String uri = string(payload, "devId");
86
87 // Project only one device over time
88 if (!Strings.isNullOrEmpty(uri)) {
89 DeviceId deviceId = DeviceId.deviceId(uri);
90 RestServerSBDevice serverDev =
91 (RestServerSBDevice) basicDriver.getController().getDevice(deviceId);
92
93 Map<Integer, Float[]> data = null;
94 MonitoringStatistics monStats = serverDriver.getGlobalMonitoringStatistics(deviceId);
95 if (monStats == null) {
96 data = populateZeroDataHistory(deviceId, MAX_COLUMNS_NB);
97 } else {
98 data = populateLatencyDataHistory(deviceId, serverDev.numberOfCpus(), monStats);
99 }
100 checkNotNull(data, "No latency data history to visualize");
101
102 // Generate a timestamp
103 LocalDateTime ldt = new LocalDateTime(timestamp);
104
105 // Project the data
106 populateMetrics(cm, data, ldt, LATENCY, NUM_OF_DATA_POINTS);
107
108 Set<DeviceId> deviceIds = Sets.newHashSet();
109 for (Device device : ds.getAvailableDevices()) {
110 // Only devices that support this type of monitoring behaviour are considered
111 if (device.is(MonitoringStatisticsDiscovery.class) && serverDev.isActive()) {
112 deviceIds.add(device.id());
113 }
114 }
115
116 // Drop down list to select devices
117 attachDeviceList(cm, deviceIds);
118 } else {
119 for (Device device : ds.getAvailableDevices()) {
120 // Only devices that support this type of monitoring behaviour are considered
121 if (!device.is(MonitoringStatisticsDiscovery.class)) {
122 continue;
123 }
124
125 DeviceId deviceId = device.id();
126 RestServerSBDevice serverDev =
127 (RestServerSBDevice) basicDriver.getController().getDevice(deviceId);
128
129 Map<Integer, Float> data = null;
130 MonitoringStatistics monStats = serverDriver.getGlobalMonitoringStatistics(deviceId);
131 if (monStats == null) {
132 data = populateZeroData(deviceId, MAX_COLUMNS_NB);
133 } else {
134 data = populateLatencyData(deviceId, serverDev.numberOfCpus(), monStats);
135 }
136 checkNotNull(data, "No latency data to visualize");
137
138 // Map them to the CPU cores
139 Map<String, Object> local = Maps.newHashMap();
140 for (int i = 0; i < data.size(); i++) {
141 local.put(getLabel(LATENCY, i), data.get(i));
142 }
143
144 // Last piece of data is the device ID
145 if (serverDev.isActive()) {
146 local.put(LABEL, deviceId);
147 populateMetric(cm.addDataPoint(deviceId), local);
148 } else {
149 local.put(LABEL, "");
150 populateMetric(cm.addDataPoint(""), local);
151 }
152 }
153 }
154 }
155
156 /**
157 * Turn the current monitoring data into a data
158 * structure that can feed the Latency UI memory.
159 *
160 * @param deviceId the device ID being monitored
161 * @param length the length of the array
162 * @param monStats a MonitoringStatistics object
163 * @return a map of latency metrics to their values
164 */
165 private Map<Integer, Float> populateLatencyData(
166 DeviceId deviceId, int length, MonitoringStatistics monStats) {
167 Map<Integer, Float> data = initializeData(MAX_COLUMNS_NB);
168
169 for (CpuStatistics stats : monStats.cpuStatisticsAll()) {
170 int index = stats.id();
171
172 // TODO: Use min and max latency to plot bars plots with error bars
173 Float value = null;
174 if ((stats.averageLatency().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
175 value = stats.averageLatency().get();
176 } else {
177 value = new Float(0);
178 }
179
180 // Unit conversion
181 LatencyUnit latencyUnit = null;
182 if (stats.latencyUnit().isPresent()) {
183 latencyUnit = (LatencyUnit) stats.latencyUnit().get();
184 } else {
185 latencyUnit = LatencyUnit.NANO_SECOND;
186 }
187 value = LatencyUnit.toNano(value, latencyUnit);
188
189 // Store it locally
190 addToCache(deviceId, length, index, value);
191
192 // And into the map
193 data.put(index, value);
194 }
195
196 return data;
197 }
198
199 /**
200 * Turn the monitoring data history into a
201 * data structure that can feed the Latency UI memory.
202 *
203 * @param deviceId the device ID being monitored
204 * @param length the length of the array
205 * @param monStats a MonitoringStatistics object
206 * @return a map of latency metrics to their arrays of values
207 */
208 private Map<Integer, Float[]> populateLatencyDataHistory(
209 DeviceId deviceId, int length, MonitoringStatistics monStats) {
210 Map<Integer, Float[]> data = initializeDataHistory(MAX_COLUMNS_NB);
211
212 for (CpuStatistics stats : monStats.cpuStatisticsAll()) {
213 int index = stats.id();
214
215 // TODO: Use min and max latency to plot bars plots with error bars
216 Float value = null;
217 if ((stats.averageLatency().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
218 value = stats.averageLatency().get();
219 } else {
220 value = new Float(0);
221 }
222
223 // Unit conversion
224 LatencyUnit latencyUnit = null;
225 if (stats.latencyUnit().isPresent()) {
226 latencyUnit = (LatencyUnit) stats.latencyUnit().get();
227 } else {
228 latencyUnit = LatencyUnit.NANO_SECOND;
229 }
230 value = LatencyUnit.toNano(value, latencyUnit);
231
232 // Store it locally
233 addToCache(deviceId, length, index, value);
234
235 LruCache<Float> loadCache = getDataHistory(deviceId, index);
236 if (loadCache == null) {
237 continue;
238 }
239 float[] floatArray = Floats.toArray(Arrays.asList(loadCache.values().toArray(new Float[0])));
240
241 // Fill the missing points
242 float[] filledLoadArray = fillData(floatArray, NUM_OF_DATA_POINTS);
243
244 // Set the data
245 data.put(index, ArrayUtils.toObject(filledLoadArray));
246 }
247
248 // Keep a timestamp
249 timestamp = System.currentTimeMillis();
250
251 return data;
252 }
253
254 }
255
256}