All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.scalecube.benchmarks.BenchmarksState Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
package io.scalecube.benchmarks;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.CsvReporter;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Timer;

import reactor.core.publisher.Flux;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.LongStream;


/**
 * BenchmarksState is the state of the benchmark. it gives you the analogy of the beginning, and ending of the test. It
 * can run both sync or async way using the {@link #runForSync(Function)} and {@link #runForAsync(Function)}
 * respectively.
 * 
 * @param  when extending this class, please add your class as the SELF. ie.
 * 
 *        
 * {@code   
 *  public class ExampleBenchmarksState extends BenchmarksState {   
 *    ...   
 *  }   
 * }
 *        
*/ public class BenchmarksState> { private static final Logger LOGGER = LoggerFactory.getLogger(BenchmarksState.class); protected final BenchmarksSettings settings; private ConsoleReporter consoleReporter; private Scheduler scheduler; private CsvReporter csvReporter; private final AtomicBoolean started = new AtomicBoolean(); public BenchmarksState(BenchmarksSettings settings) { this.settings = settings; } protected void beforeAll() { // NOP } protected void afterAll() { // NOP } /** * Executes starting of the state, also it includes running of {@link BenchmarksState#beforeAll}. */ public final void start() { if (!started.compareAndSet(false, true)) { throw new IllegalStateException("BenchmarksState is already started"); } LOGGER.info("Benchmarks settings: " + settings); consoleReporter = ConsoleReporter.forRegistry(settings.registry()) .outputTo(System.out) .convertDurationsTo(settings.durationUnit()) .convertRatesTo(settings.rateUnit()) .build(); csvReporter = CsvReporter.forRegistry(settings.registry()) .convertDurationsTo(settings.durationUnit()) .convertRatesTo(settings.rateUnit()) .build(settings.csvReporterDirectory()); scheduler = Schedulers.fromExecutor(Executors.newFixedThreadPool(settings.nThreads())); beforeAll(); consoleReporter.start(settings.reporterPeriod().toMillis(), TimeUnit.MILLISECONDS); csvReporter.start(1, TimeUnit.DAYS); Runtime.getRuntime().addShutdownHook(new Thread(() -> { if (started.get()) { csvReporter.report(); consoleReporter.report(); } })); } /** * Executes shutdown process of the state, also it includes running of {@link BenchmarksState#afterAll}. */ public final void shutdown() { if (!started.compareAndSet(true, false)) { throw new IllegalStateException("BenchmarksState is not started"); } if (consoleReporter != null) { consoleReporter.report(); consoleReporter.stop(); } if (csvReporter != null) { csvReporter.report(); csvReporter.stop(); } if (scheduler != null) { scheduler.dispose(); } afterAll(); } public Scheduler scheduler() { return scheduler; } /** * Returns timer with specified name. * * @param name name * @return timer with specified name */ public Timer timer(String name) { return settings.registry().timer(settings.taskName() + "-" + name); } /** * Returns meter with specified name. * * @param name name * @return meter with specified name */ public Meter meter(String name) { return settings.registry().meter(settings.taskName() + "-" + name); } /** * Returns histogram with specified name. * * @param name name * @return histogram with specified name */ public Histogram histogram(String name) { return settings.registry().histogram(settings.taskName() + "-" + name); } /** * Runs given function in the state. It also executes {@link BenchmarksState#start()} before and * {@link BenchmarksState#shutdown()} after. *

* NOTICE: It's only for synchronous code. *

* * @param func a function that should return the execution to be tested for the given SELF. This execution would run * on all positive values of Long (i.e. the benchmark itself) the return value is ignored. */ public final void runForSync(Function> func) { @SuppressWarnings("unchecked") SELF self = (SELF) this; try { // noinspection unchecked self.start(); Function unitOfWork = func.apply(self); Flux.merge(Flux.fromStream(LongStream.range(0, Long.MAX_VALUE).boxed()) .publishOn(scheduler()) .map(unitOfWork)) .take(settings.executionTaskTime()) .blockLast(); } finally { self.shutdown(); } } /** * Runs given function on this state. It also executes {@link BenchmarksState#start()} before and * {@link BenchmarksState#shutdown()} after. *

* NOTICE: It's only for asynchronous code. *

* * @param func a function that should return the execution to be tested for the given SELF. This execution would run * on all positive values of Long (i.e. the benchmark itself) On the return value, as it is a Publisher, The * benchmark test would {@link Publisher#subscribe(Subscriber) subscribe}, And upon all subscriptions - await * for termination. */ public final void runForAsync(Function>> func) { // noinspection unchecked @SuppressWarnings("unchecked") SELF self = (SELF) this; try { self.start(); Function> publisherToBenchmarkMethod = func.apply(self); Flux.merge(Flux.fromStream(LongStream.range(0, Long.MAX_VALUE).boxed()) .publishOn(scheduler()) .map(publisherToBenchmarkMethod)) .take(settings.executionTaskTime()) .blockLast(); } finally { self.shutdown(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy