[ 
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)

Reply via email to