Brian O'Connor
Committed by Gerrit Code Review

IntentPerfInstaller: using feedback to determine submit size

Change-Id: Iaa4eb657ee0e22d008597c40561ea89105a09a15
...@@ -61,22 +61,22 @@ import static java.lang.System.currentTimeMillis; ...@@ -61,22 +61,22 @@ import static java.lang.System.currentTimeMillis;
61 import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY; 61 import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY;
62 import static org.onlab.util.Tools.delay; 62 import static org.onlab.util.Tools.delay;
63 import static org.onlab.util.Tools.groupedThreads; 63 import static org.onlab.util.Tools.groupedThreads;
64 -import static org.onosproject.net.intent.IntentEvent.Type.INSTALLED; 64 +import static org.onosproject.net.intent.IntentEvent.Type.*;
65 -import static org.onosproject.net.intent.IntentEvent.Type.WITHDRAWN;
66 import static org.slf4j.LoggerFactory.getLogger; 65 import static org.slf4j.LoggerFactory.getLogger;
67 66
68 /** 67 /**
69 - * Application to set up demos. 68 + * Application to test sustained intent throughput.
70 */ 69 */
71 @Component(immediate = true) 70 @Component(immediate = true)
72 public class IntentPerfInstaller { 71 public class IntentPerfInstaller {
73 72
74 //FIXME make this configurable 73 //FIXME make this configurable
75 private static final int NUM_WORKERS = 1; 74 private static final int NUM_WORKERS = 1;
76 - private static final int NUM_KEYS = 10_000; 75 + private static final int NUM_KEYS = 20_000;
77 76
78 public static final int START_DELAY = 5_000; // ms 77 public static final int START_DELAY = 5_000; // ms
79 private static final int REPORT_PERIOD = 5_000; //ms 78 private static final int REPORT_PERIOD = 5_000; //ms
79 + private static final int GOAL_CYCLE_PERIOD = 1_000; //ms
80 80
81 private final Logger log = getLogger(getClass()); 81 private final Logger log = getLogger(getClass());
82 82
...@@ -99,6 +99,7 @@ public class IntentPerfInstaller { ...@@ -99,6 +99,7 @@ public class IntentPerfInstaller {
99 99
100 private Timer reportTimer; 100 private Timer reportTimer;
101 101
102 + // FIXME this variable isn't shared properly between multiple worker threads
102 private int lastKey = 0; 103 private int lastKey = 0;
103 104
104 @Activate 105 @Activate
...@@ -135,6 +136,7 @@ public class IntentPerfInstaller { ...@@ -135,6 +136,7 @@ public class IntentPerfInstaller {
135 reportTimer.scheduleAtFixedRate(new TimerTask() { 136 reportTimer.scheduleAtFixedRate(new TimerTask() {
136 @Override 137 @Override
137 public void run() { 138 public void run() {
139 + //adjustRates(); // FIXME we currently adjust rates in the cycle thread
138 listener.report(); 140 listener.report();
139 } 141 }
140 }, REPORT_PERIOD - currentTimeMillis() % REPORT_PERIOD, REPORT_PERIOD); 142 }, REPORT_PERIOD - currentTimeMillis() % REPORT_PERIOD, REPORT_PERIOD);
...@@ -158,16 +160,10 @@ public class IntentPerfInstaller { ...@@ -158,16 +160,10 @@ public class IntentPerfInstaller {
158 try { 160 try {
159 workers.awaitTermination(5, TimeUnit.SECONDS); 161 workers.awaitTermination(5, TimeUnit.SECONDS);
160 } catch (InterruptedException e) { 162 } catch (InterruptedException e) {
161 - log.warn("Failed to stop worker."); 163 + log.warn("Failed to stop worker", e);
162 } 164 }
163 } 165 }
164 166
165 - private Iterable<Intent> subset(Set<Intent> intents) {
166 - List<Intent> subset = Lists.newArrayList(intents);
167 - Collections.shuffle(subset);
168 - return subset.subList(0, subset.size() / 2);
169 - }
170 -
171 /** 167 /**
172 * Creates a specified number of intents for testing purposes. 168 * Creates a specified number of intents for testing purposes.
173 * 169 *
...@@ -200,7 +196,7 @@ public class IntentPerfInstaller { ...@@ -200,7 +196,7 @@ public class IntentPerfInstaller {
200 continue; 196 continue;
201 } 197 }
202 198
203 - //FIXME 199 + //FIXME we currently ignore the path length and always use the same device
204 TrafficSelector selector = DefaultTrafficSelector.builder().build(); 200 TrafficSelector selector = DefaultTrafficSelector.builder().build();
205 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build(); 201 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
206 ConnectPoint ingress = new ConnectPoint(ingressDevice.id(), PortNumber.portNumber(1)); 202 ConnectPoint ingress = new ConnectPoint(ingressDevice.id(), PortNumber.portNumber(1));
...@@ -216,7 +212,7 @@ public class IntentPerfInstaller { ...@@ -216,7 +212,7 @@ public class IntentPerfInstaller {
216 count++; 212 count++;
217 lastKey = k; 213 lastKey = k;
218 if (lastKey % 1000 == 0) { 214 if (lastKey % 1000 == 0) {
219 - log.info("Building intents... {} ({})", count, lastKey); 215 + log.info("Building intents... {} (attempt: {})", lastKey, count);
220 } 216 }
221 } 217 }
222 log.info("Created {} intents", numberOfKeys); 218 log.info("Created {} intents", numberOfKeys);
...@@ -226,24 +222,33 @@ public class IntentPerfInstaller { ...@@ -226,24 +222,33 @@ public class IntentPerfInstaller {
226 // Submits intent operations. 222 // Submits intent operations.
227 final class Submitter implements Runnable { 223 final class Submitter implements Runnable {
228 224
225 + private long lastDuration;
226 + private int lastCount;
227 +
229 private Set<Intent> intents = Sets.newHashSet(); 228 private Set<Intent> intents = Sets.newHashSet();
230 private Set<Intent> submitted = Sets.newHashSet(); 229 private Set<Intent> submitted = Sets.newHashSet();
231 private Set<Intent> withdrawn = Sets.newHashSet(); 230 private Set<Intent> withdrawn = Sets.newHashSet();
232 231
233 private Submitter(Set<Intent> intents) { 232 private Submitter(Set<Intent> intents) {
234 this.intents = intents; 233 this.intents = intents;
234 + lastCount = NUM_KEYS / 4;
235 + lastDuration = 1000; // 1 second
235 } 236 }
236 237
237 @Override 238 @Override
238 public void run() { 239 public void run() {
239 - delay(2000); // take a breath to start
240 prime(); 240 prime();
241 while (!stopped) { 241 while (!stopped) {
242 cycle(); 242 cycle();
243 - delay(800); // take a breath
244 } 243 }
245 } 244 }
246 245
246 + private Iterable<Intent> subset(Set<Intent> intents) {
247 + List<Intent> subset = Lists.newArrayList(intents);
248 + Collections.shuffle(subset);
249 + return subset.subList(0, lastCount);
250 + }
251 +
247 // Submits the specified intent. 252 // Submits the specified intent.
248 private void submit(Intent intent) { 253 private void submit(Intent intent) {
249 intentService.submit(intent); 254 intentService.submit(intent);
...@@ -273,23 +278,52 @@ public class IntentPerfInstaller { ...@@ -273,23 +278,52 @@ public class IntentPerfInstaller {
273 278
274 // Runs a single operation cycle. 279 // Runs a single operation cycle.
275 private void cycle() { 280 private void cycle() {
281 + //TODO consider running without rate adjustment
282 + adjustRates();
283 +
276 long start = currentTimeMillis(); 284 long start = currentTimeMillis();
277 subset(submitted).forEach(this::withdraw); 285 subset(submitted).forEach(this::withdraw);
278 subset(withdrawn).forEach(this::submit); 286 subset(withdrawn).forEach(this::submit);
279 long delta = currentTimeMillis() - start; 287 long delta = currentTimeMillis() - start;
280 - if (delta > 5000 || delta < 0) { 288 +
289 + if (delta > GOAL_CYCLE_PERIOD * 3 || delta < 0) {
281 log.warn("Cycle took {} ms", delta); 290 log.warn("Cycle took {} ms", delta);
282 } 291 }
292 +
293 + int difference = GOAL_CYCLE_PERIOD - (int) delta;
294 + if (difference > 0) {
295 + delay(difference);
296 + }
297 +
298 + lastDuration = delta;
283 } 299 }
284 - }
285 300
301 + int cycleCount = 0;
302 + private void adjustRates() {
303 + //FIXME need to iron out the rate adjustment
304 + if (++cycleCount % 5 == 0) { //TODO: maybe use a timer (we should do this every 5-10 sec)
305 + if (listener.requestThroughput() - listener.processedThroughput() <= 500 &&
306 + lastDuration <= GOAL_CYCLE_PERIOD) {
307 + lastCount = Math.min(lastCount + 100, intents.size() / 2);
308 + } else {
309 + lastCount *= 0.8;
310 + }
311 + log.info("last count: {}, last duration: {} ms (sub: {} vs inst: {})",
312 + lastCount, lastDuration, listener.requestThroughput(), listener.processedThroughput());
313 + }
314 +
315 + }
316 + }
286 317
287 // Event listener to monitor throughput. 318 // Event listener to monitor throughput.
288 final class Listener implements IntentListener { 319 final class Listener implements IntentListener {
289 320
290 - private final Map<IntentEvent.Type, Counter> counters; 321 + private Map<IntentEvent.Type, Counter> counters;
291 private final Counter runningTotal = new Counter(); 322 private final Counter runningTotal = new Counter();
292 323
324 + private volatile double processedThroughput = 0;
325 + private volatile double requestThroughput = 0;
326 +
293 public Listener() { 327 public Listener() {
294 counters = initCounters(); 328 counters = initCounters();
295 } 329 }
...@@ -302,6 +336,14 @@ public class IntentPerfInstaller { ...@@ -302,6 +336,14 @@ public class IntentPerfInstaller {
302 return map; 336 return map;
303 } 337 }
304 338
339 + public double processedThroughput() {
340 + return processedThroughput;
341 + }
342 +
343 + public double requestThroughput() {
344 + return requestThroughput;
345 + }
346 +
305 @Override 347 @Override
306 public void event(IntentEvent event) { 348 public void event(IntentEvent event) {
307 if (event.subject().appId().equals(appId)) { 349 if (event.subject().appId().equals(appId)) {
...@@ -310,25 +352,29 @@ public class IntentPerfInstaller { ...@@ -310,25 +352,29 @@ public class IntentPerfInstaller {
310 } 352 }
311 353
312 public void report() { 354 public void report() {
313 - StringBuilder stringBuilder = new StringBuilder(); 355 + Map<IntentEvent.Type, Counter> reportCounters = counters;
314 - Counter installed = counters.get(INSTALLED); 356 + counters = initCounters();
315 - Counter withdrawn = counters.get(WITHDRAWN); 357 +
316 - double current = installed.throughput() + withdrawn.throughput(); 358 + // update running total and latest throughput
359 + Counter installed = reportCounters.get(INSTALLED);
360 + Counter withdrawn = reportCounters.get(WITHDRAWN);
361 + processedThroughput = installed.throughput() + withdrawn.throughput();
317 runningTotal.add(installed.total() + withdrawn.total()); 362 runningTotal.add(installed.total() + withdrawn.total());
363 +
364 + Counter installReq = reportCounters.get(INSTALL_REQ);
365 + Counter withdrawReq = reportCounters.get(WITHDRAW_REQ);
366 + requestThroughput = installReq.throughput() + withdrawReq.throughput();
367 +
368 + // build the string to report
369 + StringBuilder stringBuilder = new StringBuilder();
318 for (IntentEvent.Type type : IntentEvent.Type.values()) { 370 for (IntentEvent.Type type : IntentEvent.Type.values()) {
319 - stringBuilder.append(printCounter(type)).append("; "); 371 + Counter counter = reportCounters.get(type);
372 + stringBuilder.append(format("%s=%.2f;", type, counter.throughput()));
320 } 373 }
321 log.info("Throughput: OVERALL={}; CURRENT={}; {}", 374 log.info("Throughput: OVERALL={}; CURRENT={}; {}",
322 format("%.2f", runningTotal.throughput()), 375 format("%.2f", runningTotal.throughput()),
323 - format("%.2f", current), stringBuilder); 376 + format("%.2f", processedThroughput),
324 - } 377 + stringBuilder);
325 -
326 - private String printCounter(IntentEvent.Type event) {
327 - Counter counter = counters.get(event);
328 - String result = format("%s=%.2f", event, counter.throughput());
329 - counter.reset();
330 - return result;
331 } 378 }
332 } 379 }
333 -
334 } 380 }
......