blob: 5c8a015f3dc20fd6346c06ee4c0d472352ca3bc8 [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
Brian O'Connor87ba7a72015-03-11 14:40:09 -070018import com.google.common.collect.ArrayListMultimap;
Brian O'Connor6ccba962015-02-17 18:16:02 -080019import com.google.common.collect.Lists;
20import com.google.common.collect.Maps;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070021import com.google.common.collect.Multimap;
Brian O'Connor6ccba962015-02-17 18:16:02 -080022import com.google.common.collect.Sets;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070023import org.apache.commons.lang.math.RandomUtils;
Brian O'Connor6ccba962015-02-17 18:16:02 -080024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070027import org.apache.felix.scr.annotations.Property;
Brian O'Connor6ccba962015-02-17 18:16:02 -080028import org.apache.felix.scr.annotations.Reference;
Brian O'Connorb9a91c12015-03-10 11:19:50 -070029import org.onlab.packet.MacAddress;
Brian O'Connor6ccba962015-02-17 18:16:02 -080030import org.onlab.util.Counter;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070031import org.onosproject.cfg.ComponentConfigService;
Brian O'Connor6ccba962015-02-17 18:16:02 -080032import org.onosproject.cluster.ClusterService;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070033import org.onosproject.cluster.ControllerNode;
34import org.onosproject.cluster.NodeId;
Brian O'Connor6ccba962015-02-17 18:16:02 -080035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070037import org.onosproject.mastership.MastershipService;
Brian O'Connor6ccba962015-02-17 18:16:02 -080038import org.onosproject.net.ConnectPoint;
39import org.onosproject.net.Device;
40import org.onosproject.net.PortNumber;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
46import org.onosproject.net.intent.Intent;
47import org.onosproject.net.intent.IntentEvent;
48import org.onosproject.net.intent.IntentListener;
49import org.onosproject.net.intent.IntentService;
50import org.onosproject.net.intent.Key;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070051import org.onosproject.net.intent.PartitionService;
Brian O'Connor6ccba962015-02-17 18:16:02 -080052import org.onosproject.net.intent.PointToPointIntent;
53import org.slf4j.Logger;
54
Brian O'Connor87ba7a72015-03-11 14:40:09 -070055import java.util.ArrayList;
Brian O'Connor6ccba962015-02-17 18:16:02 -080056import java.util.Collections;
Brian O'Connor6ccba962015-02-17 18:16:02 -080057import java.util.List;
58import java.util.Map;
59import java.util.Set;
60import java.util.Timer;
61import java.util.TimerTask;
62import java.util.concurrent.ExecutorService;
63import java.util.concurrent.Executors;
64import java.util.concurrent.TimeUnit;
Brian O'Connor87ba7a72015-03-11 14:40:09 -070065import java.util.stream.Collectors;
Brian O'Connor6ccba962015-02-17 18:16:02 -080066
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080067import static com.google.common.base.Preconditions.checkState;
Thomas Vachuska0249b532015-02-20 16:46:18 -080068import static java.lang.String.format;
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -080069import static java.lang.System.currentTimeMillis;
Brian O'Connorbcfeadb2015-02-19 21:50:01 -080070import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY;
Brian O'Connor6ccba962015-02-17 18:16:02 -080071import static org.onlab.util.Tools.delay;
72import static org.onlab.util.Tools.groupedThreads;
Brian O'Connor36ef71a2015-02-24 12:05:01 -080073import static org.onosproject.net.intent.IntentEvent.Type.*;
Brian O'Connor6ccba962015-02-17 18:16:02 -080074import static org.slf4j.LoggerFactory.getLogger;
75
76/**
Brian O'Connor36ef71a2015-02-24 12:05:01 -080077 * Application to test sustained intent throughput.
Brian O'Connor6ccba962015-02-17 18:16:02 -080078 */
79@Component(immediate = true)
80public class IntentPerfInstaller {
81
82 private final Logger log = getLogger(getClass());
83
Brian O'Connor87ba7a72015-03-11 14:40:09 -070084 private static final int DEFAULT_NUM_WORKERS = 1;
85
86 private static final int DEFAULT_NUM_KEYS = 40_000;
87 private static final int DEFAULT_GOAL_CYCLE_PERIOD = 1_000; //ms
88
89 private static final int DEFAULT_NUM_NEIGHBORS = 0;
90
91 private static final int START_DELAY = 5_000; // ms
92 private static final int REPORT_PERIOD = 5_000; //ms
93
94 //FIXME add path length
95
96 @Property(name = "numKeys", intValue = DEFAULT_NUM_KEYS,
97 label = "Number of keys (i.e. unique intents) to generate per instance")
98 private int numKeys = DEFAULT_NUM_KEYS;
99
100 //TODO implement numWorkers property
101// @Property(name = "numThreads", intValue = DEFAULT_NUM_WORKERS,
102// label = "Number of installer threads per instance")
103// private int numWokers = DEFAULT_NUM_WORKERS;
104
105 @Property(name = "cyclePeriod", intValue = DEFAULT_GOAL_CYCLE_PERIOD,
106 label = "Goal for cycle period (in ms)")
107 private int cyclePeriod = DEFAULT_GOAL_CYCLE_PERIOD;
108
109 @Property(name = "numNeighbors", intValue = DEFAULT_NUM_NEIGHBORS,
110 label = "Number of neighbors to generate intents for")
111 private int numNeighbors = DEFAULT_NUM_NEIGHBORS;
112
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800113 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -0800114 protected CoreService coreService;
115
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800116 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -0800117 protected IntentService intentService;
118
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800119 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -0800120 protected ClusterService clusterService;
121
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800122 @Reference(cardinality = MANDATORY_UNARY)
Brian O'Connor6ccba962015-02-17 18:16:02 -0800123 protected DeviceService deviceService;
124
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700125 @Reference(cardinality = MANDATORY_UNARY)
126 protected MastershipService mastershipService;
127
128 @Reference(cardinality = MANDATORY_UNARY)
129 protected PartitionService partitionService;
130
131 @Reference(cardinality = MANDATORY_UNARY)
132 protected ComponentConfigService configService;
133
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800134 private ExecutorService workers;
Brian O'Connor6ccba962015-02-17 18:16:02 -0800135 private ApplicationId appId;
136 private Listener listener;
Brian O'Connor6ccba962015-02-17 18:16:02 -0800137 private boolean stopped;
138
Brian O'Connor6ccba962015-02-17 18:16:02 -0800139 private Timer reportTimer;
140
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800141 // FIXME this variable isn't shared properly between multiple worker threads
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800142 private int lastKey = 0;
Brian O'Connor6ccba962015-02-17 18:16:02 -0800143
144 @Activate
145 public void activate() {
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700146 configService.registerProperties(getClass());
147
Brian O'Connor6ccba962015-02-17 18:16:02 -0800148 String nodeId = clusterService.getLocalNode().ip().toString();
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800149 appId = coreService.registerApplication("org.onosproject.intentperf." + nodeId);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800150
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800151 reportTimer = new Timer("onos-intent-perf-reporter");
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700152 workers = Executors.newFixedThreadPool(DEFAULT_NUM_WORKERS, groupedThreads("onos/intent-perf", "worker-%d"));
153
154
155 // disable flow backups for testing
156 log.info("flow props: {}",
157 configService.getProperties("org.onosproject.store.flow.impl.DistributedFlowRuleStore"));
158 configService.setProperty("org.onosproject.store.flow.impl.DistributedFlowRuleStore",
159 "backupEnabled", "false");
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800160
161 // Schedule delayed start
162 reportTimer.schedule(new TimerTask() {
163 @Override
164 public void run() {
165 start();
166 }
167 }, START_DELAY);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800168 }
169
170 @Deactivate
171 public void deactivate() {
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700172 configService.unregisterProperties(getClass(), false);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800173 stop();
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700174 }
175
176 //FIXME add modified
177
178 private void logConfig(String prefix) {
179 log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}",
180 prefix, appId.id(), numKeys, cyclePeriod, numNeighbors);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800181 }
182
183 public void start() {
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700184 // adjust numNeighbors and generate list of neighbors
185 numNeighbors = Math.min(clusterService.getNodes().size() - 1, numNeighbors);
186
Brian O'Connor6ccba962015-02-17 18:16:02 -0800187 // perhaps we want to prime before listening...
188 // we will need to discard the first few results for priming and warmup
189 listener = new Listener();
190 intentService.addListener(listener);
Thomas Vachuska0249b532015-02-20 16:46:18 -0800191
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800192 // Schedule reporter task on report period boundary
Brian O'Connor6ccba962015-02-17 18:16:02 -0800193 reportTimer.scheduleAtFixedRate(new TimerTask() {
194 @Override
195 public void run() {
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800196 //adjustRates(); // FIXME we currently adjust rates in the cycle thread
Brian O'Connor6ccba962015-02-17 18:16:02 -0800197 listener.report();
198 }
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800199 }, REPORT_PERIOD - currentTimeMillis() % REPORT_PERIOD, REPORT_PERIOD);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800200
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800201 // Submit workers
Brian O'Connor6ccba962015-02-17 18:16:02 -0800202 stopped = false;
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700203 for (int i = 0; i < DEFAULT_NUM_WORKERS; i++) {
204 workers.submit(new Submitter(createIntents(numKeys, /*FIXME*/ 2, lastKey)));
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800205 }
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700206 logConfig("Started");
Brian O'Connor6ccba962015-02-17 18:16:02 -0800207 }
208
209 public void stop() {
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700210 stopped = true;
Brian O'Connor6ccba962015-02-17 18:16:02 -0800211 if (listener != null) {
212 reportTimer.cancel();
213 intentService.removeListener(listener);
214 listener = null;
215 reportTimer = null;
216 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800217 try {
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800218 workers.awaitTermination(5, TimeUnit.SECONDS);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800219 } catch (InterruptedException e) {
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800220 log.warn("Failed to stop worker", e);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800221 }
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700222 log.info("Stopped");
223 }
224
225 private List<NodeId> getNeighbors() {
226 List<NodeId> nodes = clusterService.getNodes().stream()
227 .map(ControllerNode::id)
228 .collect(Collectors.toCollection(ArrayList::new));
229 // sort neighbors by id
230 Collections.sort(nodes, (node1, node2) ->
231 node1.toString().compareTo(node2.toString()));
232 // rotate the local node to index 0
233 Collections.rotate(nodes, -1 * nodes.indexOf(clusterService.getLocalNode().id()));
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700234 log.debug("neighbors (raw): {}", nodes); //TODO remove
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700235 // generate the sub-list that will contain local node and selected neighbors
236 nodes = nodes.subList(0, numNeighbors + 1);
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700237 log.debug("neighbors: {}", nodes); //TODO remove
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700238 return nodes;
239 }
240
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700241 private Intent createIntent(Key key, long mac, NodeId node, Multimap<NodeId, Device> devices) {
242 // choose a random device for which this node is master
243 List<Device> deviceList = devices.get(node).stream().collect(Collectors.toList());
244 Device device = deviceList.get(RandomUtils.nextInt(deviceList.size()));
245
246 //FIXME we currently ignore the path length and always use the same device
247 TrafficSelector selector = DefaultTrafficSelector.builder()
248 .matchEthDst(MacAddress.valueOf(mac)).build();
249 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
250 ConnectPoint ingress = new ConnectPoint(device.id(), PortNumber.portNumber(1));
251 ConnectPoint egress = new ConnectPoint(device.id(), PortNumber.portNumber(2));
252
253 return new PointToPointIntent(appId, key,
254 selector, treatment,
255 ingress, egress,
256 Collections.emptyList(),
257 Intent.DEFAULT_INTENT_PRIORITY);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800258 }
259
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800260 /**
261 * Creates a specified number of intents for testing purposes.
262 *
263 * @param numberOfKeys number of intents
264 * @param pathLength path depth
265 * @param firstKey first key to attempt
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700266 * @return set of intents
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800267 */
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700268 private Set<Intent> createIntents(int numberOfKeys, int pathLength, int firstKey) {
269 //Set<Intent> result = new HashSet<>();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800270
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700271 List<NodeId> neighbors = getNeighbors();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800272
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700273 Multimap<NodeId, Device> devices = ArrayListMultimap.create();
274 deviceService.getAvailableDevices().forEach(device ->
275 devices.put(mastershipService.getMasterFor(device.id()), device));
276
277 // ensure that we have at least one device per neighbor
278 neighbors.forEach(node ->
279 checkState(devices.get(node).size() > 0,
280 "There are no devices for {}", node));
281
282
283 // TODO pull this outside so that createIntent can use it
284 // prefix based on node id for keys generated on this instance
285 long keyPrefix = ((long) clusterService.getLocalNode().ip().getIp4Address().toInt()) << 32;
286
287 int maxKeysPerNode = (int) Math.ceil((double) numberOfKeys / neighbors.size());
288 Multimap<NodeId, Intent> intents = ArrayListMultimap.create();
289
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800290 for (int count = 0, k = firstKey; count < numberOfKeys; k++) {
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700291 Key key = Key.of(keyPrefix + k, appId);
292
293 NodeId leader = partitionService.getLeader(key);
294 if (!neighbors.contains(leader) || intents.get(leader).size() >= maxKeysPerNode) {
295 // Bail if we are not sending to this node or we have enough for this node
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800296 continue;
297 }
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700298 intents.put(leader, createIntent(key, keyPrefix + k, leader, devices));
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800299
300 // Bump up the counter and remember this as the last key used.
301 count++;
302 lastKey = k;
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700303 if (count % 1000 == 0) {
304 log.info("Building intents... {} (attempt: {})", count, lastKey);
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800305 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800306 }
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700307 checkState(intents.values().size() == numberOfKeys,
308 "Generated wrong number of intents");
Brian O'Connorbcfeadb2015-02-19 21:50:01 -0800309 log.info("Created {} intents", numberOfKeys);
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700310 intents.keySet().forEach(node -> log.info("\t{}\t{}", node, intents.get(node).size()));
311
312 return Sets.newHashSet(intents.values());
Brian O'Connor6ccba962015-02-17 18:16:02 -0800313 }
314
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800315 // Submits intent operations.
316 final class Submitter implements Runnable {
317
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800318 private long lastDuration;
319 private int lastCount;
320
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800321 private Set<Intent> intents = Sets.newHashSet();
322 private Set<Intent> submitted = Sets.newHashSet();
323 private Set<Intent> withdrawn = Sets.newHashSet();
324
325 private Submitter(Set<Intent> intents) {
326 this.intents = intents;
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700327 lastCount = numKeys / 4;
328 lastDuration = 1_000; // 1 second
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800329 }
330
331 @Override
332 public void run() {
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800333 prime();
334 while (!stopped) {
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700335 try {
336 cycle();
337 } catch (Exception e) {
338 log.warn("Exception during cycle", e);
339 }
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800340 }
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700341 clear();
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800342 }
343
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800344 private Iterable<Intent> subset(Set<Intent> intents) {
345 List<Intent> subset = Lists.newArrayList(intents);
346 Collections.shuffle(subset);
347 return subset.subList(0, lastCount);
348 }
349
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800350 // Submits the specified intent.
351 private void submit(Intent intent) {
352 intentService.submit(intent);
353 submitted.add(intent);
354 withdrawn.remove(intent); //TODO could check result here...
355 }
356
357 // Withdraws the specified intent.
358 private void withdraw(Intent intent) {
359 intentService.withdraw(intent);
360 withdrawn.add(intent);
361 submitted.remove(intent); //TODO could check result here...
362 }
363
364 // Primes the cycle.
365 private void prime() {
366 int i = 0;
367 withdrawn.addAll(intents);
368 for (Intent intent : intents) {
369 submit(intent);
370 // only submit half of the intents to start
371 if (i++ >= intents.size() / 2) {
372 break;
373 }
374 }
375 }
376
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700377 private void clear() {
378 submitted.forEach(this::withdraw);
379 }
380
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800381 // Runs a single operation cycle.
382 private void cycle() {
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800383 //TODO consider running without rate adjustment
384 adjustRates();
385
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800386 long start = currentTimeMillis();
387 subset(submitted).forEach(this::withdraw);
388 subset(withdrawn).forEach(this::submit);
389 long delta = currentTimeMillis() - start;
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800390
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700391 if (delta > cyclePeriod * 3 || delta < 0) {
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800392 log.warn("Cycle took {} ms", delta);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800393 }
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800394
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700395 int difference = cyclePeriod - (int) delta;
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800396 if (difference > 0) {
397 delay(difference);
398 }
399
400 lastDuration = delta;
401 }
402
403 int cycleCount = 0;
404 private void adjustRates() {
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700405
406 int addDelta = Math.max(1000 - cycleCount, 10);
407 double multRatio = Math.min(0.8 + cycleCount * 0.0002, 0.995);
408
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800409 //FIXME need to iron out the rate adjustment
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700410 //FIXME we should taper the adjustments over time
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700411 //FIXME don't just use the lastDuration, take an average
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800412 if (++cycleCount % 5 == 0) { //TODO: maybe use a timer (we should do this every 5-10 sec)
Brian O'Connor375573b2015-03-06 01:09:43 -0800413 if (listener.requestThroughput() - listener.processedThroughput() <= 2000 && //was 500
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700414 lastDuration <= cyclePeriod) {
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700415 lastCount = Math.min(lastCount + addDelta, intents.size() / 2);
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800416 } else {
Brian O'Connor4964d3d2015-03-12 20:38:10 -0700417 lastCount *= multRatio;
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800418 }
419 log.info("last count: {}, last duration: {} ms (sub: {} vs inst: {})",
420 lastCount, lastDuration, listener.requestThroughput(), listener.processedThroughput());
421 }
422
Brian O'Connor6ccba962015-02-17 18:16:02 -0800423 }
424 }
425
Thomas Vachuskaa132e3a2015-02-21 01:53:14 -0800426 // Event listener to monitor throughput.
427 final class Listener implements IntentListener {
Brian O'Connor6ccba962015-02-17 18:16:02 -0800428
Thomas Vachuska0249b532015-02-20 16:46:18 -0800429 private final Counter runningTotal = new Counter();
Brian O'Connor87ba7a72015-03-11 14:40:09 -0700430 private volatile Map<IntentEvent.Type, Counter> counters;
Brian O'Connor6ccba962015-02-17 18:16:02 -0800431
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800432 private volatile double processedThroughput = 0;
433 private volatile double requestThroughput = 0;
434
Brian O'Connor6ccba962015-02-17 18:16:02 -0800435 public Listener() {
436 counters = initCounters();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800437 }
438
439 private Map<IntentEvent.Type, Counter> initCounters() {
440 Map<IntentEvent.Type, Counter> map = Maps.newHashMap();
441 for (IntentEvent.Type type : IntentEvent.Type.values()) {
442 map.put(type, new Counter());
443 }
444 return map;
445 }
446
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800447 public double processedThroughput() {
448 return processedThroughput;
449 }
450
451 public double requestThroughput() {
452 return requestThroughput;
453 }
454
Brian O'Connor6ccba962015-02-17 18:16:02 -0800455 @Override
456 public void event(IntentEvent event) {
457 if (event.subject().appId().equals(appId)) {
458 counters.get(event.type()).add(1);
459 }
460 }
461
462 public void report() {
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800463 Map<IntentEvent.Type, Counter> reportCounters = counters;
464 counters = initCounters();
465
466 // update running total and latest throughput
467 Counter installed = reportCounters.get(INSTALLED);
468 Counter withdrawn = reportCounters.get(WITHDRAWN);
469 processedThroughput = installed.throughput() + withdrawn.throughput();
Thomas Vachuska0249b532015-02-20 16:46:18 -0800470 runningTotal.add(installed.total() + withdrawn.total());
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800471
472 Counter installReq = reportCounters.get(INSTALL_REQ);
473 Counter withdrawReq = reportCounters.get(WITHDRAW_REQ);
474 requestThroughput = installReq.throughput() + withdrawReq.throughput();
475
476 // build the string to report
477 StringBuilder stringBuilder = new StringBuilder();
Brian O'Connor6ccba962015-02-17 18:16:02 -0800478 for (IntentEvent.Type type : IntentEvent.Type.values()) {
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800479 Counter counter = reportCounters.get(type);
480 stringBuilder.append(format("%s=%.2f;", type, counter.throughput()));
Brian O'Connor6ccba962015-02-17 18:16:02 -0800481 }
Thomas Vachuska0249b532015-02-20 16:46:18 -0800482 log.info("Throughput: OVERALL={}; CURRENT={}; {}",
483 format("%.2f", runningTotal.throughput()),
Brian O'Connor36ef71a2015-02-24 12:05:01 -0800484 format("%.2f", processedThroughput),
485 stringBuilder);
Brian O'Connor6ccba962015-02-17 18:16:02 -0800486 }
487 }
Brian O'Connor6ccba962015-02-17 18:16:02 -0800488}