blob: 512aa95106ce8b40af79c3d70d6edecd8e365ef6 [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.ThroughputUnit;
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_THROUGHPUT_NULL;
48import static org.onosproject.drivers.server.gui.MetricType.THROUGHPUT;
49import static org.slf4j.LoggerFactory.getLogger;
Georgios Katsikas973a2652018-06-28 08:45:47 +020050
51/**
52 * Message handler for passing throughput data to the Web UI.
53 */
54public class ThroughputViewMessageHandler extends BaseViewMessageHandler {
55
56 private static final Logger log = getLogger(ThroughputViewMessageHandler.class);
57
58 private static final String THROUGHPUT_DATA_REQ = "throughputDataRequest";
59 private static final String THROUGHPUT_DATA_RESP = "throughputDataResponse";
60 private static final String THROUGHPUT_LABEL = "throughputs";
61
62 @Override
63 protected Collection<RequestHandler> createRequestHandlers() {
64 return ImmutableSet.of(new ThroughputMessageRequest());
65 }
66
Georgios Katsikas740d3282020-03-18 12:05:03 +010067 private final class ThroughputMessageRequest
68 extends BaseViewMessageHandler.ControlMessageRequest {
Georgios Katsikas973a2652018-06-28 08:45:47 +020069
70 private ThroughputMessageRequest() {
71 super(THROUGHPUT_DATA_REQ, THROUGHPUT_DATA_RESP, THROUGHPUT_LABEL);
72 }
73
74 @Override
75 protected String[] getSeries() {
Georgios Katsikas740d3282020-03-18 12:05:03 +010076 return createIndexedSeries(THROUGHPUT, 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, THROUGHPUT, 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 = populateThroughputDataHistory(deviceId, serverDev.numberOfCpus(), monStats);
101 }
Georgios Katsikas740d3282020-03-18 12:05:03 +0100102 checkNotNull(data, MSG_UI_DATA_THROUGHPUT_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, THROUGHPUT, 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 = populateThroughputData(deviceId, serverDev.numberOfCpus(), monStats);
137 }
Georgios Katsikas740d3282020-03-18 12:05:03 +0100138 checkNotNull(data, MSG_UI_DATA_THROUGHPUT_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(THROUGHPUT, 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 Throughput 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 throughput metrics to their values
166 */
167 private Map<Integer, Float> populateThroughputData(
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 Float value = null;
175 if ((stats.averageThroughput().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
176 value = stats.averageThroughput().get();
177 } else {
178 value = new Float(0);
179 }
180
181 // Unit conversion
182 ThroughputUnit throughputUnit = null;
183 if (stats.throughputUnit().isPresent()) {
184 throughputUnit = (ThroughputUnit) stats.throughputUnit().get();
185 } else {
186 throughputUnit = ThroughputUnit.BPS;
187 }
188 value = ThroughputUnit.toGbps(value, throughputUnit);
189
190 // Store it locally
191 addToCache(deviceId, length, index, value);
192
193 // And into the map
194 data.put(index, value);
195 }
196
197 return data;
198 }
199
200 /**
201 * Turn the monitoring data history into a
202 * data structure that can feed the Throughput UI memory.
203 *
204 * @param deviceId the device ID being monitored
205 * @param length the length of the array
206 * @param monStats a MonitoringStatistics object
207 * @return a map of throughput metrics to their arrays of values
208 */
209 private Map<Integer, Float[]> populateThroughputDataHistory(
210 DeviceId deviceId, int length, MonitoringStatistics monStats) {
Georgios Katsikas740d3282020-03-18 12:05:03 +0100211 Map<Integer, Float[]> data = initializeMapDataHistory(MAX_COLUMNS_NB);
Georgios Katsikas973a2652018-06-28 08:45:47 +0200212
213 for (CpuStatistics stats : monStats.cpuStatisticsAll()) {
214 int index = stats.id();
215
216 Float value = null;
217 if ((stats.averageThroughput().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
218 value = stats.averageThroughput().get();
219 } else {
220 value = new Float(0);
221 }
222
223 // Unit conversion
224 ThroughputUnit throughputUnit = null;
225 if (stats.throughputUnit().isPresent()) {
226 throughputUnit = (ThroughputUnit) stats.throughputUnit().get();
227 } else {
228 throughputUnit = ThroughputUnit.BPS;
229 }
230 value = ThroughputUnit.toGbps(value, throughputUnit);
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}