blob: 91105e911d8dbf1fc28858d21d5b46a7acdeb509 [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
46import static org.slf4j.LoggerFactory.getLogger;
47import static org.onosproject.drivers.server.gui.MetricType.THROUGHPUT;
48import static com.google.common.base.Preconditions.checkNotNull;
49
50/**
51 * Message handler for passing throughput data to the Web UI.
52 */
53public class ThroughputViewMessageHandler extends BaseViewMessageHandler {
54
55 private static final Logger log = getLogger(ThroughputViewMessageHandler.class);
56
57 private static final String THROUGHPUT_DATA_REQ = "throughputDataRequest";
58 private static final String THROUGHPUT_DATA_RESP = "throughputDataResponse";
59 private static final String THROUGHPUT_LABEL = "throughputs";
60
61 @Override
62 protected Collection<RequestHandler> createRequestHandlers() {
63 return ImmutableSet.of(new ThroughputMessageRequest());
64 }
65
66 private final class ThroughputMessageRequest extends BaseViewMessageHandler.ControlMessageRequest {
67
68 private ThroughputMessageRequest() {
69 super(THROUGHPUT_DATA_REQ, THROUGHPUT_DATA_RESP, THROUGHPUT_LABEL);
70 }
71
72 @Override
73 protected String[] getSeries() {
74 return createSeries(THROUGHPUT, 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, THROUGHPUT, 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 = populateThroughputDataHistory(deviceId, serverDev.numberOfCpus(), monStats);
99 }
100 checkNotNull(data, "No throughput 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, THROUGHPUT, 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 = populateThroughputData(deviceId, serverDev.numberOfCpus(), monStats);
135 }
136 checkNotNull(data, "No throughput 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(THROUGHPUT, 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 Throughput 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 throughput metrics to their values
164 */
165 private Map<Integer, Float> populateThroughputData(
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 Float value = null;
173 if ((stats.averageThroughput().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
174 value = stats.averageThroughput().get();
175 } else {
176 value = new Float(0);
177 }
178
179 // Unit conversion
180 ThroughputUnit throughputUnit = null;
181 if (stats.throughputUnit().isPresent()) {
182 throughputUnit = (ThroughputUnit) stats.throughputUnit().get();
183 } else {
184 throughputUnit = ThroughputUnit.BPS;
185 }
186 value = ThroughputUnit.toGbps(value, throughputUnit);
187
188 // Store it locally
189 addToCache(deviceId, length, index, value);
190
191 // And into the map
192 data.put(index, value);
193 }
194
195 return data;
196 }
197
198 /**
199 * Turn the monitoring data history into a
200 * data structure that can feed the Throughput UI memory.
201 *
202 * @param deviceId the device ID being monitored
203 * @param length the length of the array
204 * @param monStats a MonitoringStatistics object
205 * @return a map of throughput metrics to their arrays of values
206 */
207 private Map<Integer, Float[]> populateThroughputDataHistory(
208 DeviceId deviceId, int length, MonitoringStatistics monStats) {
209 Map<Integer, Float[]> data = initializeDataHistory(MAX_COLUMNS_NB);
210
211 for (CpuStatistics stats : monStats.cpuStatisticsAll()) {
212 int index = stats.id();
213
214 Float value = null;
215 if ((stats.averageThroughput().isPresent()) && (stats.load() > MIN_CPU_LOAD)) {
216 value = stats.averageThroughput().get();
217 } else {
218 value = new Float(0);
219 }
220
221 // Unit conversion
222 ThroughputUnit throughputUnit = null;
223 if (stats.throughputUnit().isPresent()) {
224 throughputUnit = (ThroughputUnit) stats.throughputUnit().get();
225 } else {
226 throughputUnit = ThroughputUnit.BPS;
227 }
228 value = ThroughputUnit.toGbps(value, throughputUnit);
229
230 // Store it locally
231 addToCache(deviceId, length, index, value);
232
233 LruCache<Float> loadCache = getDataHistory(deviceId, index);
234 if (loadCache == null) {
235 continue;
236 }
237 float[] floatArray = Floats.toArray(Arrays.asList(loadCache.values().toArray(new Float[0])));
238
239 // Fill the missing points
240 float[] filledLoadArray = fillData(floatArray, NUM_OF_DATA_POINTS);
241
242 // Set the data
243 data.put(index, ArrayUtils.toObject(filledLoadArray));
244 }
245
246 // Keep a timestamp
247 timestamp = System.currentTimeMillis();
248
249 return data;
250 }
251
252 }
253
254}