blob: a1c29c3684f50fe5158f555207b9865d4c170ee7 [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
Georgios Katsikas973a2652018-06-28 08:45:47 +020046import static com.google.common.base.Preconditions.checkNotNull;
Georgios Katsikas740d3282020-03-18 12:05:03 +010047import static org.onosproject.drivers.server.Constants.MSG_UI_DATA_LATENCY_NULL;
48import static org.onosproject.drivers.server.gui.MetricType.LATENCY;
49import static org.slf4j.LoggerFactory.getLogger;
Georgios Katsikas973a2652018-06-28 08:45:47 +020050
51/**
52 * Message handler for passing latency data to the Web UI.
53 */
54public class LatencyViewMessageHandler extends BaseViewMessageHandler {
55
56 private static final Logger log = getLogger(LatencyViewMessageHandler.class);
57
58 private static final String LATENCY_DATA_REQ = "latencyDataRequest";
59 private static final String LATENCY_DATA_RESP = "latencyDataResponse";
60 private static final String LATENCY_LABEL = "latencys";
61
62 @Override
63 protected Collection<RequestHandler> createRequestHandlers() {
64 return ImmutableSet.of(new LatencyMessageRequest());
65 }
66
Georgios Katsikas740d3282020-03-18 12:05:03 +010067 private final class LatencyMessageRequest
68 extends BaseViewMessageHandler.ControlMessageRequest {
Georgios Katsikas973a2652018-06-28 08:45:47 +020069
70 private LatencyMessageRequest() {
71 super(LATENCY_DATA_REQ, LATENCY_DATA_RESP, LATENCY_LABEL);
72 }
73
74 @Override
75 protected String[] getSeries() {
Georgios Katsikas740d3282020-03-18 12:05:03 +010076 return createIndexedSeries(LATENCY, MAX_COLUMNS_NB);
Georgios Katsikas973a2652018-06-28 08:45:47 +020077 }
78
79 @Override
80 protected void populateChart(ChartModel cm, ObjectNode payload) {
81 DeviceService ds = get(DeviceService.class);
82 if ((ds == null) || (ds.getAvailableDeviceCount() == 0)) {
83 fillDataWhenNoDevicePresent(cm, LATENCY, MAX_COLUMNS_NB);
84 return;
85 }
86
87 String uri = string(payload, "devId");
88
89 // Project only one device over time
90 if (!Strings.isNullOrEmpty(uri)) {
91 DeviceId deviceId = DeviceId.deviceId(uri);
92 RestServerSBDevice serverDev =
93 (RestServerSBDevice) basicDriver.getController().getDevice(deviceId);
94
95 Map<Integer, Float[]> data = null;
96 MonitoringStatistics monStats = serverDriver.getGlobalMonitoringStatistics(deviceId);
97 if (monStats == null) {
Georgios Katsikas740d3282020-03-18 12:05:03 +010098 data = populateZeroMapDataHistory(deviceId, MAX_COLUMNS_NB);
Georgios Katsikas973a2652018-06-28 08:45:47 +020099 } else {
100 data = populateLatencyDataHistory(deviceId, serverDev.numberOfCpus(), monStats);
101 }
Georgios Katsikas740d3282020-03-18 12:05:03 +0100102 checkNotNull(data, MSG_UI_DATA_LATENCY_NULL);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200103
104 // Generate a timestamp
105 LocalDateTime ldt = new LocalDateTime(timestamp);
106
107 // Project the data
Georgios Katsikas740d3282020-03-18 12:05:03 +0100108 populateMapMetrics(cm, data, ldt, LATENCY, NUM_OF_DATA_POINTS);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200109
110 Set<DeviceId> deviceIds = Sets.newHashSet();
111 for (Device device : ds.getAvailableDevices()) {
112 // Only devices that support this type of monitoring behaviour are considered
113 if (device.is(MonitoringStatisticsDiscovery.class) && serverDev.isActive()) {
114 deviceIds.add(device.id());
115 }
116 }
117
118 // Drop down list to select devices
119 attachDeviceList(cm, deviceIds);
120 } else {
121 for (Device device : ds.getAvailableDevices()) {
122 // Only devices that support this type of monitoring behaviour are considered
123 if (!device.is(MonitoringStatisticsDiscovery.class)) {
124 continue;
125 }
126
127 DeviceId deviceId = device.id();
128 RestServerSBDevice serverDev =
129 (RestServerSBDevice) basicDriver.getController().getDevice(deviceId);
130
131 Map<Integer, Float> data = null;
132 MonitoringStatistics monStats = serverDriver.getGlobalMonitoringStatistics(deviceId);
133 if (monStats == null) {
Georgios Katsikas740d3282020-03-18 12:05:03 +0100134 data = populateZeroMapData(deviceId, MAX_COLUMNS_NB);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200135 } else {
136 data = populateLatencyData(deviceId, serverDev.numberOfCpus(), monStats);
137 }
Georgios Katsikas740d3282020-03-18 12:05:03 +0100138 checkNotNull(data, MSG_UI_DATA_LATENCY_NULL);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200139
140 // Map them to the CPU cores
141 Map<String, Object> local = Maps.newHashMap();
142 for (int i = 0; i < data.size(); i++) {
Georgios Katsikas740d3282020-03-18 12:05:03 +0100143 local.put(getIndexedLabel(LATENCY, i), data.get(i));
Georgios Katsikas973a2652018-06-28 08:45:47 +0200144 }
145
146 // Last piece of data is the device ID
147 if (serverDev.isActive()) {
148 local.put(LABEL, deviceId);
149 populateMetric(cm.addDataPoint(deviceId), local);
150 } else {
151 local.put(LABEL, "");
152 populateMetric(cm.addDataPoint(""), local);
153 }
154 }
155 }
156 }
157
158 /**
159 * Turn the current monitoring data into a data
160 * structure that can feed the Latency UI memory.
161 *
162 * @param deviceId the device ID being monitored
163 * @param length the length of the array
164 * @param monStats a MonitoringStatistics object
165 * @return a map of latency metrics to their values
166 */
167 private Map<Integer, Float> populateLatencyData(
168 DeviceId deviceId, int length, MonitoringStatistics monStats) {
Georgios Katsikas740d3282020-03-18 12:05:03 +0100169 Map<Integer, Float> data = initializeMapData(MAX_COLUMNS_NB);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200170
171 for (CpuStatistics stats : monStats.cpuStatisticsAll()) {
172 int index = stats.id();
173
174 // TODO: Use min and max latency to plot bars plots with error bars
175 Float value = null;
176 if ((stats.averageLatency().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
177 value = stats.averageLatency().get();
178 } else {
179 value = new Float(0);
180 }
181
182 // Unit conversion
183 LatencyUnit latencyUnit = null;
184 if (stats.latencyUnit().isPresent()) {
185 latencyUnit = (LatencyUnit) stats.latencyUnit().get();
186 } else {
187 latencyUnit = LatencyUnit.NANO_SECOND;
188 }
189 value = LatencyUnit.toNano(value, latencyUnit);
190
191 // Store it locally
192 addToCache(deviceId, length, index, value);
193
194 // And into the map
195 data.put(index, value);
196 }
197
198 return data;
199 }
200
201 /**
202 * Turn the monitoring data history into a
203 * data structure that can feed the Latency UI memory.
204 *
205 * @param deviceId the device ID being monitored
206 * @param length the length of the array
207 * @param monStats a MonitoringStatistics object
208 * @return a map of latency metrics to their arrays of values
209 */
210 private Map<Integer, Float[]> populateLatencyDataHistory(
211 DeviceId deviceId, int length, MonitoringStatistics monStats) {
Georgios Katsikas740d3282020-03-18 12:05:03 +0100212 Map<Integer, Float[]> data = initializeMapDataHistory(MAX_COLUMNS_NB);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200213
214 for (CpuStatistics stats : monStats.cpuStatisticsAll()) {
215 int index = stats.id();
216
217 // TODO: Use min and max latency to plot bars plots with error bars
218 Float value = null;
219 if ((stats.averageLatency().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
220 value = stats.averageLatency().get();
221 } else {
222 value = new Float(0);
223 }
224
225 // Unit conversion
226 LatencyUnit latencyUnit = null;
227 if (stats.latencyUnit().isPresent()) {
228 latencyUnit = (LatencyUnit) stats.latencyUnit().get();
229 } else {
230 latencyUnit = LatencyUnit.NANO_SECOND;
231 }
232 value = LatencyUnit.toNano(value, latencyUnit);
233
234 // Store it locally
235 addToCache(deviceId, length, index, value);
236
237 LruCache<Float> loadCache = getDataHistory(deviceId, index);
238 if (loadCache == null) {
239 continue;
240 }
241 float[] floatArray = Floats.toArray(Arrays.asList(loadCache.values().toArray(new Float[0])));
242
243 // Fill the missing points
244 float[] filledLoadArray = fillData(floatArray, NUM_OF_DATA_POINTS);
245
246 // Set the data
247 data.put(index, ArrayUtils.toObject(filledLoadArray));
248 }
249
250 // Keep a timestamp
251 timestamp = System.currentTimeMillis();
252
253 return data;
254 }
255
256 }
257
258}