[
https://issues.apache.org/jira/browse/HTRACE-170?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14542033#comment-14542033
]
Vladimir Sitnikov edited comment on HTRACE-170 at 5/13/15 2:59 PM:
-------------------------------------------------------------------
I've created a jmh benchmark to measure time it takes to create a new random
value.
It turns out ThreadLocalRandom is somehow 5 times faster than regular Random,
so it would be nice to use j.u.c.TLR when it is available.
My next question is: can we rely on JDK 7+ being used to build the project?
Is there a requirement to be able to build htrace with JDK6?
If we can build using JDK7 there is an easy trick to use j.u.c.TLR when running
in jre 7+ and fallback to ThreadLocal otherwise.
The following was executed on a 1 socket 4 cores 8 threads macbook.
{code:java}
package org.apache.htrace;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(1)
@Measurement(iterations = 10)
@Warmup(iterations = 5)
@Threads(4)
public class RandomBenchmark {
private static final ThreadLocal<java.util.Random> RANDOM = new
ThreadLocal<java.util.Random>() {
@Override
protected java.util.Random initialValue() {
return new java.util.Random();
}
};
java.util.Random sharedRandom = new java.util.Random();
@Benchmark
public long nonZeroRandom64_jdk7() {
java.util.Random random = ThreadLocalRandom.current();
long id;
do {
id = random.nextLong();
} while (id == 0);
return id;
}
@Benchmark
public long nonZeroRandom64_jdk5() {
java.util.Random random = RANDOM.get();
long id;
do {
id = random.nextLong();
} while (id == 0);
return id;
}
@Benchmark
public long nonZeroRandom64_sharedrandom() {
java.util.Random random = sharedRandom;
long id;
do {
id = random.nextLong();
} while (id == 0);
return id;
}
public static void main(String[] args) throws RunnerException {
new Runner(new OptionsBuilder()
.include(".*RandomBenchmark.*")
// .addProfiler(GCProfiler.class)
.build()).run();
}
}
{code}
{noformat}
# Threads: 1 thread, will synchronize iterations
Benchmark Mode Cnt Score Error Units
RandomBenchmark.nonZeroRandom64_jdk5 avgt 10 22,566 ± 0,634 ns/op
RandomBenchmark.nonZeroRandom64_jdk7 avgt 10 4,116 ± 0,098 ns/op
RandomBenchmark.nonZeroRandom64_sharedrandom avgt 10 23,258 ± 1,346
ns/op{noformat}
{noformat}
# Threads: 2 threads, will synchronize iterations
Benchmark Mode Cnt Score Error Units
RandomBenchmark.nonZeroRandom64_jdk5 avgt 10 21,061 ± 0,324 ns/op
RandomBenchmark.nonZeroRandom64_jdk7 avgt 10 3,791 ± 0,074 ns/op
RandomBenchmark.nonZeroRandom64_sharedrandom avgt 10 237,245 ± 3,503 ns/op
{noformat}
{noformat}
# Threads: 4 threads, will synchronize iterations
Benchmark Mode Cnt Score Error Units
RandomBenchmark.nonZeroRandom64_jdk5 avgt 10 21,109 ± 0,325 ns/op
RandomBenchmark.nonZeroRandom64_jdk7 avgt 10 4,539 ± 0,129 ns/op
RandomBenchmark.nonZeroRandom64_sharedrandom avgt 10 820,314 ± 40,330 ns/op
{noformat}
was (Author: vladimirsitnikov):
I've created a jmh benchmark to measure time it takes to create a new random
value.
It turns out ThreadLocalRandom is somehow 5 times faster than regular Random,
so it would be nice to use j.u.c.TLR when it is available.
My next question is: can we rely on JDK 7+ being used to build the project?
Is there a requirement to be able to build htrace with JDK6?
If we can build using JDK7 there is an easy trick to use j.u.c.TLR when running
in jre 7+ and fallback to ThreadLocal otherwise.
{code:java}
package org.apache.htrace;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(1)
@Measurement(iterations = 10)
@Warmup(iterations = 5)
@Threads(4)
public class RandomBenchmark {
private static final ThreadLocal<java.util.Random> RANDOM = new
ThreadLocal<java.util.Random>() {
@Override
protected java.util.Random initialValue() {
return new java.util.Random();
}
};
java.util.Random sharedRandom = new java.util.Random();
@Benchmark
public long nonZeroRandom64_jdk7() {
java.util.Random random = ThreadLocalRandom.current();
long id;
do {
id = random.nextLong();
} while (id == 0);
return id;
}
@Benchmark
public long nonZeroRandom64_jdk5() {
java.util.Random random = RANDOM.get();
long id;
do {
id = random.nextLong();
} while (id == 0);
return id;
}
@Benchmark
public long nonZeroRandom64_sharedrandom() {
java.util.Random random = sharedRandom;
long id;
do {
id = random.nextLong();
} while (id == 0);
return id;
}
public static void main(String[] args) throws RunnerException {
new Runner(new OptionsBuilder()
.include(".*RandomBenchmark.*")
// .addProfiler(GCProfiler.class)
.build()).run();
}
}
{code}
{noformat}
# Threads: 1 thread, will synchronize iterations
Benchmark Mode Cnt Score Error Units
RandomBenchmark.nonZeroRandom64_jdk5 avgt 10 22,566 ± 0,634 ns/op
RandomBenchmark.nonZeroRandom64_jdk7 avgt 10 4,116 ± 0,098 ns/op
RandomBenchmark.nonZeroRandom64_sharedrandom avgt 10 23,258 ± 1,346
ns/op{noformat}
{noformat}
# Threads: 2 threads, will synchronize iterations
Benchmark Mode Cnt Score Error Units
RandomBenchmark.nonZeroRandom64_jdk5 avgt 10 21,061 ± 0,324 ns/op
RandomBenchmark.nonZeroRandom64_jdk7 avgt 10 3,791 ± 0,074 ns/op
RandomBenchmark.nonZeroRandom64_sharedrandom avgt 10 237,245 ± 3,503 ns/op
{noformat}
{noformat}
# Threads: 4 threads, will synchronize iterations
Benchmark Mode Cnt Score Error Units
RandomBenchmark.nonZeroRandom64_jdk5 avgt 10 21,109 ± 0,325 ns/op
RandomBenchmark.nonZeroRandom64_jdk7 avgt 10 4,539 ± 0,129 ns/op
RandomBenchmark.nonZeroRandom64_sharedrandom avgt 10 820,314 ± 40,330 ns/op
{noformat}
> Optimize use of Random in htrace-core
> -------------------------------------
>
> Key: HTRACE-170
> URL: https://issues.apache.org/jira/browse/HTRACE-170
> Project: HTrace
> Issue Type: Bug
> Affects Versions: 3.3.0
> Reporter: Vladimir Sitnikov
>
> org.apache.htrace.Tracer#nonZeroRandom64 is obviously shares the same Random
> instance between multiple execution threads.
> That does not work.
> Either {{ThreadLocal<Random>}} (1.5+) or {{ThreadLocalRandom}} (1.7+) should
> be used.
> Other places with the same problem:
> org.apache.htrace.impl.CountSampler#random
> org.apache.htrace.impl.MilliSpan#nonZeroRandom64
> org.apache.htrace.impl.ProbabilitySampler#next
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)