blob: 3e754e19f2645f910dba9090ba44fe20f2acca47 [file] [log] [blame]
Brian O'Connor6ccba962015-02-17 18:16:02 -08001/*
2 * Copyright 2015 Open Networking Laboratory
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 */
16package org.onosproject.intentperf;
17
18import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import com.google.common.collect.Sets;
21import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
Brian O'Connor6ccba962015-02-17 18:16:02 -080025import org.onlab.util.Counter;
26import org.onosproject.cluster.ClusterService;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.Device;
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080031import org.onosproject.net.MastershipRole;
Brian O'Connor6ccba962015-02-17 18:16:02 -080032import org.onosproject.net.PortNumber;
33import org.onosproject.net.device.DeviceService;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
38import org.onosproject.net.intent.Intent;
39import org.onosproject.net.intent.IntentEvent;
40import org.onosproject.net.intent.IntentListener;
41import org.onosproject.net.intent.IntentService;
42import org.onosproject.net.intent.Key;
43import org.onosproject.net.intent.PointToPointIntent;
44import org.slf4j.Logger;
45
46import java.util.Collections;
47import java.util.Iterator;
48import java.util.List;
49import java.util.Map;
50import java.util.Set;
51import java.util.Timer;
52import java.util.TimerTask;
53import java.util.concurrent.ExecutorService;
54import java.util.concurrent.Executors;
55import java.util.concurrent.TimeUnit;
56
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080057import static com.google.common.base.Preconditions.checkState;
Thomas Vachuska0249b532015-02-20 16:46:18 -080058import static java.lang.String.format;
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080059import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY;
Brian O'Connor6ccba962015-02-17 18:16:02 -080060import static org.onlab.util.Tools.delay;
61import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska0249b532015-02-20 16:46:18 -080062import static org.onosproject.net.intent.IntentEvent.Type.INSTALLED;
63import static org.onosproject.net.intent.IntentEvent.Type.WITHDRAWN;
Brian O'Connor6ccba962015-02-17 18:16:02 -080064import static org.slf4j.LoggerFactory.getLogger;
65
66/**
67 * Application to set up demos.
68 */
69@Component(immediate = true)
70public class IntentPerfInstaller {
71
72 private final Logger log = getLogger(getClass());
73
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080074 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -080075 protected CoreService coreService;
76
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080077 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -080078 protected IntentService intentService;
79
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080080 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -080081 protected ClusterService clusterService;
82
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080083 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -080084 protected DeviceService deviceService;
85
86 private ExecutorService worker;
87 private ApplicationId appId;
88 private Listener listener;
89 private Set<Intent> intents;
90 private Set<Intent> submitted;
91 private Set<Intent> withdrawn;
92 private boolean stopped;
93
94 private static final long REPORT_PERIOD = 5000L; //ms
95 private Timer reportTimer;
96
97 //FIXME make this configurable
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080098 private static final int NUM_KEYS = 10_000;
Brian O'Connor6ccba962015-02-17 18:16:02 -080099
100 @Activate
101 public void activate() {
102 String nodeId = clusterService.getLocalNode().ip().toString();
103 appId = coreService.registerApplication("org.onosproject.intentperf."
104 + nodeId);
105 intents = Sets.newHashSet();
106 submitted = Sets.newHashSet();
107 withdrawn = Sets.newHashSet();
108
109 worker = Executors.newFixedThreadPool(1, groupedThreads("onos/intent-perf", "worker"));
110 log.info("Started with Application ID {}", appId.id());
111 start(); //FIXME
112 }
113
114 @Deactivate
115 public void deactivate() {
116 stop();
117 log.info("Stopped");
118 }
119
120 public void start() {
121 // perhaps we want to prime before listening...
122 // we will need to discard the first few results for priming and warmup
123 listener = new Listener();
124 intentService.addListener(listener);
Thomas Vachuska0249b532015-02-20 16:46:18 -0800125
126 long delay = System.currentTimeMillis() % REPORT_PERIOD;
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800127 reportTimer = new Timer("onos-intent-perf-reporter");
Brian O'Connor6ccba962015-02-17 18:16:02 -0800128 reportTimer.scheduleAtFixedRate(new TimerTask() {
129 @Override
130 public void run() {
131 listener.report();
132 }
Thomas Vachuska0249b532015-02-20 16:46:18 -0800133 }, delay, REPORT_PERIOD);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800134
135 stopped = false;
136 worker.submit(() -> {
Thomas Vachuska0249b532015-02-20 16:46:18 -0800137 delay(2000); // take a breath to start
Brian O'Connor6ccba962015-02-17 18:16:02 -0800138 createIntents(NUM_KEYS, 2); //FIXME
139 prime();
140 while (!stopped) {
141 cycle();
Thomas Vachuska0249b532015-02-20 16:46:18 -0800142 delay(800); // take a breath
Brian O'Connor6ccba962015-02-17 18:16:02 -0800143 }
144 });
145
146 }
147
148 public void stop() {
149 if (listener != null) {
150 reportTimer.cancel();
151 intentService.removeListener(listener);
152 listener = null;
153 reportTimer = null;
154 }
155 stopped = true;
156 try {
157 worker.awaitTermination(5, TimeUnit.SECONDS);
158 } catch (InterruptedException e) {
159 log.warn("Failed to stop worker.");
160 }
161 }
162
163
164 private void cycle() {
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800165 long start = System.currentTimeMillis();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800166 subset(submitted).forEach(this::withdraw);
167 subset(withdrawn).forEach(this::submit);
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800168 long delta = System.currentTimeMillis() - start;
169 if (delta > 1000 || delta < 0) {
170 log.warn("Cycle took {} ms", delta);
171 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800172 }
173
174 private Iterable<Intent> subset(Set<Intent> intents) {
175 List<Intent> subset = Lists.newArrayList(intents);
176 Collections.shuffle(subset);
177 return subset.subList(0, subset.size() / 2);
178 }
179
180 private void submit(Intent intent) {
181 intentService.submit(intent);
182 submitted.add(intent);
183 withdrawn.remove(intent); //TODO could check result here...
184 }
185
186 private void withdraw(Intent intent) {
187 intentService.withdraw(intent);
188 withdrawn.add(intent);
189 submitted.remove(intent); //TODO could check result here...
190 }
191
192 private void createIntents(int numberOfKeys, int pathLength) {
Brian O'Connor6ccba962015-02-17 18:16:02 -0800193 Iterator<Device> deviceItr = deviceService.getAvailableDevices().iterator();
194
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800195 Device ingressDevice = null;
196 while (deviceItr.hasNext()) {
197 Device device = deviceItr.next();
198 if (deviceService.getRole(device.id()) == MastershipRole.MASTER) {
199 ingressDevice = device;
200 break;
201 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800202 }
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800203 checkState(ingressDevice != null, "There are no local devices");
Brian O'Connor6ccba962015-02-17 18:16:02 -0800204
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800205 for (int local = 0, i = 0; local < numberOfKeys; i++) {
Brian O'Connor6ccba962015-02-17 18:16:02 -0800206 Key key = Key.of(i, appId);
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800207 if (!intentService.isLocal(key)) {
208 continue;
209 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800210 TrafficSelector selector = DefaultTrafficSelector.builder().build();
211
212 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
213 //FIXME
214 ConnectPoint ingress = new ConnectPoint(ingressDevice.id(), PortNumber.portNumber(1));
215 ConnectPoint egress = new ConnectPoint(ingressDevice.id(), PortNumber.portNumber(2));
216
217 Intent intent = new PointToPointIntent(appId, key,
218 selector, treatment,
219 ingress, egress,
220 Collections.emptyList());
221 intents.add(intent);
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800222 local++;
223 if (i % 1000 == 0) {
224 log.info("Building intents... {} ({})", local, i);
225 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800226 }
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800227 log.info("Created {} intents", numberOfKeys);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800228 }
229
230 private void prime() {
231 int i = 0;
232 withdrawn.addAll(intents);
233 for (Intent intent : intents) {
234 submit(intent);
235 // only submit half of the intents to start
236 if (i++ >= intents.size() / 2) {
237 break;
238 }
239 }
240 }
241
242 class Listener implements IntentListener {
243
Thomas Vachuska0249b532015-02-20 16:46:18 -0800244 private final Map<IntentEvent.Type, Counter> counters;
245 private final Counter runningTotal = new Counter();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800246
247 public Listener() {
248 counters = initCounters();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800249 }
250
251 private Map<IntentEvent.Type, Counter> initCounters() {
252 Map<IntentEvent.Type, Counter> map = Maps.newHashMap();
253 for (IntentEvent.Type type : IntentEvent.Type.values()) {
254 map.put(type, new Counter());
255 }
256 return map;
257 }
258
259 @Override
260 public void event(IntentEvent event) {
261 if (event.subject().appId().equals(appId)) {
262 counters.get(event.type()).add(1);
263 }
264 }
265
266 public void report() {
267 StringBuilder stringBuilder = new StringBuilder();
Thomas Vachuska0249b532015-02-20 16:46:18 -0800268 Counter installed = counters.get(INSTALLED);
269 Counter withdrawn = counters.get(WITHDRAWN);
270 double current = installed.throughput() + withdrawn.throughput();
271 runningTotal.add(installed.total() + withdrawn.total());
Brian O'Connor6ccba962015-02-17 18:16:02 -0800272 for (IntentEvent.Type type : IntentEvent.Type.values()) {
273 stringBuilder.append(printCounter(type)).append("; ");
274 }
Thomas Vachuska0249b532015-02-20 16:46:18 -0800275 log.info("Throughput: OVERALL={}; CURRENT={}; {}",
276 format("%.2f", runningTotal.throughput()),
277 format("%.2f", current), stringBuilder);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800278 }
279
280 private String printCounter(IntentEvent.Type event) {
281 Counter counter = counters.get(event);
Thomas Vachuska0249b532015-02-20 16:46:18 -0800282 String result = format("%s=%.2f", event, counter.throughput());
Brian O'Connor6ccba962015-02-17 18:16:02 -0800283 counter.reset();
284 return result;
285 }
286 }
287}