/**
* Copyright 2013, Landz and its contributors. All rights reserved.
*
* 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 z.basic;
import org.HdrHistogram.Histogram;
import org.junit.Ignore;
import org.junit.Test;
import java.io.PrintStream;
import java.util.concurrent.*;
import java.util.stream.IntStream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static z.util.Throwables.uncheck;
/**
* Note: the time of instantizate new Long value for passing
*
*/
public class EndToEndLatencyTest {
private static final Histogram HISTOGRAM = new Histogram(2000_000_000L, 0);
private LinkedTransferQueue<Long> ltq = new LinkedTransferQueue();
private SynchronousQueue<Long> sq = new SynchronousQueue();
//XXX: ABQ/CLQ, not appropriate for one-shot latency, just placeholder
private ArrayBlockingQueue<Long> abq = new ArrayBlockingQueue(1024);
private ConcurrentLinkedQueue<Long> clq = new ConcurrentLinkedQueue();
private static final int RUNS = 10_000_000;
public void runLTQ() {
int numRunnings0 = numOfRunningThreads();
HISTOGRAM.reset();
new Thread(() -> {
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() -> {
Long t = ltq.take();
long now = System.nanoTime();
HISTOGRAM.recordValue(now - t);
})
);
}).start();
//XXX: producer is in main thread
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() ->
ltq.transfer(new Long(System.nanoTime())))
);
assertThat(ltq.size(), is(0));
assertThat(numOfRunningThreads(), is(numRunnings0));
dumpHistogram(HISTOGRAM, System.out);
}
public void runSQ() {
int numRunnings0 = numOfRunningThreads();
HISTOGRAM.reset();
new Thread(() -> {
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() -> {
Long t = sq.take();
long now = System.nanoTime();
HISTOGRAM.recordValue(now - t);
})
);
}).start();
//XXX: producer is in main thread
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() ->
sq.put(new Long(System.nanoTime())))
);
assertThat(sq.size(), is(0));
assertThat(numOfRunningThreads(), is(numRunnings0));
dumpHistogram(HISTOGRAM, System.out);
}
public void runABQ() {
int numRunnings0 = numOfRunningThreads();
HISTOGRAM.reset();
CountDownLatch latch = new CountDownLatch(2);
new Thread(() -> {
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() -> {
Long t = abq.take();
long now = System.nanoTime();
HISTOGRAM.recordValue(now - t);
})
);
latch.countDown();
}).start();
//XXX: producer is in main thread
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() ->
abq.put(new Long(System.nanoTime())))
);
latch.countDown();
uncheck(() -> latch.await());
assertThat(abq.size(), is(0));
assertThat(numOfRunningThreads(), is(numRunnings0));
dumpHistogram(HISTOGRAM, System.out);
}
public void runCLQ() {
int numRunnings0 = numOfRunningThreads();
HISTOGRAM.reset();
CountDownLatch latch = new CountDownLatch(2);
new Thread(() -> {
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() -> {
Long t = null;
while (t==null)
t = clq.poll();
long now = System.nanoTime();
HISTOGRAM.recordValue(now - t);
})
);
latch.countDown();
}).start();
//XXX: producer is in main thread
IntStream.range(0, RUNS).forEach((i) ->
uncheck(() ->
clq.offer(new Long(System.nanoTime())))
);
latch.countDown();
uncheck(() -> latch.await());
assertThat(clq.size(), is(0));
assertThat(numOfRunningThreads(), is(numRunnings0));
dumpHistogram(HISTOGRAM, System.out);
}
private static final int numOfRunningThreads() {
return (int)
Thread.getAllStackTraces().keySet().stream()
.filter(t -> t.getState() == Thread.State.RUNNABLE)
.count();
}
private static void dumpHistogram(final Histogram histogram, final PrintStream out) {
histogram.getHistogramData().outputPercentileDistribution(out, 1, 1.0);
}
private static void runFinePrint(String label, Runnable runnable) {
System.out.println("================================");
System.out.println(label + " start...");
runnable.run();
System.out.println(label + " done.");
System.out.println("================================");
}
public static void main(String[] args) {
new EndToEndLatencyTest().testLTQ();
new EndToEndLatencyTest().testSQ();
// new EndToEndLatencyTest().testABQ();
// new EndToEndLatencyTest().testCLQ();
}
@Test
public void testLTQ() {
for (int i=0;i<3;i++)
runFinePrint("for LinkedTransferQueue", () -> runLTQ());
}
@Ignore
@Test
public void testSQ() {
runFinePrint("for SynchronousQueue", () -> runSQ());
}
@Ignore
@Test
public void testABQ() {
runFinePrint("for ArrayBlockingQueue", () -> runABQ());
}
@Ignore
@Test
public void testCLQ() {
runFinePrint("for ConcurrentLinkedQueue", () -> runCLQ());
}
}