/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule; import static java.lang.Class.forName; import static java.lang.Thread.sleep; import static org.mule.runtime.api.message.Message.of; import static org.mule.runtime.core.api.construct.Flow.builder; import static org.mule.runtime.core.api.lifecycle.LifecycleUtils.stopIfNeeded; import static org.openjdk.jmh.infra.Blackhole.consumeCPU; import org.mule.runtime.api.exception.MuleException; import org.mule.runtime.core.DefaultEventContext; import org.mule.runtime.core.api.Event; import org.mule.runtime.core.api.MuleContext; import org.mule.runtime.core.api.construct.Flow; import org.mule.runtime.core.api.processor.Processor; import org.mule.runtime.core.api.processor.strategy.ProcessingStrategyFactory; import org.mule.runtime.core.api.scheduler.SchedulerService; import org.mule.runtime.core.processor.strategy.AbstractProcessingStrategyFactory; import org.mule.runtime.core.processor.strategy.ReactorStreamProcessingStrategyFactory; import org.mule.tck.TriggerableMessageSource; import java.util.List; import java.util.concurrent.CountDownLatch; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import reactor.core.publisher.Mono; @State(Scope.Benchmark) public abstract class AbstractFlowBenchmark extends AbstractBenchmark { static final Processor nullProcessor = event -> event; static final Processor cpuLightProcessor = event -> { // Roughly 50uS on modern CPU. consumeCPU(25000); return event; }; static final Processor cpuIntensiveProcessor = new Processor() { @Override public Event process(Event event) throws MuleException { // Roughly 5mS on modern CPU. consumeCPU(2500000); return event; } @Override public ProcessingType getProcessingType() { return ProcessingType.CPU_INTENSIVE; } }; static final Processor blockingProcessor = new Processor() { @Override public Event process(Event event) throws MuleException { try { sleep(20); } catch (InterruptedException e) { throw new RuntimeException(e); } return event; } @Override public ProcessingType getProcessingType() { return ProcessingType.BLOCKING; } }; protected MuleContext muleContext; protected Flow flow; protected TriggerableMessageSource source; @Param({ "org.mule.runtime.core.processor.strategy.DirectProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.DirectStreamPerThreadProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.ReactorProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.ReactorStreamProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.DefaultFlowProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.DefaultStreamProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.WorkQueueProcessingStrategyFactory", "org.mule.runtime.core.processor.strategy.WorkQueueStreamProcessingStrategyFactory", }) public String processingStrategyFactory; @Param({"1"}) public int subscribers; @Param({"256"}) public int bufferSize; @Param({"10000"}) public int maxConcurrency; @Setup public void setup() throws Exception { muleContext = createMuleContextWithServices(); muleContext.start(); ProcessingStrategyFactory factory = (ProcessingStrategyFactory) forName(processingStrategyFactory).newInstance(); if (factory instanceof AbstractProcessingStrategyFactory) { ((AbstractProcessingStrategyFactory) factory).setMaxConcurrency(maxConcurrency); } if (factory instanceof ReactorStreamProcessingStrategyFactory) { ((ReactorStreamProcessingStrategyFactory) factory).setBufferSize(bufferSize); ((ReactorStreamProcessingStrategyFactory) factory).setSubscriberCount(subscribers); } source = new TriggerableMessageSource(); flow = builder(FLOW_NAME, muleContext).messageProcessors(getMessageProcessors()).messageSource(source) .processingStrategyFactory(factory).build(); muleContext.getRegistry().registerFlowConstruct(flow); } protected abstract List<Processor> getMessageProcessors(); protected abstract int getStreamIterations(); @TearDown public void teardown() throws MuleException { SchedulerService schedulerService = muleContext.getRegistry().lookupObject(SchedulerService.class); muleContext.dispose(); stopIfNeeded(schedulerService); } @Benchmark public Event processSourceBlocking() throws MuleException { return source.trigger(Event.builder(DefaultEventContext.create(flow, CONNECTOR_LOCATION)) .message(of(PAYLOAD)).build()); } @Benchmark public CountDownLatch processSourceStream() throws MuleException, InterruptedException { CountDownLatch latch = new CountDownLatch(getStreamIterations()); for (int i = 0; i < getStreamIterations(); i++) { Mono.just(Event.builder(DefaultEventContext.create(flow, CONNECTOR_LOCATION)) .message(of(PAYLOAD)).build()).transform(source.getListener()).doOnNext(event -> latch.countDown()) .subscribe(); } latch.await(); return latch; } }