Committed by
Gerrit Code Review
IntentPerfInstaller: using feedback to determine submit size
Change-Id: Iaa4eb657ee0e22d008597c40561ea89105a09a15
Showing
1 changed file
with
78 additions
and
32 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); | ||
| 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 | } | ... | ... |
-
Please register or login to post a comment