/**
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rx.operators;
import java.util.*;
import java.util.concurrent.*;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import rx.*;
import rx.Observable;
import rx.observables.ConnectableObservable;
import rx.schedulers.Schedulers;
/**
* Benchmark typical atomic operations on volatile fields and AtomicXYZ classes.
*
* gradlew benchmarks "-Pjmh=-f 1 -tu s -bm thrpt -wi 5 -i 5 -r 1 .*OperatorPublishPerf.*"
*
* gradlew benchmarks "-Pjmh=-f 1 -tu ns -bm avgt -wi 5 -i 5 -r 1 .*OperatorPublishPerf.*"
*/
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Thread)
public class OperatorPublishPerf {
static final class SharedLatchObserver extends Subscriber {
final CountDownLatch cdl;
final int batchFrequency;
final Blackhole bh;
int received;
public SharedLatchObserver(CountDownLatch cdl, int batchFrequency, Blackhole bh) {
this.cdl = cdl;
this.batchFrequency = batchFrequency;
this.bh = bh;
}
@Override
public void onStart() {
request(batchFrequency);
}
@Override
public void onNext(Integer t) {
if (bh != null) {
bh.consume(t);
}
if (++received == batchFrequency) {
received = 0;
request(batchFrequency);
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
cdl.countDown();
}
@Override
public void onCompleted() {
cdl.countDown();
}
}
/** How long the range should be. */
@Param({"1", "1000", "1000000"})
private int size;
/** Should children use observeOn? */
@Param({"false", "true"})
private boolean async;
/** Number of child subscribers. */
@Param({"0", "1", "2", "3", "4", "5"})
private int childCount;
/** How often the child subscribers should re-request. */
@Param({"1", "2", "4", "8", "16", "32", "64"})
private int batchFrequency;
private ConnectableObservable source;
private Observable observable;
@Setup
public void setup() {
List list = new ArrayList();
for (int i = 0; i < size; i++) {
list.add(i);
}
Observable src = Observable.from(list);
source = src.publish();
observable = async ? source.observeOn(Schedulers.computation()) : source;
}
@Benchmark
public void benchmark(Blackhole bh) throws InterruptedException,
TimeoutException, BrokenBarrierException {
CountDownLatch completion = null;
int cc = childCount;
if (cc > 0) {
completion = new CountDownLatch(cc);
Observable o = observable;
for (int i = 0; i < childCount; i++) {
o.subscribe(new SharedLatchObserver(completion, batchFrequency, bh));
}
}
Subscription s = source.connect();
if (completion != null && !completion.await(2, TimeUnit.SECONDS)) {
throw new RuntimeException("Source hung!");
}
s.unsubscribe();
}
public static void main(String[] args) throws Exception {
OperatorPublishPerf o = new OperatorPublishPerf();
o.async = false;
o.batchFrequency = 1;
o.childCount = 0;
o.size = 1;
o.setup();
for (int j = 0; j < 1000; j++) {
o.benchmark(null);
}
}
}