Committed by
Gerrit Code Review
IntentPerfInstaller: using feedback to determine submit size
Change-Id: Iaa4eb657ee0e22d008597c40561ea89105a09a15
Showing
1 changed file
with
77 additions
and
31 deletions
... | @@ -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); | ||
283 | } | 296 | } |
297 | + | ||
298 | + lastDuration = delta; | ||
284 | } | 299 | } |
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), |
377 | + stringBuilder); | ||
324 | } | 378 | } |
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 | } | 379 | } |
332 | - } | ||
333 | - | ||
334 | } | 380 | } | ... | ... |
-
Please register or login to post a comment