+ *
+ * Mode.Throughput, as stated in its Javadoc, measures the raw throughput by
+ * continuously calling the benchmark method in a time-bound iteration, and
+ * counting how many times we executed the method.
+ *
+ * We are using the special annotation to select the units to measure in,
+ * although you can use the default.
+ */
+ @Benchmark
+ @BenchmarkMode(Mode.Throughput)
+ @OutputTimeUnit(TimeUnit.SECONDS)
+ public static void measureThroughput() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+ /*
+ * Mode.AverageTime measures the average execution time, and it does it
+ * in the way similar to Mode.Throughput.
+ *
+ * Some might say it is the reciprocal throughput, and it really is.
+ * There are workloads where measuring times is more convenient though.
+ */
+
+ /**
+ *
+ */
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ public static void measureAverageTime() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+ /*
+ * Mode.SampleTime samples the execution time. With this mode, we are
+ * still running the method in a time-bound iteration, but instead of
+ * measuring the total time, we measure the time spent in *some* of
+ * the benchmark method calls.
+ *
+ * This allows us to infer the distributions, percentiles, etc.
+ *
+ * JMH also tries to auto-adjust sampling frequency: if the method
+ * is long enough, you will end up capturing all the samples.
+ */
+
+ /**
+ *
Sample time: 对每次操作的时间进行采样 Sampling time
+ *
+ *
This mode automatically adjusts the sampling
+ * frequency, but may omit some pauses which missed the sampling measurement.
+ */
+ @Benchmark
+ @BenchmarkMode(Mode.SampleTime)
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ public static void measureSampleTime() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+ /*
+ * Mode.SingleShotTime measures the single method invocation time. As the Javadoc
+ * suggests, we do only the single benchmark method invocation. The iteration
+ * time is meaningless in this mode: as soon as benchmark method stops, the
+ * iteration is over.
+ *
+ * This mode is useful to do cold startup tests, when you specifically
+ * do not want to call the benchmark method continuously.
+ */
+
+ /**
+ *
+ *
+ */
+ @Benchmark
+ @BenchmarkMode(Mode.SingleShotTime)
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ public static void measureSingleShotTime() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+ /*
+ * We can also ask for multiple benchmark modes at once. All the tests
+ * above can be replaced with just a single test like this:
+ */
+
+ @Benchmark
+ @BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime})
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ public void measureMultiple() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+ /**
+ * Meta-mode: all the benchmark modes.
+ * This is mostly useful for internal JMH testing.
+ */
+
+ @Benchmark
+ @BenchmarkMode(Mode.All)
+ @OutputTimeUnit(TimeUnit.MICROSECONDS)
+ public void measureAll() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_03_States.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_03_States.java
new file mode 100644
index 00000000..6e0c5f29
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_03_States.java
@@ -0,0 +1,85 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ *
+ * @see Scope
+ *
+ * @author childe
+ * @date 2018/9/20 16:02
+ **/
+public class JMHSample_03_States {
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_03_States.class.getSimpleName())
+ .output("JMHSample_03_States_result.sampleLog")
+ .threads(4)
+ .forks(1)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ /*
+ * 有些情况下,你需要在基准测试执行时维护一些状态。因为JHM常常用来构建并发基准测试,
+ * 我们选择了一个明确的state-bearing(状态支撑)对象概念。
+ *
+ * 下面是两个状态对象。他们的类名不是必需的,只是我们需要在类上标记@State。
+ * 这些对象在需要时被创建,在整个基准试验期间重复使用。
+ *
+ * 这个重要的状态属性始终由其中一个基准线程实例化,然后可以访问该状态。
+ * 这意味着你可以初始化字段,就像在工作线程中那样(ThreadLocals是你的,等等)
+ *
+ */
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkState {
+ {
+ System.out.println("swwwws");
+ }
+ volatile double x = Math.PI;
+ }
+
+ @State(Scope.Thread)
+ public static class ThreadState {
+ {
+ System.out.println("ss");
+ }
+ volatile double x = Math.PI;
+ }
+
+ /*
+ * Benchmark方法可以引用这个状态,JHM在调用这些方法时会注入适当的状态。
+ * 你可以没有状态,或者只有一个,又或者引用多个。
+ * 这使你构建一个多线程的基准测试轻而易举。
+ */
+
+ @Benchmark
+ public void measureUnshared(ThreadState state) {
+ // All benchmark threads will call in this method.
+ //
+ // However, since ThreadState is the Scope.Thread, each thread
+ // will have it's own copy of the state, and this benchmark
+ // will measure unshared case.
+ state.x++;
+ }
+
+ @Benchmark
+ public void measureShared(BenchmarkState state) {
+ // All benchmark threads will call in this method.
+ //
+ // Since BenchmarkState is the Scope.Benchmark, all threads
+ // will share the state instance, and we will end up measuring
+ // shared case.
+ state.x++;
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_04_DefaultState.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_04_DefaultState.java
new file mode 100644
index 00000000..0794ddd0
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_04_DefaultState.java
@@ -0,0 +1,37 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * 幸运的是,大多情况下你只需要一个单独的对象。
+ * 这种情况下,我们可以用benchmark的实例来标记@State。
+ * 然后,我们就可以像其他任何Java程序那样来引用他。
+ *
+ * @author childe
+ * @date 2018/9/20 17:08
+ **/
+@State(Scope.Thread)
+public class JMHSample_04_DefaultState {
+
+ private double x = Math.PI;
+
+ public static void main(String[] args) throws RunnerException {
+ Options options = new OptionsBuilder()
+ .include(JMHSample_04_DefaultState.class.getSimpleName())
+ .output("JMHSample_04_DefaultState_result.sampleLog")
+ .threads(1)
+ .forks(1)
+ .build();
+ new Runner(options).run();
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.Throughput)
+ public void measureDefaultState() {
+ x++;
+ }
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_05_StateFixtures.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_05_StateFixtures.java
new file mode 100644
index 00000000..9decedd8
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_05_StateFixtures.java
@@ -0,0 +1,113 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * @see Level
+ * @see Setup
+ * @see TearDown
+ *
+ * @author childe
+ * @date 2018/10/8 11:23
+ **/
+@State(Scope.Thread)
+public class JMHSample_05_StateFixtures {
+
+ private double x;
+
+ /*
+ * Since @State objects are kept around during the lifetime of the
+ * benchmark, it helps to have the methods which do state housekeeping.
+ * These are usual fixture methods, you are probably familiar with them from
+ * JUnit and TestNG.
+ *
+ * Fixture methods make sense only on @State objects, and JMH will fail to
+ * compile the test otherwise.
+ *
+ * As with the State, fixture methods are only called by those benchmark
+ * threads which are using the state. That means you can operate in the
+ * thread-local context, and (not) use synchronization as if you are
+ * executing in the context of benchmark thread.
+ *
+ * Note: fixture methods can also work with static fields, although the
+ * semantics of these operations fall back out of State scope, and obey
+ * usual Java rules (i.e. one static field per class).
+ *
+ * 因为@State对象在benchmark的生命周期中保持不变,它可以帮助我们使用状态管理的方法。
+ * 这些fixture方法看起来和JUnit和TestNG很像
+ * @see org.openjdk.jmh.annotations.Level。
+ *
+ * fixture方法只对@State对象有意义,否则,JHM在编译时会报错。
+ *
+ * 与State一样,fixture方法仅被那些使用state的benchmark线程调用。 这意味着你可以在线程本地上下文中操作,
+ * 并且(不)使用同步,就像你在benchmark线程的上下文中执行一样。
+ *
+ * 注意:fixture方法也可以使用静态字段,尽管这些操作的语义从State范围中退出,并遵守通常的Java规则(即每个类一个静态字段)。
+ */
+
+ /*
+ * Level默认每个@Benchmark前执行
+ * Ok, let's prepare our benchmark:
+ */
+
+ @Setup
+ public void prepare() {
+ x = Math.PI;
+ }
+
+ /*
+ * Level默认每个@TearDown后执行
+ * And, check the benchmark went fine afterwards:
+ */
+
+ @TearDown
+ public void check() {
+ assert x > Math.PI : "Nothing changed?";
+ }
+
+ /*
+ * This method obviously does the right thing, incrementing the field x
+ * in the benchmark state. check() will never fail this way, because
+ * we are always guaranteed to have at least one benchmark call.
+ */
+
+ @Benchmark
+ public void measureRight() {
+ x++;
+ }
+
+ /*
+ * This method, however, will fail the check(), because we deliberately
+ * have the "typo", and increment only the local variable. This should
+ * not pass the check, and JMH will fail the run.
+ */
+
+ @Benchmark
+ public void measureWrong() {
+ double x = 0;
+ x++;
+ }
+
+ /*
+ * java -ea //启动断言
+ * java -ea:pkname... //在包pkname及其子包下起用断言
+ * java -ea:pkname.classname //对类 pkname.classname启用断言
+ * 停用断言与启用设置类似
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_05_StateFixtures.class.getSimpleName())
+ .forks(1)
+ .jvmArgs("-ea")
+ .output("JMHSample_05_StateFixtures.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_06_FixtureLevel.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_06_FixtureLevel.java
new file mode 100644
index 00000000..c7d7bf79
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_06_FixtureLevel.java
@@ -0,0 +1,79 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * @see Level
+ * @see Setup
+ * @see TearDown
+ *
+ * @author childe
+ * @date 2018/10/8 15:36
+ **/
+@State(Scope.Thread)
+public class JMHSample_06_FixtureLevel {
+
+ private double x;
+
+ /*
+ * Fixture methods have different levels to control when they should be run.
+ * There are at least three Levels available to the user. These are, from
+ * top to bottom:
+ *
+ * Level.Trial: before or after the entire benchmark run (the sequence of iterations)
+ * Level.Iteration: before or after the benchmark iteration (the sequence of invocations)
+ * Level.Invocation; before or after the benchmark method invocation (WARNING: read the Javadoc before using)
+ *
+ * Time spent in fixture methods does not count into the performance
+ * metrics, so you can use this to do some heavy-lifting.
+ *
+ * fixture方法在运行时有几个不同的等级。
+ * 一共有三个等级供我们使用:
+ *
+ * Level.Trial:整个基准测试(一个@Benchmark注解为一个基准测试)运行之前或之后(迭代序列)
+ * Level.Iteration:在基准迭代之前或之后(调用序列)
+ * Level.Invocation:该等级表现比较复杂 @see org.openjdk.jmh.annotations.Level
+ *
+ * fixture方法的耗时不会被统计进性能指标,所以可以用它来做一些比较重的操作。
+ */
+
+ @TearDown(Level.Iteration)
+ public void check() {
+ assert x > Math.PI : "Nothing changed?";
+ }
+
+ @Benchmark
+ public void measureRight() {
+ x++;
+ }
+
+ @Benchmark
+ public void measureWrong() {
+ double x = 0;
+ x++;
+ }
+
+ /*
+ * java -ea //启动断言
+ * java -ea:pkname... //在包pkname及其子包下起用断言
+ * java -ea:pkname.classname //对类 pkname.classname启用断言
+ * 停用断言与启用设置类似
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_06_FixtureLevel.class.getSimpleName())
+ .forks(1)
+ .jvmArgs("-ea")
+ // switch to "true" to fail the complete run
+ .shouldFailOnError(false)
+ .output("JMHSample_06_FixtureLevel.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_07_FixtureLevelInvocation.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_07_FixtureLevelInvocation.java
new file mode 100644
index 00000000..6eb4c850
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_07_FixtureLevelInvocation.java
@@ -0,0 +1,137 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.*;
+
+/**
+ * Fixtures have different Levels to control when they are about to run.
+ * Level.Invocation is useful sometimes to do some per-invocation work
+ * which should not count as payload (e.g. sleep for some time to emulate
+ * think time)
+ *
+ * 在他们运行的时候fixture有不同的等级进行控制。
+ * Level.Invocation一些情况下很有用,比如:每次调用前做一些工作,并且这些工作不会被统计为有效载荷。
+ *
+ * @author childe
+ * @date 2018/10/8 17:13
+ **/
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+public class JMHSample_07_FixtureLevelInvocation {
+
+ /*
+ * Fixtures have different Levels to control when they are about to run.
+ * Level.Invocation is useful sometimes to do some per-invocation work,
+ * which should not count as payload. PLEASE NOTE the timestamping and
+ * synchronization for Level.Invocation helpers might significantly offset
+ * the measurement, use with care. See Level.Invocation javadoc for further
+ * discussion.
+ *
+ * 在他们运行的时候fixture有不同的等级进行控制。
+ * Level.Invocation一些情况下很有用,比如:每次调用前做一些工作,并且这些工作不会被统计为有效载荷。
+ * 请注意Level.Invocation助手的时间戳和同步可能会显着抵消测量,请谨慎使用。
+ *
+ * Consider this sample:
+ * 看下面的例子:
+ */
+
+ /*
+ * This state handles the executor.
+ * Note we create and shutdown executor with Level.Trial, so
+ * it is kept around the same across all iterations.
+ */
+
+ @State(Scope.Benchmark)
+ public static class NormalState {
+ ExecutorService service;
+
+ @Setup(Level.Trial)
+ public void up() {
+ System.out.println("up");
+ service = Executors.newCachedThreadPool();
+ }
+
+ @TearDown(Level.Trial)
+ public void down() {
+ service.shutdown();
+ }
+
+ }
+
+ /*
+ * This is the *extension* of the basic state, which also
+ * has the Level.Invocation fixture method, sleeping for some time.
+ *
+ * @State 是可继承的
+ */
+
+ public static class LaggingState extends NormalState {
+ static final int SLEEP_TIME = Integer.getInteger("sleepTime", 10);
+
+ @Setup(Level.Invocation)
+ public void lag() throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
+ }
+ }
+
+ /*
+ * This allows us to formulate the task: measure the task turnaround in
+ * "hot" mode when we are not sleeping between the submits, and "cold" mode,
+ * when we are sleeping.
+ */
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ public double measureHot(NormalState e, final Scratch s) throws ExecutionException, InterruptedException {
+ return e.service.submit(new Task(s)).get();
+ }
+
+ @Benchmark
+ @BenchmarkMode(Mode.AverageTime)
+ public double measureCold(LaggingState e, final Scratch s) throws ExecutionException, InterruptedException {
+ return e.service.submit(new Task(s)).get();
+ }
+
+ /*
+ * This is our scratch state which will handle the work.
+ */
+
+ @State(Scope.Thread)
+ public static class Scratch {
+
+ private double p;
+
+ private double doWork() {
+ p = Math.log(p);
+ return p;
+ }
+ }
+
+ public static class Task implements Callable {
+ private Scratch s;
+
+ private Task(Scratch s) {
+ this.s = s;
+ }
+
+ @Override
+ public Double call() {
+ return s.doWork();
+ }
+ }
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_07_FixtureLevelInvocation.class.getSimpleName())
+ .forks(1)
+ .output("JMHSample_07_FixtureLevelInvocation.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_08_DeadCode.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_08_DeadCode.java
new file mode 100644
index 00000000..7d3873e4
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_08_DeadCode.java
@@ -0,0 +1,74 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Dead-Code Elimination (DCE)
+ * 死代码消除对基准测试造成的影响
+ *
+ * @author childe
+ * @date 2018/10/9 11:18
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_08_DeadCode {
+
+ /*
+ * The downfall of many benchmarks is Dead-Code Elimination (DCE): compilers
+ * are smart enough to deduce some computations are redundant and eliminate
+ * them completely. If the eliminated part was our benchmarked code, we are
+ * in trouble.
+ *
+ * Fortunately, JMH provides the essential infrastructure to fight this
+ * where appropriate: returning the result of the computation will ask JMH
+ * to deal with the result to limit dead-code elimination (returned results
+ * are implicitly consumed by Blackholes, see JMHSample_09_Blackholes).
+ *
+ * 许多基准测试的失败是死代码消除(DCE):
+ * 编译器非常聪明,可以推断出一些冗余的计算并完全消除它们。
+ * 如果被淘汰的部分是我们的基准代码,我们就遇到了麻烦。
+ *
+ * 幸运的是JMH提供了必要的基础设施,以便在适当的时候来避免这种情况:返回计算结果将要求JMH进行处理以限制死码消除(
+ * 返回的结果可以饮食被Blackholes消费,参见 JMHSample_09_Blackholes
+ * )
+ */
+
+ private double x = Math.PI;
+
+ @Benchmark
+ public void baseline() {
+ // do nothing, this is a baseline
+ // 基准线
+ }
+
+ @Benchmark
+ public void measureWrong() {
+ // This is wrong: result is not used and the entire computation is optimized away.
+ // 这是错误的:结果没有被使用,整个计算将会被编译器优化。
+ Math.log(x);
+ }
+
+ @Benchmark
+ public double measureRight() {
+ // This is correct: the result is being used.
+ return Math.log(x);
+ }
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_08_DeadCode.class.getSimpleName())
+ .output("JMHSample_08_DeadCode.sampleLog")
+ .forks(1)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_09_Blackholes.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_09_Blackholes.java
new file mode 100644
index 00000000..ca6857ed
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_09_Blackholes.java
@@ -0,0 +1,101 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 死代码消除解决
+ *
+ * @author childe
+ * @date 2018/10/9 11:44
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Thread)
+public class JMHSample_09_Blackholes {
+
+ /*
+ * Should your benchmark require returning multiple results, you have to
+ * consider two options (detailed below).
+ *
+ * NOTE: If you are only producing a single result, it is more readable to
+ * use the implicit return, as in JMHSample_08_DeadCode. Do not make your benchmark
+ * code less readable with explicit Blackholes!
+ *
+ * 你的基准测试是否需要返回付哦个测试结果,你需要考虑下民两个问题。
+ * 注意:如果你只会产生一个结果,应该使用更易读的明确return,就像JMHSample_08_DeadCode。
+ * 不要使用明确的Blackholes来降低您的基准代码的可读性!
+ */
+
+ double x1 = Math.PI;
+ double x2 = Math.PI * 2;
+
+ /*
+ * Baseline measurement: how much single Math.sampleLog costs.
+ */
+
+ @Benchmark
+ public double baseline() {
+ return Math.log(x1);
+ }
+
+ /*
+ * While the Math.sampleLog(x2) computation is intact(完好), Math.sampleLog(x1)
+ * is redundant and optimized out.
+ */
+
+ @Benchmark
+ public double measureWrong() {
+ Math.log(x1);
+ return Math.log(x2);
+ }
+
+ /*
+ * This demonstrates(演示) Option A:
+ *
+ * Merge multiple results into one and return it.
+ * This is OK when is computation is relatively heavyweight, and merging
+ * the results does not offset the results much.
+ *
+ * 演示选项A:
+ * 合并多个结果并返回。
+ * 这种方式行得通,但相对较重,并且这个结果不会对结果有太大影响。
+ */
+
+ @Benchmark
+ public double measureRight_1() {
+ return Math.log(x1) + Math.log(x2);
+ }
+
+ /*
+ * This demonstrates Option B:
+ *
+ * Use explicit Blackhole objects, and sink the values there.
+ * (Background: Blackhole is just another @State object, bundled with JMH).
+ *
+ * 演示选项B:
+ * 明确的使用Blackhole对象,并且把值汇入。
+ * (背后:Blackhole就像另一个@State对象,绑定在JMH)。
+ */
+
+ @Benchmark
+ public void measureRight_2(Blackhole bh) {
+ bh.consume(Math.log(x1));
+ bh.consume(Math.log(x2));
+ }
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_09_Blackholes.class.getSimpleName())
+ .forks(1)
+ .build();
+
+ new Runner(opt).run();
+ }
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_10_ConstantFold.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_10_ConstantFold.java
new file mode 100644
index 00000000..992a7d72
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_10_ConstantFold.java
@@ -0,0 +1,84 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * DCE的常量折叠(constant-folding)
+ *
+ * @author childe
+ * @date 2018/10/9 14:27
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_10_ConstantFold {
+
+ /*
+ * The flip side of dead-code elimination is constant-folding.
+ *
+ * If JVM realizes the result of the computation is the same no matter what,
+ * it can cleverly optimize it. In our case, that means we can move the
+ * computation outside of the internal JMH loop.
+ *
+ * This can be prevented by always reading the inputs from non-final
+ * instance fields of @State objects, computing the result based on those
+ * values, and follow the rules to prevent DCE.
+ *
+ * 死代码消除的另一面是常量折叠。
+ * 如果JVM意识到计算结果不管怎样计算都是不变的,他便会巧妙的优化掉。
+ * 在我们的例子中,这意味着我们可以把计算移到JMH内部循环之外。
+ *
+ * 这可以通过始终从@State对象的non-final字段读取输入,根据这些值计算结果,并遵循规则来防止DCE。
+ */
+
+ // IDEs will say "Oh, you can convert this field to local variable". Don't. Trust. Them.
+ // (While this is normally fine advice, it does not work in the context of measuring correctly.)
+ // 哈哈,竟然言中
+ private double x = Math.PI;
+
+ // IDEs will probably also say "Look, it could be final". Don't. Trust. Them. Either.
+ // (While this is normally fine advice, it does not work in the context of measuring correctly.)
+ // 哈哈,原因说错了
+
+ private final double wrongX = Math.PI;
+
+ @Benchmark
+ public double baseline() {
+ // simply return the value, this is a baseline
+ return Math.PI;
+ }
+
+ @Benchmark
+ public double measureWrong_1() {
+ // This is wrong: the source is predictable, and computation is foldable.
+ return Math.log(Math.PI);
+ }
+
+ @Benchmark
+ public double measureWrong_2() {
+ // This is wrong: the source is predictable, and computation is foldable.
+ return Math.log(wrongX);
+ }
+
+ @Benchmark
+ public double measureRight() {
+ // This is correct: the source is not predictable.
+ return Math.log(x);
+ }
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_10_ConstantFold.class.getSimpleName())
+ .forks(1)
+ .output("JMHSample_10_ConstantFold.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_11_Loops.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_11_Loops.java
new file mode 100644
index 00000000..9eb1b16a
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_11_Loops.java
@@ -0,0 +1,134 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基准测试方法中进行循环是坏做法
+ *
+ * @author childe
+ * @date 2018/10/9 15:51
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_11_Loops {
+
+ /*
+ * It would be tempting for users to do loops within the benchmarked method.
+ * (This is the bad thing Caliper taught everyone). These tests explain why
+ * this is a bad idea.
+ *
+ * Looping is done in the hope of minimizing the overhead of calling the
+ * test method, by doing the operations inside the loop instead of inside
+ * the method call. Don't buy this argument; you will see there is more
+ * magic happening when we allow optimizers to merge the loop iterations.
+ *
+ * 在基准测试方法中做循环是很诱人的。这是Caliper教给大家的坏事情。以下测试告诉你原因。
+ *
+ * 循环是为了通过在循环内而不是在方法调用内部进行操作来最小化调用测试方法的开销。???
+ * 不要买这个论点;当我们允许优化器合并循环迭代时,你会发现有更多的魔法发生。
+ */
+
+ /*
+ * Suppose we want to measure how much it takes to sum two integers:
+ */
+
+ int x = 1;
+ int y = 2;
+
+ /*
+ * This is what you do with JMH.
+ */
+
+ @Benchmark
+ public int measureRight() {
+ return (x + y);
+ }
+
+ /*
+ * The following tests emulate the naive looping.
+ * This is the Caliper-style benchmark.
+ *
+ * Caliper风格的基准测试
+ */
+
+ private int reps(int reps) {
+ int s = 0;
+ for (int i = 0; i < reps; i++) {
+ s += (x + y);
+ }
+ return s;
+ }
+
+ /*
+ * We would like to measure this with different repetitions count.
+ * Special annotation is used to get the individual operation cost.
+ */
+
+ @Benchmark
+ @OperationsPerInvocation(1)
+ public int measureWrong_1() {
+ return reps(1);
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(10)
+ public int measureWrong_10() {
+ return reps(10);
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(100)
+ public int measureWrong_100() {
+ return reps(100);
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(1000)
+ public int measureWrong_1000() {
+ return reps(1000);
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(10000)
+ public int measureWrong_10000() {
+ return reps(10000);
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(100000)
+ public int measureWrong_100000() {
+ return reps(100000);
+ }
+
+ /*
+ * You might notice the larger the repetitions count, the lower the "perceived"
+ * cost of the operation being measured. Up to the point we do each addition with 1/20 ns,
+ * well beyond what hardware can actually do.
+ *
+ * This happens because the loop is heavily unrolled/pipelined, and the operation
+ * to be measured is hoisted from the loop. Morale: don't overuse loops, rely on JMH
+ * to get the measurement right.
+ *
+ * 你可能已经注意到,循环次数阅读,统计出来的时间越短。到目前位置,每次操作的时间已经是1/20 ns,远远超过硬件的实际能力。
+ *
+ * 发生这种情况是因为循环被大量unrolled/pipelined,并且要从循环中提升要测量的操作。规则:不要过度使用循环,依靠JMH来正确测量。
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_11_Loops.class.getSimpleName())
+ .forks(1)
+ .output("JMHSample_11_Loops.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_12_Forking.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_12_Forking.java
new file mode 100644
index 00000000..b9b514d9
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_12_Forking.java
@@ -0,0 +1,162 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Use non-forked runs only for debugging purposes, not for actual performance runs
+ * 使用non-forked运行仅用于调试目的,而不是用于实际性能运行
+ *
+ * @author childe
+ * @date 2018/10/9 17:17
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_12_Forking {
+
+ /*
+ * JVMs are notoriously good at profile-guided optimizations. This is bad
+ * for benchmarks, because different tests can mix their profiles together,
+ * and then render the "uniformly bad" code for every test. Forking (running
+ * in a separate process) each test can help to evade this issue.
+ *
+ * JMH will fork the tests by default.
+ *
+ * JVM擅长profile-guided优化。但这对基准不友好,因为不同的测试可以把他们的profiles混合在一起,
+ * 然后为每一个测试渲染"uniformly bad"代码???。forking(运行在不同的进程)每个测试可以避免这个问题。
+ *
+ * JMH默认fork所有test。
+ */
+
+ /*
+ * Suppose we have this simple counter interface, and two implementations.
+ * Even though those are semantically the same, from the JVM standpoint,
+ * those are distinct classes.
+ *
+ * 假设我们又一个简单的统计接受,并且有两个实现。
+ * 即使他们逻辑相同,站在JVM角度看他们是不同的类。
+ */
+
+ public interface Counter {
+ int inc();
+ }
+
+ public class Counter1 implements Counter {
+ private int x;
+
+ @Override
+ public int inc() {
+ return x++;
+ }
+ }
+
+ public class Counter2 implements Counter {
+ private int x;
+
+ @Override
+ public int inc() {
+ return x++;
+ }
+ }
+
+ /*
+ * And this is how we measure it.
+ * Note this is susceptible for same issue with loops we mention in previous examples.
+ */
+
+ public int measure(Counter c) {
+ int s = 0;
+ for (int i = 0; i < 10; i++) {
+ s += c.inc();
+ }
+ return s;
+ }
+
+ /*
+ * These are two counters.
+ */
+
+ Counter c1 = new Counter1();
+ Counter c2 = new Counter2();
+
+ /*
+ * We first measure the Counter1 alone...
+ * Fork(0) helps to run in the same JVM.
+ */
+
+ @Benchmark
+ @Fork(0)
+ public int measure_1_c1() {
+ return measure(c1);
+ }
+
+ /*
+ * Then Counter2...
+ */
+
+ @Benchmark
+ @Fork(0)
+ public int measure_2_c2() {
+ return measure(c2);
+ }
+
+ /*
+ * Then Counter1 again...
+ */
+
+ @Benchmark
+ @Fork(0)
+ public int measure_3_c1_again() {
+ return measure(c1);
+ }
+
+ /*
+ * These two tests have explicit @Fork annotation.
+ * JMH takes this annotation as the request to run the test in the forked JVM.
+ * It's even simpler to force this behavior for all the tests via the command
+ * line option "-f". The forking is default, but we still use the annotation
+ * for the consistency.
+ *
+ * This is the test for Counter1.
+ */
+
+ @Benchmark
+ @Fork(1)
+ public int measure_4_forked_c1() {
+ return measure(c1);
+ }
+
+ /*
+ * ...and this is the test for Counter2.
+ */
+
+ @Benchmark
+ @Fork(1)
+ public int measure_5_forked_c2() {
+ return measure(c2);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note that C1 is faster, C2 is slower, but the C1 is slow again! This is because
+ * the profiles for C1 and C2 had merged together.
+ *
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_12_Forking.class.getSimpleName())
+ .output("JMHSample_12_Forking.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_13_RunToRun.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_13_RunToRun.java
new file mode 100644
index 00000000..8dfd39b9
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_13_RunToRun.java
@@ -0,0 +1,118 @@
+package com.renchao.jmh;
+
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * run-to-run variance
+ * 运行间差异
+ *
+ * @author childe
+ * @date 2018/10/10 09:16
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+public class JMHSample_13_RunToRun {
+
+ /*
+ * Forking also allows to estimate run-to-run variance.
+ *
+ * JVMs are complex systems, and the non-determinism is inherent for them.
+ * This requires us to always account the run-to-run variance as the one
+ * of the effects in our experiments.
+ *
+ * Luckily, forking aggregates the results across several JVM launches.
+ *
+ * fork还允许估计运行间的差异。
+ * JVM是复杂的系统,非决定论是他们固有的。
+ * 这要求我们始终将运行间差异视为我们实验中的影响之一。
+ *
+ * 幸运的是,fork聚合了多个JVM启动的结果。
+ */
+
+ /*
+ * In order to introduce readily measurable run-to-run variance, we build
+ * the workload which performance differs from run to run. Note that many workloads
+ * will have the similar behavior, but we do that artificially to make a point.
+ *
+ * 为了引入易于测量的逐次运行差异,我们构建了性能因运行而异的工作负载。
+ * 许多工作负载都会有类似的行为,但我们会人为地指出这一点。
+ */
+
+ @State(Scope.Thread)
+ public static class SleepyState {
+ public long sleepTime;
+
+ @Setup
+ public void setup() {
+ // 每次fork都会执行,fork相当于重复多次某个被标记@Benchmark注解的方法,但它会合并结果。
+ sleepTime = (long) (Math.random() * 1000);
+ }
+ }
+
+ /*
+ * Now, we will run this different number of times.
+ */
+
+ @Benchmark
+ @Fork(1)
+ public void baseline(SleepyState s) throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(s.sleepTime);
+ }
+
+ @Benchmark
+ @Fork(5)
+ public void fork_1(SleepyState s) throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(s.sleepTime);
+ }
+
+ @Benchmark
+ @Fork(20)
+ public void fork_2(SleepyState s) throws InterruptedException {
+ TimeUnit.MILLISECONDS.sleep(s.sleepTime);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note the baseline is random within [0..1000] msec; and both forked runs
+ * are estimating the average 500 msec with some confidence.
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_13 -wi 0 -i 3
+ * (we requested no warmup, 3 measurement iterations; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_13_RunToRun.class.getSimpleName())
+ .warmupIterations(0)
+ .measurementIterations(3)
+ .output("JMHSample_13_RunToRun.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_15_Asymmetric.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_15_Asymmetric.java
new file mode 100644
index 00000000..30536a3d
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_15_Asymmetric.java
@@ -0,0 +1,122 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Group;
+import org.openjdk.jmh.annotations.GroupThreads;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 非对称分组执行
+ *
+ * 例子场景:生产者/消费者
+ *
+ * @author childe
+ * @date 2018/10/10 10:40
+ **/
+@State(Scope.Group)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_15_Asymmetric {
+
+ /*
+ * So far all the tests were symmetric: the same code was executed in all the threads.
+ * At times, you need the asymmetric test. JMH provides this with the notion of @Group,
+ * which can bind several methods together, and all the threads are distributed among
+ * the test methods.
+ *
+ * Each execution group contains of one or more threads. Each thread within a particular
+ * execution group executes one of @Group-annotated @Benchmark methods. Multiple execution
+ * groups may participate in the run. The total thread count in the run is rounded to the
+ * execution group size, which will only allow the full execution groups.
+ *
+ * Note that two state scopes: Scope.Benchmark and Scope.Thread are not covering all
+ * the use cases here -- you either share everything in the state, or share nothing.
+ * To break this, we have the middle ground Scope.Group, which marks the state to be
+ * shared within the execution group, but not among the execution groups.
+ *
+ * Putting this all together, the example below means:
+ * a) define the execution group "g", with 3 threads executing inc(), and 1 thread
+ * executing get(), 4 threads per group in total;
+ * b) if we run this test case with 4 threads, then we will have a single execution
+ * group. Generally, running with 4*N threads will create N execution groups, etc.;
+ * c) each execution group has one @State instance to share: that is, execution groups
+ * share the counter within the group, but not across the groups.
+ *
+ * 到目前位置,我们的测试都是对称的:所有的线程都运行相同的代码。
+ * 是时候了解非对称测试了。JMH提供了@Group注解来把几个方法绑定到一起,所有线程都分布在测试方法中。
+ *
+ * 每个执行组包含一个或者多个线程。特定执行组中的每个线程执行@Group-annotated @Benchmark方法之一。
+ * 多个执行组可以参与运行。运行中的总线程数将四舍五入为执行组大小,这将只允许完整的执行组。???
+ *
+ * 注意那两个状态的作用域:Scope.Benchmark 和 Scope.Thread没有在这个用例中覆盖 -- 你要么在状态中共享每个东西,要么不共享。
+ * 我们使用Scope.Group状态用来表明在执行组内共享,而不在组间共享。
+ *
+ * 以下事例含义:
+ * a)定义执行组"g",它有3个线程来执行inc(),1个线程来执行get(),每个分组共有4个线程;
+ * b)如果我们用4个线程来运行这个测试用例,我们将会有一个单独的执行组。通常,用4*N个线程来创建N个执行组。
+ * c)每个执行组内共享一个@State实例:也就是执行组内共享counter,而不是跨组共享。
+ */
+
+ private AtomicInteger counter;
+
+ @Setup
+ public void up() {
+ counter = new AtomicInteger();
+ }
+
+ @Benchmark
+ @Group("g")
+ @GroupThreads(3)
+ public int inc() {
+ return counter.incrementAndGet();
+ }
+
+ @Benchmark
+ @Group("g")
+ @GroupThreads(1)
+ public int get() {
+ return counter.get();
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You will have the distinct metrics for inc() and get() from this run.
+ *
+ * 在此次运行中我们讲分别获得inc()和get()的指标。
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_15 -f 1
+ * (we requested single fork; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_15_Asymmetric.class.getSimpleName())
+ .forks(1)
+ .output("JMHSample_15_Asymmetric.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_16_CompilerControl.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_16_CompilerControl.java
new file mode 100644
index 00000000..73b8fb31
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_16_CompilerControl.java
@@ -0,0 +1,161 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Method Inlining
+ * 方法内敛,是JVM对代码的编译优化,常见的编译优化 @see http://www.importnew.com/2009.html
+ *
+ * 官方白皮书
+ * From http://www.oracle.com/technetwork/java/whitepaper-135217.html#method:
+ *
+ * The frequency of virtual method invocations in the Java programming language is an important optimization bottleneck.
+ * Once the Java HotSpot adaptive optimizer has gathered information during execution about program hot spots,
+ * it not only compiles the hot spot into native code, but also performs extensive method inlining on that code.
+ *
+ * Inlining has important benefits.
+ * It dramatically reduces the dynamic frequency of method invocations, which saves the time needed to perform those method invocations.
+ * But even more importantly, inlining produces much larger blocks of code for the optimizer to work on.
+ * This creates a situation that significantly increases the effectiveness of traditional compiler optimizations,
+ * overcoming a major obstacle to increased Java programming language performance.
+ *
+ * Inlining is synergistic with other code optimizations, because it makes them more effective.
+ * As the Java HotSpot compiler matures, the ability to operate on large, inlined blocks of code will open the door to a host of even more advanced optimizations in the future.
+ *
+ * Java编程语言中虚拟方法调用的频率是一个重要的优化瓶颈。
+ * 一旦Java HotSpot自适应优化器在执行期间收集有关程序热点的信息,它不仅将热点编译为本机代码,而且还对该代码执行大量方法内联。
+ *
+ * 内联具有重要的好处。
+ * 它大大降低了方法调用的动态频率,从而节省了执行这些方法调用所需的时间。
+ * 但更重要的是,内联会为优化程序生成更大的代码块。
+ * 这创造了一种能够显着提高传统编译器优化效率的情况,克服了增加Java编程语言性能的主要障碍。
+ *
+ * 内联与其他代码优化具有协同作用,因为它使它们更有效。
+ * 随着Java HotSpot编译器的成熟,对大型内联代码块进行操作的能力将为未来的一系列更高级的优化打开大门。
+ *
+ * @author childe
+ * @date 2018/10/10 14:16
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_16_CompilerControl {
+
+ /*
+ * We can use HotSpot-specific functionality to tell the compiler what
+ * do we want to do with particular methods. To demonstrate the effects,
+ * we end up with 3 methods in this sample.
+ *
+ * 我们使用HotSpot特定的功能来告诉编译器我们想对特定的方法做怎么。
+ * 为了证明这种效果,我们在这个例子中写了三个测试方法。
+ */
+
+ /**
+ * These are our targets:
+ * - first method is prohibited from inlining
+ * - second method is forced to inline
+ * - third method is prohibited from compiling
+ *
+ * We might even place the annotations directly to the benchmarked
+ * methods, but this expresses the intent more clearly.
+ *
+ * 这是我们的目标:
+ * - 第一个方法禁止内敛
+ * - 第二个方法强制内敛
+ * - 第三个方法禁止编译
+ *
+ * 我们甚至可以将注释直接放在基准测试方法中,但这更清楚地表达了意图。
+ */
+
+ public void target_blank() {
+ // this method was intentionally left blank
+ // 方法故意留空
+ }
+
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public void target_dontInline() {
+ // this method was intentionally left blank
+ }
+
+ @CompilerControl(CompilerControl.Mode.INLINE)
+ public void target_inline() {
+ // this method was intentionally left blank
+ }
+
+ /**
+ * Exclude the method from the compilation.
+ */
+ @CompilerControl(CompilerControl.Mode.EXCLUDE)
+ public void target_exclude() {
+ // this method was intentionally left blank
+ }
+
+ /*
+ * These method measures the calls performance.
+ *
+ * 这些方法来测量调用性能。
+ */
+
+ @Benchmark
+ public void baseline() {
+ // this method was intentionally left blank
+ }
+
+ @Benchmark
+ public void blank() {
+ target_blank();
+ }
+
+ @Benchmark
+ public void dontinline() {
+ target_dontInline();
+ }
+
+ @Benchmark
+ public void inline() {
+ target_inline();
+ }
+
+ @Benchmark
+ public void exclude() {
+ target_exclude();
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note the performance of the baseline, blank, and inline methods are the same.
+ * dontinline differs a bit, because we are making the proper call.
+ * exclude is severely slower, becase we are not compiling it at all.
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_16 -wi 0 -i 3 -f 1
+ * (we requested no warmup iterations, 3 iterations, single fork; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_16_CompilerControl.class.getSimpleName())
+ .warmupIterations(0)
+ .measurementIterations(3)
+ .forks(1)
+ .output("JMHSample_16_CompilerControl.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_17_SyncIterations.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_17_SyncIterations.java
new file mode 100644
index 00000000..51bbb976
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_17_SyncIterations.java
@@ -0,0 +1,117 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/11 17:01
+ **/
+@State(Scope.Thread)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+public class JMHSample_17_SyncIterations {
+
+ /*
+ * This is the another thing that is enabled in JMH by default.
+ *
+ * Suppose we have this simple benchmark.
+ */
+
+ private double src;
+
+ @Benchmark
+ public double test() {
+ double s = src;
+ for (int i = 0; i < 1000; i++) {
+ s = Math.sin(s);
+ }
+ return s;
+ }
+
+ /*
+ * It turns out if you run the benchmark with multiple threads,
+ * the way you start and stop the worker threads seriously affects
+ * performance.
+ *
+ * The natural way would be to park all the threads on some sort
+ * of barrier, and the let them go "at once". However, that does
+ * not work: there are no guarantees the worker threads will start
+ * at the same time, meaning other worker threads are working
+ * in better conditions, skewing the result.
+ *
+ * The better solution would be to introduce bogus iterations,
+ * ramp up the threads executing the iterations, and then atomically
+ * shift the system to measuring stuff. The same thing can be done
+ * during the rampdown. This sounds complicated, but JMH already
+ * handles that for you.
+ *
+ * 事实证明如果你用多线程来跑benchmark,你启动和停止工作线程的方式会严重影响性能。
+ *
+ * 通常的做法是,让所有的线程都挂起在一些有序的屏障上,然后让他们一起开始。
+ * 然而,这种做法是不奏效的:没有谁能够保证工作线程在同一时间开始,这就意味着其他工作线程在更好的条件下运行,从而扭曲了结果。
+ *
+ * 更好的解决方案是引入虚假迭代,增加执行迭代的线程,然后将系统原子地转换为测量内容。在减速期间可以做同样的事情。
+ * 这听起来很复杂,但是JMH已经帮你处理好了。
+ */
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You will need to oversubscribe the system to make this effect
+ * clearly visible; however, this effect can also be shown on the
+ * unsaturated systems.*
+ *
+ * 您需要超额预订系统才能使此效果清晰可见;然而,这种效应也可以在不饱和系统上显示出来。
+ *
+ * Note the performance of -si false version is more flaky, even
+ * though it is "better". This is the false improvement, granted by
+ * some of the threads executing in solo. The -si true version more stable
+ * and coherent.
+ *
+ * -si false版本的性能更加不稳定,即使它“更好”。 -si true版本更稳定,更连贯。
+ *
+ * -si true is enabled by default.
+ *
+ * Say, $CPU is the number of CPUs on your machine.
+ *
+ * You can run this test with:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_17 \
+ * -w 1s -r 1s -f 1 -t ${CPU*16} -si {true|false}
+ * (we requested shorter warmup/measurement iterations, single fork,
+ * lots of threads, and changeable "synchronize iterations" option)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_17_SyncIterations.class.getSimpleName())
+ .warmupTime(TimeValue.seconds(1))
+ .measurementTime(TimeValue.seconds(1))
+ .threads(Runtime.getRuntime().availableProcessors()*16)
+ .forks(1)
+ // try to switch to "false", default is true
+ .syncIterations(false)
+ .output("JMHSample_17_SyncIterations_false.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_18_Control.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_18_Control.java
new file mode 100644
index 00000000..6ad50c28
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_18_Control.java
@@ -0,0 +1,91 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Group;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.infra.Control;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * 同benchmark交互
+ * @see Control
+ * @author childe
+ * @date 2018/10/12 15:12
+ **/
+@State(Scope.Group)
+public class JMHSample_18_Control {
+
+ /*
+ * Sometimes you need the tap into the harness mind to get the info
+ * on the transition change. For this, we have the experimental state object,
+ * Control, which is updated by JMH as we go.
+ *
+ * 有时您需要点击线束头脑以获取有关转换更改的信息。为此,我们有实验状态对象Control,它由JMH随时更新。
+ *
+ * WARNING: The API for Contro class is considered unstable, and can be changed without notice.
+ */
+
+ /*
+ * In this example, we want to estimate the ping-pong speed for the simple
+ * AtomicBoolean. Unfortunately, doing that in naive manner will livelock
+ * one of the threads, because the executions of ping/pong are not paired
+ * perfectly. We need the escape hatch to terminate the loop if threads
+ * are about to leave the measurement.
+ *
+ * 在这个例子中,我们想要估计简单的AtomicBoolean的ping / pong速度。
+ * 不幸的是,以天真的方式执行此操作将会锁定其中一个线程,因为ping / pong的执行不能完美配对。
+ * 如果线程即将离开测量,我们需要"逃生舱口"来终止循环。
+ */
+
+ public final AtomicBoolean flag = new AtomicBoolean();
+
+ @Benchmark
+ @Group("pingpong")
+ public void ping(Control cnt) {
+ // 业务在迭代时间未结束前,一直运行。
+ while (!cnt.stopMeasurement && !flag.compareAndSet(false, true)) {
+ // this body is intentionally left blank
+ }
+ }
+
+ @Benchmark
+ @Group("pingpong")
+ public void pong(Control cnt) {
+ while (!cnt.stopMeasurement && !flag.compareAndSet(true, false)) {
+ // this body is intentionally left blank
+ }
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_18 -t 2 -f 1
+ * (we requested 2 threads and single fork; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_18_Control.class.getSimpleName())
+ .threads(2)
+ .forks(1)
+ .output("JMHSample_18_Control.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_20_Annotations.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_20_Annotations.java
new file mode 100644
index 00000000..480b8b47
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_20_Annotations.java
@@ -0,0 +1,79 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 基于注解的基准测试
+ *
+ * @author childe
+ * @date 2018/10/12 16:28
+ **/
+@State(Scope.Thread)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Fork(1)
+public class JMHSample_20_Annotations {
+
+ double x1 = Math.PI;
+
+ /*
+ * In addition to all the command line options usable at run time,
+ * we have the annotations which can provide the reasonable defaults
+ * for the some of the benchmarks. This is very useful when you are
+ * dealing with lots of benchmarks, and some of them require
+ * special treatment.
+ *
+ * Annotation can also be placed on class, to have the effect over
+ * all the benchmark methods in the same class. The rule is, the
+ * annotation in the closest scope takes the precedence: i.e.
+ * the method-based annotation overrides class-based annotation,
+ * etc.
+ *
+ * 除了运行时所有的命令行选项外,我们还可以通过注解给一些基准测试提供默认值。
+ * 在你处理大量基准测试时这个很有用,其中一些需要特别处理。
+ *
+ * 注解可以放在class上,来影响这个class中所有的基准测试方法。规则是,靠近作用域的注解有优先权:
+ * 比如,方法上的注解可以覆盖类上的注解。
+ *
+ * 注意:命令行优先级最高。
+ */
+
+ @Benchmark
+ @Warmup(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+ public double measure() {
+ return Math.log(x1);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note JMH honors the default annotation settings. You can always override
+ * the defaults via the command line or API.
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_20
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_20_Annotations.class.getSimpleName())
+ .output("JMHSample_20_Annotations.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_21_ConsumeCPU.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_21_ConsumeCPU.java
new file mode 100644
index 00000000..2305f530
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_21_ConsumeCPU.java
@@ -0,0 +1,139 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Consume some amount of time tokens.
+ *
+ * 消费一些时间令牌。
+ *
+ * 有时测试消耗一定CPU周期。通过静态的BlackHole.consumeCPU(tokens)方法来实现。
+ * Token是一些CPU指令。这样编写方法代码就可以达到运行时间依赖于该参数的目的(不被任何JIT/CPU优化)。
+ *
+ * @author childe
+ * @date 2018/10/13 15:03
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_21_ConsumeCPU {
+
+ /*
+ * At times you require the test to burn some of the cycles doing nothing.
+ * In many cases, you *do* want to burn the cycles instead of waiting.
+ *
+ * For these occasions, we have the infrastructure support. Blackholes
+ * can not only consume the values, but also the time! Run this test
+ * to get familiar with this part of JMH.
+ *
+ * (Note we use static method because most of the use cases are deep
+ * within the testing code, and propagating blackholes is tedious).
+ *
+ * 有时你需要测试来烧掉一些无所事事的循环。
+ * 在许多情况下,你想要燃烧周期而不是等待。
+ *
+ * 在这些场合,我们有基础设施支持。
+ * Blackhole不仅可以消耗数值,还可以消耗时间!运行此测试以熟悉JMH的这一部分。
+ *
+ * (注意:我们使用静态方法,因为大多数用例都在测试代码的深处,传播Blackhole很繁琐)
+ */
+
+ @Benchmark
+ public void consume_0000() {
+ Blackhole.consumeCPU(0);
+ }
+
+ @Benchmark
+ public void consume_0001() {
+ Blackhole.consumeCPU(1);
+ }
+
+ @Benchmark
+ public void consume_0002() {
+ Blackhole.consumeCPU(2);
+ }
+
+ @Benchmark
+ public void consume_0004() {
+ Blackhole.consumeCPU(4);
+ }
+
+ @Benchmark
+ public void consume_0008() {
+ Blackhole.consumeCPU(8);
+ }
+
+ @Benchmark
+ public void consume_0016() {
+ Blackhole.consumeCPU(16);
+ }
+
+ @Benchmark
+ public void consume_0032() {
+ Blackhole.consumeCPU(32);
+ }
+
+ @Benchmark
+ public void consume_0064() {
+ Blackhole.consumeCPU(64);
+ }
+
+ @Benchmark
+ public void consume_0128() {
+ Blackhole.consumeCPU(128);
+ }
+
+ @Benchmark
+ public void consume_0256() {
+ Blackhole.consumeCPU(256);
+ }
+
+ @Benchmark
+ public void consume_0512() {
+ Blackhole.consumeCPU(512);
+ }
+
+ @Benchmark
+ public void consume_1024() {
+ Blackhole.consumeCPU(1024);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note the single token is just a few cycles, and the more tokens
+ * you request, then more work is spent (almost linearly)
+ *
+ * 注意:单个token只有几个周期,请求的令牌越多则消耗更多的工作(近乎线性)
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_21 -f 1
+ * (we requested single fork; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_21_ConsumeCPU.class.getSimpleName())
+ .forks(1)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_23_AuxCounters.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_23_AuxCounters.java
new file mode 100644
index 00000000..16eef333
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_23_AuxCounters.java
@@ -0,0 +1,104 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * AuxCounters是实验类,慎用!未来可能删除。
+ * CAVEAT: THIS IS AN EXPERIMENTAL API, it may be changed or removed in future without prior warning.
+ *
+ * 所以不深入了解了。大意是作为@State的辅助类,可以分别统计操作对象的每个字段值。
+ * @author childe
+ * @date 2018/10/16 15:20
+ **/
+@OutputTimeUnit(TimeUnit.SECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(1)
+public class JMHSample_23_AuxCounters {
+
+ /*
+ * In some weird cases you need to get the separate throughput/time
+ * metrics for the benchmarked code depending on the outcome of the
+ * current code. Trying to accommodate the cases like this, JMH optionally
+ * provides the special annotation which treats @State objects
+ * as the object bearing user counters. See @AuxCounters javadoc for
+ * the limitations.
+ */
+
+ @State(Scope.Thread)
+ @AuxCounters(AuxCounters.Type.OPERATIONS)
+ public static class OpCounters {
+ // These fields would be counted as metrics
+ public int case1;
+ public int case2;
+
+ // This accessor will also produce a metric
+ public int total() {
+ return case1 + case2;
+ }
+ }
+
+ @State(Scope.Thread)
+ // 计算“事件”,即工作量生命周期中的一次性事件。此计数器不会按时间标准化。
+ @AuxCounters(AuxCounters.Type.EVENTS)
+ public static class EventCounters {
+ // This field would be counted as metric
+ public int wows;
+ }
+
+ /*
+ * This code measures the "throughput" in two parts of the branch.
+ * The @AuxCounters state above holds the counters which we increment
+ * ourselves, and then let JMH to use their values in the performance
+ * calculations.
+ */
+
+ @Benchmark
+ public void splitBranch(OpCounters counters) {
+ if (Math.random() < 0.1) {
+ counters.case1++;
+ } else {
+ counters.case2++;
+ }
+ }
+
+ @Benchmark
+ public void runSETI(EventCounters counters) {
+ float random = (float) Math.random();
+ float wowSignal = (float) Math.PI / 4;
+ if (random == wowSignal) {
+ // WOW, that's unusual.
+ counters.wows++;
+ }
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_23
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_23_AuxCounters.class.getSimpleName())
+ .output("JMHSample_23_AuxCounters.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_24_Inheritance.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_24_Inheritance.java
new file mode 100644
index 00000000..a38c4373
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_24_Inheritance.java
@@ -0,0 +1,109 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/16 17:17
+ **/
+public class JMHSample_24_Inheritance {
+
+ /*
+ * In very special circumstances, you might want to provide the benchmark
+ * body in the (abstract) superclass, and specialize it with the concrete
+ * pieces in the subclasses.
+ *
+ * The rule of thumb is: if some class has @Benchmark method, then all the subclasses
+ * are also having the "synthetic" @Benchmark method. The caveat is, because we only
+ * know the type hierarchy during the compilation, it is only possible during
+ * the same compilation session. That is, mixing in the subclass extending your
+ * benchmark class *after* the JMH compilation would have no effect.
+ *
+ * Note how annotations now have two possible places. The closest annotation
+ * in the hierarchy wins.
+ *
+ * 我们可以使用模版模式通过抽象方法来分离实现。
+ * 经验法则是:如果一些类有@Benchmark方法,那么它所有的子类都继承@Benchmark方法。
+ * 注意,因为我们只知道编译期间的类型层次结构,所以只能在同一个编译会话期间使用。
+ * 也就是说,在JMH编译之后混合扩展benchmark类的子类将不起作用。
+ *
+ * 注释现在有两个可能的地方。靠近的注视将被采纳。
+ */
+
+ @BenchmarkMode(Mode.AverageTime)
+ @Fork(1)
+ @State(Scope.Thread)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static abstract class AbstractBenchmark {
+ int x;
+
+ @Setup
+ public void setup() {
+ x = 42;
+ }
+
+ @Benchmark
+ @Warmup(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = 5, time = 100, timeUnit = TimeUnit.MILLISECONDS)
+ public double bench() {
+ return doWork() * doWork();
+ }
+
+ protected abstract double doWork();
+ }
+
+ @BenchmarkMode(Mode.Throughput)
+ public static class BenchmarkLog extends AbstractBenchmark {
+ @Override
+ protected double doWork() {
+ return Math.log(x);
+ }
+ }
+
+ public static class BenchmarkSin extends AbstractBenchmark {
+ @Override
+ protected double doWork() {
+ return Math.sin(x);
+ }
+ }
+
+ public static class BenchmarkCos extends AbstractBenchmark {
+ @Override
+ protected double doWork() {
+ return Math.cos(x);
+ }
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test, and observe the three distinct benchmarks running the squares
+ * of Math.sampleLog, Math.sin, and Math.cos, accordingly.
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_24
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_24_Inheritance.class.getSimpleName())
+ .output("JMHSample_24_Inheritance.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_26_BatchSize.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_26_BatchSize.java
new file mode 100644
index 00000000..7dfe1c3b
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_26_BatchSize.java
@@ -0,0 +1,121 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/17 10:05
+ **/
+@State(Scope.Thread)
+public class JMHSample_26_BatchSize {
+
+ /*
+ * Sometimes you need to evaluate operation which doesn't have
+ * the steady state. The cost of a benchmarked operation may
+ * significantly vary from invocation to invocation.
+ *
+ * In this case, using the timed measurements is not a good idea,
+ * and the only acceptable benchmark mode is a single shot. On the
+ * other hand, the operation may be too small for reliable single
+ * shot measurement.
+ *
+ * We can use "batch size" parameter to describe the number of
+ * benchmark calls to do per one invocation without looping the method
+ * manually and protect from problems described in JMHSample_11_Loops.
+ *
+ * 有时你需要评估没有稳定状态的操作。基准操作的成本可能因调用而异。
+ *
+ * 这种情况下,使用时间检测不是一个好主意,唯一可以接受的基准模型是single shot(单次测量)。
+ * 另一方面,对于可靠的单次测量,操作可能太小。
+ *
+ * 我们可以使用“batch size”参数来描述每次调用执行的基准调用次数,而无需手动循环方法并防止JMHSample_11_Loops中描述的问题。
+ */
+
+ /*
+ * Suppose we want to measure insertion in the middle of the list.
+ */
+
+ List list = new LinkedList<>();
+
+ @Benchmark
+ @Warmup(iterations = 5, time = 1)
+ @Measurement(iterations = 5, time = 1)
+ @BenchmarkMode(Mode.AverageTime)
+ public List measureWrong_1() {
+ list.add(list.size() / 2, "something");
+ return list;
+ }
+
+ @Benchmark
+ @Warmup(iterations = 5, time = 5)
+ @Measurement(iterations = 5, time = 5)
+ @BenchmarkMode(Mode.AverageTime)
+ public List measureWrong_5() {
+ list.add(list.size() / 2, "something");
+ return list;
+ }
+
+ /*
+ * This is what you do with JMH.
+ */
+
+ @Benchmark
+ @Warmup(iterations = 5, batchSize = 5000)
+ @Measurement(iterations = 5, batchSize = 5000)
+ @BenchmarkMode(Mode.SingleShotTime)
+ public List measureRight() {
+ list.add(list.size() / 2, "something");
+ return list;
+ }
+
+ @Setup(Level.Iteration)
+ public void setup(){
+ list.clear();
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can see completely different results for measureWrong_1 and measureWrong_5; this
+ * is because the workload has no steady state. The result of the workload is dependent
+ * on the measurement time. measureRight does not have this drawback, because it measures
+ * the N invocations of the test method and measures it's time.
+ *
+ * We measure batch of 5000 invocations and consider the batch as the single operation.
+ *
+ * 您可以看到measureWrong_1和measureWrong_5的完全不同的结果;这是因为工作负载没有稳定状态。工作量的结果取决于测量时间。
+ * measureRight没有这个缺点,因为它测量测试方法的N次调用并测量它的时间。
+ *
+ * 我们测量5000次调用批次并将批次视为单个操作。
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_26 -f 1
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_26_BatchSize.class.getSimpleName())
+ .forks(1)
+ .output("JMHSample_26_BatchSize.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_27_Params.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_27_Params.java
new file mode 100644
index 00000000..41609f90
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_27_Params.java
@@ -0,0 +1,76 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.math.BigInteger;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/17 14:30
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(1)
+@State(Scope.Benchmark)
+public class JMHSample_27_Params {
+
+ /**
+ * In many cases, the experiments require walking the configuration space
+ * for a benchmark. This is needed for additional control, or investigating
+ * how the workload performance changes with different settings.
+ *
+ * 大多情况下,一个基准需要跑在不同的配置下。这需要额外的控制,或者调查工作性能如何随着不同设定改变。
+ *
+ * 如下每个arg参数会完全组合一遍certainty。
+ */
+
+ @Param({"1", "31", "65", "101", "103"})
+ public int arg;
+
+ @Param({"0", "1", "2", "4", "8", "16", "32"})
+ public int certainty;
+
+ @Benchmark
+ public boolean bench() {
+ // 该计算的时常随着certainty的变大而变长
+ return BigInteger.valueOf(arg).isProbablePrime(certainty);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note the performance is different with different parameters.
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_27
+ *
+ * You can juggle parameters through the command line, e.g. with "-p arg=41,42"
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_27_Params.class.getSimpleName())
+// .param("arg", "41", "42") // Use this to selectively constrain/override parameters
+ .output("JMHSample_27_Params.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_28_BlackholeHelpers.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_28_BlackholeHelpers.java
new file mode 100644
index 00000000..0d18c264
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_28_BlackholeHelpers.java
@@ -0,0 +1,126 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/17 15:14
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(1)
+@State(Scope.Thread)
+public class JMHSample_28_BlackholeHelpers {
+
+ /**
+ * Sometimes you need the black hole not in @Benchmark method, but in
+ * helper methods, because you want to pass it through to the concrete
+ * implementation which is instantiated in helper methods. In this case,
+ * you can request the black hole straight in the helper method signature.
+ * This applies to both @Setup and @TearDown methods, and also to other
+ * JMH infrastructure objects, like Control.
+ *
+ * Below is the variant of {@link com.cxd.benchmark.JMHSample_08_DeadCode}
+ * test, but wrapped in the anonymous classes.
+ *
+ * 有时你不需要Blackhole在@Benchmark方法中,而是在helper方法中,因为你想把它传递给在helper方法中的具体实现的实例。
+ * 在这种清凉夏,你可以通过helper方法签名获得Blackhole。
+ * 这可以应用在被标注为@Setup和@TearDown的方法上,也包括其他JMH脚手架对象,比如Control。
+ *
+ * {@link com.cxd.benchmark.JMHSample_08_DeadCode}是它的变种,但是他被包装在匿名类中。
+ */
+
+ public interface Worker {
+ void work();
+ }
+
+ private Worker workerBaseline;
+ private Worker workerRight;
+ private Worker workerWrong;
+
+ @Setup
+ public void setup(final Blackhole bh) {
+ workerBaseline = new Worker() {
+ double x;
+
+ @Override
+ public void work() {
+ // do nothing
+ }
+ };
+
+ workerWrong = new Worker() {
+ double x;
+
+ @Override
+ public void work() {
+ Math.log(x);
+ }
+ };
+
+ workerRight = new Worker() {
+ double x;
+
+ @Override
+ public void work() {
+ bh.consume(Math.log(x));
+ }
+ };
+
+ }
+
+ @Benchmark
+ public void baseline() {
+ workerBaseline.work();
+ }
+
+ @Benchmark
+ public void measureWrong() {
+ workerWrong.work();
+ }
+
+ @Benchmark
+ public void measureRight() {
+ workerRight.work();
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You will see measureWrong() running on-par with baseline().
+ * Both measureRight() are measuring twice the baseline, so the logs are intact.
+ *
+ * measureWrong()的测量结果和baseline()很相近。
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_28
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_28_BlackholeHelpers.class.getSimpleName())
+ .output("JMHSample_28_BlackholeHelpers.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_30_Interrupts.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_30_Interrupts.java
new file mode 100644
index 00000000..738a1f5c
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_30_Interrupts.java
@@ -0,0 +1,106 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.TimeValue;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/17 15:31
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Group)
+@Timeout(time = 10)
+public class JMHSample_30_Interrupts {
+
+ /*
+ * JMH can also detect when threads are stuck in the benchmarks, and try
+ * to forcefully interrupt the benchmark thread. JMH tries to do that
+ * when it is arguably sure it would not affect the measurement.
+ *
+ * JMH还可以检测线程何时卡在基准测试中,并尝试强制中断基准线程。
+ * 在可以确定它不会影响测量时,JMH会尝试这样做。
+ */
+
+ /*
+ * In this example, we want to measure the simple performance characteristics
+ * of the ArrayBlockingQueue. Unfortunately, doing that without a harness
+ * support will deadlock one of the threads, because the executions of
+ * take/put are not paired perfectly. Fortunately for us, both methods react
+ * to interrupts well, and therefore we can rely on JMH to terminate the
+ * measurement for us. JMH will notify users about the interrupt actions
+ * nevertheless, so users can see if those interrupts affected the measurement.
+ * JMH will start issuing interrupts after the default or user-specified timeout
+ * had been reached.
+ *
+ * This is a variant of org.openjdk.jmh.samples.JMHSample_18_Control, but without
+ * the explicit control objects. This example is suitable for the methods which
+ * react to interrupts gracefully.
+ *
+ * 在这个例子中,我们想测量ArrayBlockingQueue的简单性能特征。
+ * 不幸的是,在没有工具支持的情况下执行此操作会使其中一个线程死锁,因为take / put的执行不能完美配对。
+ * 幸运的是,这两种方法都能很好地应对中断,因此我们可以依赖JMH来中断测量。
+ * JMH将通知用户有关中断操作的信息,因此用户可以查看这些中断是否会影响测量。
+ * 在达到默认或用户指定的超时后,JMH将开始发出中断。
+ *
+ * 这是 {@link com.cxd.benchmark.JMHSample_18_Control}的一个变种,但是没有明确的控制对象。
+ * 这个例子很适合那些需要优雅应对中断的方法。
+ */
+
+ private BlockingQueue q;
+
+ @Setup
+ public void setup() {
+ q = new ArrayBlockingQueue<>(1);
+ }
+
+ @Group("Q")
+ @Benchmark
+ public Integer take() throws InterruptedException {
+ return q.take();
+ }
+
+ @Group("Q")
+ @Benchmark
+ public void put() throws InterruptedException {
+ q.put(42);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_30 -t 2 -f 5 -to 10
+ * (we requested 2 threads, 5 forks, and 10 sec timeout)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_30_Interrupts.class.getSimpleName())
+ .threads(2)
+ .forks(5)
+// .timeout(TimeValue.seconds(10))
+ .output("JMHSample_30_Interrupts_annotation.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_31_InfraParams.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_31_InfraParams.java
new file mode 100644
index 00000000..0171d499
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_31_InfraParams.java
@@ -0,0 +1,124 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.infra.ThreadParams;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 通过JMH提供的脚手架获取JMH的一些运行信息
+ *
+ * @author childe
+ * @date 2018/10/17 16:35
+ **/
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@State(Scope.Benchmark)
+public class JMHSample_31_InfraParams {
+
+ /*
+ * There is a way to query JMH about the current running mode. This is
+ * possible with three infrastructure objects we can request to be injected:
+ * - BenchmarkParams: covers the benchmark-global configuration
+ * - IterationParams: covers the current iteration configuration
+ * - ThreadParams: covers the specifics about threading
+ *
+ * Suppose we want to check how the ConcurrentHashMap scales under different
+ * parallelism levels. We can put concurrencyLevel in @Param, but it sometimes
+ * inconvenient if, say, we want it to follow the @Threads count. Here is
+ * how we can query JMH about how many threads was requested for the current run,
+ * and put that into concurrencyLevel argument for CHM constructor.
+ *
+ * 有一种方式用来查JMH并发运行的模型。通过请求注入以下三个脚手架对象我们就可以做到:
+ * - BenchmarkParams: 涵盖了benchmark的全局配置
+ * - IterationParams: 涵盖了当前迭代的配置
+ * - ThreadParams: 涵盖了指定线程的配置
+ *
+ * 假设我们想检查ConcurrentHashMap如何在不同的并行级别下扩展。我们可以可以把concurrencyLevel通过@Param传入,
+ * 但有时不方便,比如,我们想让他和@Threads一致。以下是我们如何查询JMH关于当前运行请求的线程数,
+ * 并将其放入ConcurrentHashMap构造函数的concurrencyLevel参数中。
+ */
+
+ static final int THREAD_SLICE = 1000;
+
+ private ConcurrentHashMap mapSingle;
+ private ConcurrentHashMap mapFollowThreads;
+
+ @Setup
+ public void setup(BenchmarkParams params) {
+ int capacity = 16 * THREAD_SLICE * params.getThreads();
+ // 并发级别数量似乎只会影响initcapacity(仅在initcapacity小于并发数量时)。这么测试好像没什么意义。
+ mapSingle = new ConcurrentHashMap<>(capacity, 0.75f, 1);
+ mapFollowThreads = new ConcurrentHashMap<>(capacity, 0.75f, params.getThreads());
+ }
+
+ /*
+ * Here is another neat trick. Generate the distinct set of keys for all threads:
+ *
+ * 这是另一个巧妙的伎俩。为所有线程生成不同的密钥集:
+ */
+
+ @State(Scope.Thread)
+ public static class Ids {
+ private List ids;
+
+ @Setup
+ public void setup(ThreadParams threads) {
+ ids = new ArrayList<>();
+ for (int c = 0; c < THREAD_SLICE; c++) {
+ ids.add("ID" + (THREAD_SLICE * threads.getThreadIndex() + c));
+ }
+ }
+ }
+
+ @Benchmark
+ public void measureDefault(Ids ids) {
+ for (String s : ids.ids) {
+ mapSingle.remove(s);
+ mapSingle.put(s, s);
+ }
+ }
+
+ @Benchmark
+ public void measureFollowThreads(Ids ids) {
+ for (String s : ids.ids) {
+ mapFollowThreads.remove(s);
+ mapFollowThreads.put(s, s);
+ }
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_31 -t 4 -f 5
+ * (we requested 4 threads, and 5 forks; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_31_InfraParams.class.getSimpleName())
+ .threads(4)
+ .forks(5)
+ .output("JMHSample_31_InfraParams.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_32_BulkWarmup.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_32_BulkWarmup.java
new file mode 100644
index 00000000..41015bc1
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_32_BulkWarmup.java
@@ -0,0 +1,131 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+import org.openjdk.jmh.runner.options.WarmupMode;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 预热方式不同测量的结果大不一样。
+ *
+ * @author childe
+ * @date 2018/10/17 17:09
+ **/
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_32_BulkWarmup {
+
+ /*
+ * This is an addendum to JMHSample_12_Forking test.
+ *
+ * Sometimes you want an opposite configuration: instead of separating the profiles
+ * for different benchmarks, you want to mix them together to test the worst-case
+ * scenario.
+ *
+ * JMH has a bulk warmup feature for that: it does the warmups for all the tests
+ * first, and then measures them. JMH still forks the JVM for each test, but once the
+ * new JVM has started, all the warmups are being run there, before running the
+ * measurement. This helps to dodge the type profile skews, as each test is still
+ * executed in a different JVM, and we only "mix" the warmup code we want.
+ *
+ * 这是JMHSample_12_Forking测试的附录。
+ *
+ * 有时你想要一个相反的配置:您可以将它们混合在一起以测试最坏情况,而不是分离不同基准的配置文件。
+ *
+ * JMH有一个批量预热特性:它首先预热所有测试,然后测量他们。JMH仍然为每个测试fork出一个JVM,但当新的JVM启动,
+ * 所有的预热在测量开始前都会执行。
+ * 这有助于避免类型配置文件偏差???,因为每个测试仍然在不同的JVM中执行,我们只“混合”我们想要的预热代码。
+ */
+
+ /*
+ * These test classes are borrowed verbatim from JMHSample_12_Forking.
+ */
+
+ public interface Counter {
+ int inc();
+ }
+
+ public class Counter1 implements Counter {
+ private int x;
+
+ @Override
+ public int inc() {
+ return x++;
+ }
+ }
+
+ public class Counter2 implements Counter {
+ private int x;
+
+ @Override
+ public int inc() {
+ return x++;
+ }
+ }
+
+ Counter c1 = new Counter1();
+ Counter c2 = new Counter2();
+
+ /*
+ * And this is our test payload. Notice we have to break the inlining of the payload,
+ * so that in could not be inlined in either measure_c1() or measure_c2() below, and
+ * specialized for that only call.
+ */
+
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public int measure(Counter c) {
+ int s = 0;
+ for (int i = 0; i < 10; i++) {
+ s += c.inc();
+ }
+ return s;
+ }
+
+ @Benchmark
+ public int measure_c1() {
+ return measure(c1);
+ }
+
+ @Benchmark
+ public int measure_c2() {
+ return measure(c2);
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * Note how JMH runs the warmups first, and only then a given test. Note how JMH re-warmups
+ * the JVM for each test. The scores for C1 and C2 cases are equally bad, compare them to
+ * the scores from JMHSample_12_Forking.
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_32 -f 1 -wm BULK
+ * (we requested a single fork, and bulk warmup mode; there are also other options, see -h)
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_32_BulkWarmup.class.getSimpleName())
+ // .includeWarmup(...) <-- this may include other benchmarks into warmup
+// .warmupMode(WarmupMode.BULK) // see other WarmupMode.* as well
+ .warmupMode(WarmupMode.INDI) // see other WarmupMode.* as well
+ .forks(1)
+ .output("JMHSample_32_BulkWarmup_indi.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_34_SafeLooping.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_34_SafeLooping.java
new file mode 100644
index 00000000..129d8a62
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_34_SafeLooping.java
@@ -0,0 +1,199 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 如何避免编译器的优化,按照预想跑循环
+ *
+ * @author childe
+ * @date 2018/10/17 17:37
+ **/
+@State(Scope.Thread)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(3)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+public class JMHSample_34_SafeLooping {
+
+ /*
+ * JMHSample_11_Loops warns about the dangers of using loops in @Benchmark methods.
+ * Sometimes, however, one needs to traverse through several elements in a dataset.
+ * This is hard to do without loops, and therefore we need to devise a scheme for
+ * safe looping.
+ *
+ * JMHSample_11_Loops警告我们在@Benchmark方法中使用循环很危险。
+ * 然而,有时我们需要便利数据集中的元素。很难避免循环,因此我们需要为安全循环设计一种方式。
+ */
+
+ /*
+ * Suppose we want to measure how much it takes to execute work() with different
+ * arguments. This mimics a frequent use case when multiple instances with the same
+ * implementation, but different data, is measured.
+ *
+ * 假设我们想要测量以不同参数运行work()时的性能。当测量具有相同实现但数据不同的多个实例时,这模仿了一个常见的用例。
+ */
+
+ static final int BASE = 42;
+
+ static int work(int x) {
+ return BASE + x;
+ }
+
+ /*
+ * Every benchmark requires control. We do a trivial control for our benchmarks
+ * by checking the benchmark costs are growing linearly with increased task size.
+ * If it doesn't, then something wrong is happening.
+ *
+ * 每个基准都需要控制。我们对的基准进行了微不足道的控制,通过检查基准成本随着任务规模的增加而线性增长。
+ * 如果没有,那么就出现了问题。
+ */
+
+ @Param({"1", "10", "100", "1000"})
+ int size;
+
+ int[] xs;
+
+ @Setup
+ public void setup() {
+ xs = new int[size];
+ for (int c = 0; c < size; c++) {
+ xs[c] = c;
+ }
+ }
+
+ /*
+ * First, the obviously wrong way: "saving" the result into a local variable would not
+ * work. A sufficiently smart compiler will inline work(), and figure out only the last
+ * work() call needs to be evaluated. Indeed, if you run it with varying $size, the score
+ * will stay the same!
+ *
+ * 首先,这个错误很明显:把结果保存在了局部变量中,这是达不到效果。一个足够只能的编译器会把work()进行内敛优化,
+ * 并指出只有最后一次work()调用需要被操作。确实,如果你用一系列$size(x数组的长度)来测试,会发现他们的结果是一样的。
+ */
+
+ @Benchmark
+ public int measureWrong_1() {
+ int acc = 0;
+ for (int x : xs) {
+ acc = work(x);
+ }
+ return acc;
+ }
+
+ /*
+ * Second, another wrong way: "accumulating" the result into a local variable. While
+ * it would force the computation of each work() method, there are software pipelining
+ * effects in action, that can merge the operations between two otherwise distinct work()
+ * bodies. This will obliterate the benchmark setup.
+ *
+ * In this example, HotSpot does the unrolled loop, merges the $BASE operands into a single
+ * addition to $acc, and then does a bunch of very tight stores of $x-s. The final performance
+ * depends on how much of the loop unrolling happened *and* how much data is available to make
+ * the large strides.
+ *
+ * 然后,另外一个错误:把计算结果保存在局部变量中。
+ * 虽然它会强制计算每个work()方法,但是有一些软件的pipelining可以合并两个不同的work()体之间的操作。这将消除基准设置。
+ *
+ * HotSpot执行unrolled循环,将$BASE操作数合并为$acc的单个添加,然后执行一堆非常紧凑的$x-s存储。
+ * 最终的性能取决于循环unrolled的次数以及可用于实现大幅度跨越的数据量。
+ */
+
+ @Benchmark
+ public int measureWrong_2() {
+ int acc = 0;
+ for (int x : xs) {
+ acc += work(x);
+ }
+ return acc;
+ }
+
+ /*
+ * Now, let's see how to measure these things properly. A very straight-forward way to
+ * break the merging is to sink each result to Blackhole. This will force runtime to compute
+ * every work() call in full. (We would normally like to care about several concurrent work()
+ * computations at once, but the memory effects from Blackhole.consume() prevent those optimization
+ * on most runtimes).
+ *
+ * 现在,让我们看下如何正确测量。一个很直接打断合并的方法就是把每个结果都下沉到Blackhole。
+ * 这会强制在运行时为每次调用work()方法都会进行计算。我们通常喜欢同时关注几个并发的work()计算,但是Blackhole.consume()的内存效果阻止了大多数运行时的优化)
+ */
+
+ @Benchmark
+ public void measureRight_1(Blackhole bh) {
+ for (int x : xs) {
+ bh.consume(work(x));
+ }
+ }
+
+ /*
+ * DANGEROUS AREA, PLEASE READ THE DESCRIPTION BELOW.
+ *
+ * Sometimes, the cost of sinking the value into a Blackhole is dominating the nano-benchmark score.
+ * In these cases, one may try to do a make-shift "sinker" with non-inlineable method. This trick is
+ * *very* VM-specific, and can only be used if you are verifying the generated code (that's a good
+ * strategy when dealing with nano-benchmarks anyway).
+ *
+ * You SHOULD NOT use this trick in most cases. Apply only where needed.
+ *
+ * 危险区域,请阅读以下解释。
+ *
+ * 有时,将结果下沉到Blackhole的花费会影响nano-benchmark的结果。
+ * 在这些情况下,我们或许可以尝试用non-inlineable的方法来做切换。?这个技巧非常特定于VM?,只有在验证生成的代码?时才能使用(这在处理nano-benchmarks时是一个很好的策略)。
+ *
+ * 大多情况下不要使用该技巧。仅在需要时使用。
+ */
+
+ @Benchmark
+ public void measureRight_2() {
+ for (int x : xs) {
+ sink(work(x));
+ }
+ }
+
+ @CompilerControl(CompilerControl.Mode.DONT_INLINE)
+ public static void sink(int v) {
+ // IT IS VERY IMPORTANT TO MATCH THE SIGNATURE TO AVOID AUTOBOXING.
+ // The method intentionally does nothing.
+ }
+
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You might notice measureWrong_1 does not depend on $size, measureWrong_2 has troubles with
+ * linearity, and otherwise much faster than both measureRight_*. You can also see measureRight_2
+ * is marginally faster than measureRight_1.
+ *
+ * 你会注意到measureWrong_1结果不受$size影响,measureWrong_2不是线性增长并且比measureRight_*要快的多。
+ * 你也会看到measureRight_2比measureRight_1稍快。
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_34
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(JMHSample_34_SafeLooping.class.getSimpleName())
+ .forks(3)
+ .output("JMHSample_34_SafeLooping.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_35_Profilers.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_35_Profilers.java
new file mode 100644
index 00000000..e8642d74
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_35_Profilers.java
@@ -0,0 +1,612 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.profile.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * 全部配置 {@link org.openjdk.jmh.profile}
+ *
+ * @author childe
+ * @date 2018/10/18 19:21
+ **/
+public class JMHSample_35_Profilers {
+ /*
+ * This sample serves as the profiler overview.
+ *
+ * JMH has a few very handy profilers that help to understand your benchmarks. While
+ * these profilers are not the substitute for full-fledged external profilers, in many
+ * cases, these are handy to quickly dig into the benchmark behavior. When you are
+ * doing many cycles of tuning up the benchmark code itself, it is important to have
+ * a quick turnaround for the results.
+ *
+ * Use -lprof to list the profilers. There are quite a few profilers, and this sample
+ * would expand on a handful of most useful ones. Many profilers have their own options,
+ * usually accessible via -prof :help.
+ *
+ * Since profilers are reporting on different things, it is hard to construct a single
+ * benchmark sample that will show all profilers in action. Therefore, we have a couple
+ * of benchmarks in this sample.
+ *
+ * 这个例子是profiler(分析器)的概览。
+ *
+ * JMH有一些很便利的profiler来帮助我们理解benchmark。
+ * 虽然这些分析器不能替代成熟的外部分析器,但在许多情况下,这些分析器很容易快速挖掘基准行为。
+ *
+ * 使用-lprof列出所有profiler。本例中只展示常用的一些。许多profiler有他们自己的选项,通过-prof :help获取。
+ *
+ * 因为profiler报告不同的事情,很难在一个基准测试中展示所有profiler的行为。因为有好几个例子。
+ *
+ * */
+
+ /*
+ * ================================ MAPS BENCHMARK ================================
+ */
+
+ @State(Scope.Thread)
+ @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+ @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+ @Fork(3)
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static class Maps {
+ private Map map;
+
+ @Param({"hashmap", "treemap"})
+ private String type;
+
+ private int begin;
+ private int end;
+
+ @Setup
+ public void setup() {
+ switch (type) {
+ case "hashmap":
+ map = new HashMap<>();
+ break;
+ case "treemap":
+ map = new TreeMap<>();
+ break;
+ default:
+ throw new IllegalStateException("Unknown type: " + type);
+ }
+
+ begin = 1;
+ end = 256;
+ for (int i = begin; i < end; i++) {
+ map.put(i, i);
+ }
+ }
+
+ @Benchmark
+ public void test(Blackhole bh) {
+ for (int i = begin; i < end; i++) {
+ bh.consume(map.get(i));
+ }
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Maps -prof stack
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Maps -prof gc
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(Maps.class.getSimpleName())
+// .addProfiler(StackProfiler.class)
+ .addProfiler(GCProfiler.class)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ /*
+ Running this benchmark will yield something like:
+
+ Benchmark (type) Mode Cnt Score Error Units
+ JMHSample_35_Profilers.Maps.test hashmap avgt 5 1553.201 ± 6.199 ns/op
+ JMHSample_35_Profilers.Maps.test treemap avgt 5 5177.065 ± 361.278 ns/op
+
+ Running with -prof stack will yield:
+
+ ....[Thread state: RUNNABLE]........................................................................
+ 99.0% 99.0% org.openjdk.jmh.samples.JMHSample_35_Profilers$Maps.test
+ 0.4% 0.4% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Maps_test.test_avgt_jmhStub
+ 0.2% 0.2% sun.reflect.NativeMethodAccessorImpl.invoke0
+ 0.2% 0.2% java.lang.Integer.valueOf
+ 0.2% 0.2% sun.misc.Unsafe.compareAndSwapInt
+
+ ....[Thread state: RUNNABLE]........................................................................
+ 78.0% 78.0% java.util.TreeMap.getEntry
+ 21.2% 21.2% org.openjdk.jmh.samples.JMHSample_35_Profilers$Maps.test
+ 0.4% 0.4% java.lang.Integer.valueOf
+ 0.2% 0.2% sun.reflect.NativeMethodAccessorImpl.invoke0
+ 0.2% 0.2% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Maps_test.test_avgt_jmhStub
+
+ Stack profiler is useful to quickly see if the code we are stressing actually executes. As many other
+ sampling profilers, it is susceptible for sampling bias: it can fail to notice quickly executing methods,
+ for example. In the benchmark above, it does not notice HashMap.get.
+
+ Stack profiler可以快速查看我们所强调的代码是否实际执行。
+ 和其他许采样分析器一样,它容易受到采样偏差的影响:它无法快速发现执行方法,例如:在上面的基准测试中,它没有注意到HashMap.get。
+
+ Next up, GC profiler. Running with -prof gc will yield:
+
+ Benchmark (type) Mode Cnt Score Error Units
+
+ JMHSample_35_Profilers.Maps.test hashmap avgt 5 1553.201 ± 6.199 ns/op
+ JMHSample_35_Profilers.Maps.test:·gc.alloc.rate hashmap avgt 5 1257.046 ± 5.675 MB/sec
+ JMHSample_35_Profilers.Maps.test:·gc.alloc.rate.norm hashmap avgt 5 2048.001 ± 0.001 B/op
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space hashmap avgt 5 1259.148 ± 315.277 MB/sec
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space.norm hashmap avgt 5 2051.519 ± 520.324 B/op
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space hashmap avgt 5 0.175 ± 0.386 MB/sec
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space.norm hashmap avgt 5 0.285 ± 0.629 B/op
+ JMHSample_35_Profilers.Maps.test:·gc.count hashmap avgt 5 29.000 counts
+ JMHSample_35_Profilers.Maps.test:·gc.time hashmap avgt 5 16.000 ms
+
+ JMHSample_35_Profilers.Maps.test treemap avgt 5 5177.065 ± 361.278 ns/op
+ JMHSample_35_Profilers.Maps.test:·gc.alloc.rate treemap avgt 5 377.251 ± 26.188 MB/sec
+ JMHSample_35_Profilers.Maps.test:·gc.alloc.rate.norm treemap avgt 5 2048.003 ± 0.001 B/op
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space treemap avgt 5 392.743 ± 174.156 MB/sec
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Eden_Space.norm treemap avgt 5 2131.767 ± 913.941 B/op
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space treemap avgt 5 0.131 ± 0.215 MB/sec
+ JMHSample_35_Profilers.Maps.test:·gc.churn.PS_Survivor_Space.norm treemap avgt 5 0.709 ± 1.125 B/op
+ JMHSample_35_Profilers.Maps.test:·gc.count treemap avgt 5 25.000 counts
+ JMHSample_35_Profilers.Maps.test:·gc.time treemap avgt 5 26.000 ms
+
+ There, we can see that the tests are producing quite some garbage. "gc.alloc" would say we are allocating 1257
+ and 377 MB of objects per second, or 2048 bytes per benchmark operation. "gc.churn" would say that GC removes
+ the same amount of garbage from Eden space every second. In other words, we are producing 2048 bytes of garbage per
+ benchmark operation.
+ 我们可以看到测试产生了相当多的垃圾。"gc.alloc"表示我们每秒分配1257和277MB内存,或者为每个基准测试操作分配了2048字节。
+ "gc.churn"表示GC每秒从Eden区域删除与GC相同量的内存。换句话说,我们每个基准测试操作产生了2048字节的垃圾。
+
+ If you look closely at the test, you can get a (correct) hypothesis this is due to Integer autoboxing.
+ 如果仔细观察测试,可以得到一个(正确的)假设,这是由于Integer自动装箱造成的。为什么???
+
+ Note that "gc.alloc" counters generally produce more accurate data, but they can also fail when threads come and
+ go over the course of the benchmark. "gc.churn" values are updated on each GC event, and so if you want a more accurate
+ data, running longer and/or with small heap would help. But anyhow, always cross-reference "gc.alloc" and "gc.churn"
+ values with each other to get a complete picture.
+
+ 请注意,"gc.alloc"计数器通常会产生更准确的数据,但是当线程来回顾基准测试的过程,它们也会失败。
+ "gc.churn"值会在每个GC事件上更新,因此如果您想要更准确的数据,运行更长时间和/或使用小堆会有所帮助。
+ 但无论如何,总是互相引用“gc.alloc”和“gc.churn”值来获得完整的图片。
+
+ It is also worth noticing that non-normalized counters are dependent on benchmark performance! Here, "treemap"
+ tests are 3x slower, and thus both allocation and churn rates are also comparably lower. It is often useful to look
+ into non-normalized counters to see if the test is allocation/GC-bound (figure the allocation pressure "ceiling"
+ for your configuration!), and normalized counters to see the more precise benchmark behavior.
+
+ 值得注意的是,非标准化计数器依赖于benchmark的性能!
+ "treemap"测试速度慢了3倍,因此分配和回收速率也相对较低。
+ 查看 非规范化计数器以查看测试是否为allocation/GC-bound(计算配置的分配压力“上限”)和 规范化计数器以查看更精确的benchmark行为 通常很有用。
+
+ As most profilers, both "stack" and "gc" profile are able to aggregate samples from multiple forks. It is a good
+ idea to run multiple forks with the profilers enabled, as it improves results error estimates.
+
+ 与大多数分析器一样,"stack"和"gc"配置文件都能够聚合来自多个fork的样本。在启用分析器的情况下运行多个fork是个好主意,因为它可以改善结果误差估计。
+ */
+ }
+
+ /*
+ * ================================ CLASSLOADER BENCHMARK ================================
+ */
+
+
+ @State(Scope.Thread)
+ @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+ @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+ @Fork(3)
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static class Classy {
+
+ /**
+ * Our own crippled classloader, that can only load a simple class over and over again.
+ */
+ public static class XLoader extends URLClassLoader {
+ private static final byte[] X_BYTECODE = new byte[]{
+ (byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE, 0x00, 0x00, 0x00, 0x34, 0x00, 0x0D, 0x0A, 0x00, 0x03, 0x00,
+ 0x0A, 0x07, 0x00, 0x0B, 0x07, 0x00, 0x0C, 0x01, 0x00, 0x06, 0x3C, 0x69, 0x6E, 0x69, 0x74, 0x3E, 0x01, 0x00, 0x03,
+ 0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43, 0x6F, 0x64, 0x65, 0x01, 0x00, 0x0F, 0x4C, 0x69, 0x6E, 0x65, 0x4E, 0x75,
+ 0x6D, 0x62, 0x65, 0x72, 0x54, 0x61, 0x62, 0x6C, 0x65, 0x01, 0x00, 0x0A, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x46,
+ 0x69, 0x6C, 0x65, 0x01, 0x00, 0x06, 0x58, 0x2E, 0x6A, 0x61, 0x76, 0x61, 0x0C, 0x00, 0x04, 0x00, 0x05, 0x01, 0x00,
+ 0x01, 0x58, 0x01, 0x00, 0x10, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x4F, 0x62, 0x6A, 0x65,
+ 0x63, 0x74, 0x00, 0x20, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x2A,
+ (byte) 0xB7, 0x00, 0x01, (byte) 0xB1, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x09,
+ };
+
+ public XLoader() {
+ super(new URL[0], ClassLoader.getSystemClassLoader());
+ }
+
+ @Override
+ protected Class> findClass(final String name) {
+ return defineClass(name, X_BYTECODE, 0, X_BYTECODE.length);
+ }
+
+ }
+
+ @Benchmark
+ public Class> load() throws ClassNotFoundException {
+ return Class.forName("X", true, new XLoader());
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Classy -prof cl
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Classy -prof comp
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(Classy.class.getSimpleName())
+ .addProfiler(ClassloaderProfiler.class)
+// .addProfiler(CompilerProfiler.class)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ /*
+ Running with -prof cl will yield:
+
+ Benchmark Mode Cnt Score Error Units
+ JMHSample_35_Profilers.Classy.load avgt 15 34215.363 ± 545.892 ns/op
+ JMHSample_35_Profilers.Classy.load:·class.load avgt 15 29374.097 ± 716.743 classes/sec
+ JMHSample_35_Profilers.Classy.load:·class.load.norm avgt 15 1.000 ± 0.001 classes/op
+ JMHSample_35_Profilers.Classy.load:·class.unload avgt 15 29598.233 ± 3420.181 classes/sec
+ JMHSample_35_Profilers.Classy.load:·class.unload.norm avgt 15 1.008 ± 0.119 classes/op
+
+ Here, we can see the benchmark indeed load class per benchmark op, and this adds up to more than 29K classloads
+ per second. We can also see the runtime is able to successfully keep the number of loaded classes at bay,
+ since the class unloading happens at the same rate.
+
+ 这里,我们可以看到基准在每个基准操作的确有加载类,这种操作有每秒超过29K的类加载量。
+ 我们看到运行时能够成功地保持加载的类的数量,因为类的卸载以同样速率在发生。
+
+ This profiler is handy when doing the classloading performance work, because it says if the classes
+ were actually loaded, and not reused across the Class.forName calls. It also helps to see if the benchmark
+ performs any classloading in the measurement phase. For example, if you have non-classloading benchmark,
+ you would expect these metrics be zero.
+
+ 在进行类加载性能工作时,此分析器很方便,因为它表示类是否实际加载,而不是在Class.forName调用中重用。
+ 它还有助于查看基准测试是否在测量阶段执行任何类加载。例如,如果您有非类加载基准,那么您可能希望这些指标为零。
+
+ Another useful profiler that could tell if compiler is doing a heavy work in background, and thus interfering
+ with measurement, -prof comp:
+
+ 另一个有用的profiler可以告诉我们编译器会否在后台做了一些较重的操作,这些操作会影响我们的检测,-prof comp:
+
+ Benchmark Mode Cnt Score Error Units
+ JMHSample_35_Profilers.Classy.load avgt 5 33523.875 ± 3026.025 ns/op
+ JMHSample_35_Profilers.Classy.load:·compiler.time.profiled avgt 5 5.000 ms
+ JMHSample_35_Profilers.Classy.load:·compiler.time.total avgt 5 479.000 ms
+
+ We seem to be at proper steady state: out of 479 ms of total compiler work, only 5 ms happen during the
+ measurement window. It is expected to have some level of background compilation even at steady state.
+
+ 我们似乎看到了稳定状态:在超过479ms的编译器工作重,仅有5ms发生在检测窗口期。
+ 即使在稳定状态下,也会有一定程度的后台编译。
+
+ As most profilers, both "cl" and "comp" are able to aggregate samples from multiple forks. It is a good
+ idea to run multiple forks with the profilers enabled, as it improves results error estimates.
+
+ 像其他profilers一样,"cl"和"comp"能够聚合多个fork的采样。这对运行多个开启了profiler的fork是件好事,改善了错误的误差。
+ */
+ }
+
+ /*
+ * ================================ ATOMIC LONG BENCHMARK ================================
+ */
+
+ @State(Scope.Benchmark)
+ @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+ @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+ @Fork(1)
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ public static class Atomic {
+ private AtomicLong n;
+
+ @Setup
+ public void setup() {
+ n = new AtomicLong();
+ }
+
+ @Benchmark
+ public long test() {
+ return n.incrementAndGet();
+ }
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof perf -f 1 (Linux)
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof perfnorm -f 3 (Linux)
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof perfasm -f 1 (Linux)
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof xperfasm -f 1 (Windows)
+ * $ java -jar target/benchmarks.jar JMHSample_35.*Atomic -prof dtraceasm -f 1 (Mac OS X)
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(Atomic.class.getSimpleName())
+// .addProfiler(LinuxPerfProfiler.class)
+// .addProfiler(LinuxPerfNormProfiler.class)
+// .addProfiler(LinuxPerfAsmProfiler.class)
+// .addProfiler(WinPerfAsmProfiler.class)
+ // 需要开启用户sudo免密
+ .addProfiler(DTraceAsmProfiler.class)
+ .build();
+
+ new Runner(opt).run();
+ }
+
+ /*
+ Dealing with nanobenchmarks like these requires looking into the abyss of runtime, hardware, and
+ generated code. Luckily, JMH has a few handy tools that ease the pain. If you are running Linux,
+ then perf_events are probably available as standard package. This kernel facility taps into
+ hardware counters, and provides the data for user space programs like JMH. Windows has less
+ sophisticated facilities, but also usable, see below.
+
+ One can simply run "perf stat java -jar ..." to get the first idea how the workload behaves. In
+ JMH case, however, this will cause perf to profile both host and forked JVMs.
+
+ -prof perf avoids that: JMH invokes perf for the forked VM alone. For the benchmark above, it
+ would print something like:
+
+ Perf stats:
+ --------------------------------------------------
+
+ 4172.776137 task-clock (msec) # 0.411 CPUs utilized
+ 612 context-switches # 0.147 K/sec
+ 31 cpu-migrations # 0.007 K/sec
+ 195 page-faults # 0.047 K/sec
+ 16,599,643,026 cycles # 3.978 GHz [30.80%]
+ stalled-cycles-frontend
+ stalled-cycles-backend
+ 17,815,084,879 instructions # 1.07 insns per cycle [38.49%]
+ 3,813,373,583 branches # 913.870 M/sec [38.56%]
+ 1,212,788 branch-misses # 0.03% of all branches [38.91%]
+ 7,582,256,427 L1-dcache-loads # 1817.077 M/sec [39.07%]
+ 312,913 L1-dcache-load-misses # 0.00% of all L1-dcache hits [38.66%]
+ 35,688 LLC-loads # 0.009 M/sec [32.58%]
+ LLC-load-misses:HG
+ L1-icache-loads:HG
+ 161,436 L1-icache-load-misses:HG # 0.00% of all L1-icache hits [32.81%]
+ 7,200,981,198 dTLB-loads:HG # 1725.705 M/sec [32.68%]
+ 3,360 dTLB-load-misses:HG # 0.00% of all dTLB cache hits [32.65%]
+ 193,874 iTLB-loads:HG # 0.046 M/sec [32.56%]
+ 4,193 iTLB-load-misses:HG # 2.16% of all iTLB cache hits [32.44%]
+ L1-dcache-prefetches:HG
+ 0 L1-dcache-prefetch-misses:HG # 0.000 K/sec [32.33%]
+
+ 10.159432892 seconds time elapsed
+
+ We can already see this benchmark goes with good IPC, does lots of loads and lots of stores,
+ all of them are more or less fulfilled without misses. The data like this is not handy though:
+ you would like to normalize the counters per benchmark op.
+
+ This is exactly what -prof perfnorm does:
+
+ Benchmark Mode Cnt Score Error Units
+ JMHSample_35_Profilers.Atomic.test avgt 15 6.551 ± 0.023 ns/op
+ JMHSample_35_Profilers.Atomic.test:·CPI avgt 3 0.933 ± 0.026 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-load-misses avgt 3 0.001 ± 0.022 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-loads avgt 3 12.267 ± 1.324 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-store-misses avgt 3 0.001 ± 0.006 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-stores avgt 3 4.090 ± 0.402 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-icache-load-misses avgt 3 0.001 ± 0.011 #/op
+ JMHSample_35_Profilers.Atomic.test:·LLC-loads avgt 3 0.001 ± 0.004 #/op
+ JMHSample_35_Profilers.Atomic.test:·LLC-stores avgt 3 ≈ 10â»â´ #/op
+ JMHSample_35_Profilers.Atomic.test:·branch-misses avgt 3 ≈ 10â»â´ #/op
+ JMHSample_35_Profilers.Atomic.test:·branches avgt 3 6.152 ± 0.385 #/op
+ JMHSample_35_Profilers.Atomic.test:·bus-cycles avgt 3 0.670 ± 0.048 #/op
+ JMHSample_35_Profilers.Atomic.test:·context-switches avgt 3 ≈ 10â»â¶ #/op
+ JMHSample_35_Profilers.Atomic.test:·cpu-migrations avgt 3 ≈ 10â»â· #/op
+ JMHSample_35_Profilers.Atomic.test:·cycles avgt 3 26.790 ± 1.393 #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-load-misses avgt 3 ≈ 10â»â´ #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-loads avgt 3 12.278 ± 0.277 #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-store-misses avgt 3 ≈ 10â»âµ #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-stores avgt 3 4.113 ± 0.437 #/op
+ JMHSample_35_Profilers.Atomic.test:·iTLB-load-misses avgt 3 ≈ 10â»âµ #/op
+ JMHSample_35_Profilers.Atomic.test:·iTLB-loads avgt 3 0.001 ± 0.034 #/op
+ JMHSample_35_Profilers.Atomic.test:·instructions avgt 3 28.729 ± 1.297 #/op
+ JMHSample_35_Profilers.Atomic.test:·minor-faults avgt 3 ≈ 10â»â· #/op
+ JMHSample_35_Profilers.Atomic.test:·page-faults avgt 3 ≈ 10â»â· #/op
+ JMHSample_35_Profilers.Atomic.test:·ref-cycles avgt 3 26.734 ± 2.081 #/op
+
+ It is customary to trim the lines irrelevant to the particular benchmark. We show all of them here for
+ completeness.
+
+ We can see that the benchmark does ~12 loads per benchmark op, and about ~4 stores per op, most of
+ them fitting in the cache. There are also ~6 branches per benchmark op, all are predicted as well.
+ It is also easy to see the benchmark op takes ~28 instructions executed in ~27 cycles.
+
+ The output would get more interesting when we run with more threads, say, -t 8:
+
+ Benchmark Mode Cnt Score Error Units
+ JMHSample_35_Profilers.Atomic.test avgt 15 143.595 ± 1.968 ns/op
+ JMHSample_35_Profilers.Atomic.test:·CPI avgt 3 17.741 ± 28.761 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-load-misses avgt 3 0.175 ± 0.406 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-loads avgt 3 11.872 ± 0.786 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-store-misses avgt 3 0.184 ± 0.505 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-dcache-stores avgt 3 4.422 ± 0.561 #/op
+ JMHSample_35_Profilers.Atomic.test:·L1-icache-load-misses avgt 3 0.015 ± 0.083 #/op
+ JMHSample_35_Profilers.Atomic.test:·LLC-loads avgt 3 0.015 ± 0.128 #/op
+ JMHSample_35_Profilers.Atomic.test:·LLC-stores avgt 3 1.036 ± 0.045 #/op
+ JMHSample_35_Profilers.Atomic.test:·branch-misses avgt 3 0.224 ± 0.492 #/op
+ JMHSample_35_Profilers.Atomic.test:·branches avgt 3 6.524 ± 2.873 #/op
+ JMHSample_35_Profilers.Atomic.test:·bus-cycles avgt 3 13.475 ± 14.502 #/op
+ JMHSample_35_Profilers.Atomic.test:·context-switches avgt 3 ≈ 10â»â´ #/op
+ JMHSample_35_Profilers.Atomic.test:·cpu-migrations avgt 3 ≈ 10â»â¶ #/op
+ JMHSample_35_Profilers.Atomic.test:·cycles avgt 3 537.874 ± 595.723 #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-load-misses avgt 3 0.001 ± 0.006 #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-loads avgt 3 12.032 ± 2.430 #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-store-misses avgt 3 ≈ 10â»â´ #/op
+ JMHSample_35_Profilers.Atomic.test:·dTLB-stores avgt 3 4.557 ± 0.948 #/op
+ JMHSample_35_Profilers.Atomic.test:·iTLB-load-misses avgt 3 ≈ 10â»Â³ #/op
+ JMHSample_35_Profilers.Atomic.test:·iTLB-loads avgt 3 0.016 ± 0.052 #/op
+ JMHSample_35_Profilers.Atomic.test:·instructions avgt 3 30.367 ± 15.052 #/op
+ JMHSample_35_Profilers.Atomic.test:·minor-faults avgt 3 ≈ 10â»âµ #/op
+ JMHSample_35_Profilers.Atomic.test:·page-faults avgt 3 ≈ 10â»âµ #/op
+ JMHSample_35_Profilers.Atomic.test:·ref-cycles avgt 3 538.697 ± 590.183 #/op
+
+ Note how this time the CPI is awfully high: 17 cycles per instruction! Indeed, we are making almost the
+ same ~30 instructions, but now they take >530 cycles. Other counters highlight why: we now have cache
+ misses on both loads and stores, on all levels of cache hierarchy. With a simple constant-footprint
+ like ours, that's an indication of sharing problems. Indeed, our AtomicLong is heavily-contended
+ with 8 threads.
+
+ "perfnorm", again, can (and should!) be used with multiple forks, to properly estimate the metrics.
+
+ The last, but not the least player on our field is -prof perfasm. It is important to follow up on
+ generated code when dealing with fine-grained benchmarks. We could employ PrintAssembly to dump the
+ generated code, but it will dump *all* the generated code, and figuring out what is related to our
+ benchmark is a daunting task. But we have "perf" that can tell what program addresses are really hot!
+ This enables us to contrast the assembly output.
+
+ -prof perfasm would indeed contrast out the hottest loop in the generated code! It will also point
+ fingers at "lock xadd" as the hottest instruction in our code. Hardware counters are not very precise
+ about the instruction addresses, so sometimes they attribute the events to the adjacent code lines.
+
+ Hottest code regions (>10.00% "cycles" events):
+ ....[Hottest Region 1]..............................................................................
+ [0x7f1824f87c45:0x7f1824f87c79] in org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub
+
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@29 (line 201)
+ ; implicit exception: dispatches to 0x00007f1824f87d21
+ 0x00007f1824f87c25: test %r11d,%r11d
+ 0x00007f1824f87c28: jne 0x00007f1824f87cbd ;*ifeq
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@32 (line 201)
+ 0x00007f1824f87c2e: mov $0x1,%ebp
+ 0x00007f1824f87c33: nopw 0x0(%rax,%rax,1)
+ 0x00007f1824f87c3c: xchg %ax,%ax ;*aload
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@13 (line 199)
+ 0x00007f1824f87c40: mov 0x8(%rsp),%r10
+ 0.00% 0x00007f1824f87c45: mov 0xc(%r10),%r11d ;*getfield n
+ ; - org.openjdk.jmh.samples.JMHSample_35_Profilers$Atomic::test@1 (line 280)
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@16 (line 199)
+ 0.19% 0.02% 0x00007f1824f87c49: test %r11d,%r11d
+ 0x00007f1824f87c4c: je 0x00007f1824f87cad
+ 0x00007f1824f87c4e: mov $0x1,%edx
+ 0x00007f1824f87c53: lock xadd %rdx,0x10(%r12,%r11,8)
+ ;*invokevirtual getAndAddLong
+ ; - java.util.concurrent.atomic.AtomicLong::incrementAndGet@8 (line 200)
+ ; - org.openjdk.jmh.samples.JMHSample_35_Profilers$Atomic::test@4 (line 280)
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@16 (line 199)
+ 95.20% 95.06% 0x00007f1824f87c5a: add $0x1,%rdx ;*ladd
+ ; - java.util.concurrent.atomic.AtomicLong::incrementAndGet@12 (line 200)
+ ; - org.openjdk.jmh.samples.JMHSample_35_Profilers$Atomic::test@4 (line 280)
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@16 (line 199)
+ 0.24% 0.00% 0x00007f1824f87c5e: mov 0x10(%rsp),%rsi
+ 0x00007f1824f87c63: callq 0x00007f1824e2b020 ; OopMap{[0]=Oop [8]=Oop [16]=Oop [24]=Oop off=232}
+ ;*invokevirtual consume
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@19 (line 199)
+ ; {optimized virtual_call}
+ 0.20% 0.01% 0x00007f1824f87c68: mov 0x18(%rsp),%r10
+ 0x00007f1824f87c6d: movzbl 0x94(%r10),%r11d ;*getfield isDone
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@29 (line 201)
+ 0.00% 0x00007f1824f87c75: add $0x1,%rbp ; OopMap{r10=Oop [0]=Oop [8]=Oop [16]=Oop [24]=Oop off=249}
+ ;*ifeq
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@32 (line 201)
+ 0.20% 0.01% 0x00007f1824f87c79: test %eax,0x15f36381(%rip) # 0x00007f183aebe000
+ ; {poll}
+ 0x00007f1824f87c7f: test %r11d,%r11d
+ 0x00007f1824f87c82: je 0x00007f1824f87c40 ;*aload_2
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@35 (line 202)
+ 0x00007f1824f87c84: mov $0x7f1839be4220,%r10
+ 0x00007f1824f87c8e: callq *%r10 ;*invokestatic nanoTime
+ ; - org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub@36 (line 202)
+ 0x00007f1824f87c91: mov (%rsp),%r10
+ ....................................................................................................
+ 96.03% 95.10%
+
+ perfasm would also print the hottest methods to show if we indeed spending time in our benchmark. Most of the time,
+ it can demangle VM and kernel symbols as well:
+
+ ....[Hottest Methods (after inlining)]..............................................................
+ 96.03% 95.10% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_avgt_jmhStub
+ 0.73% 0.78% org.openjdk.jmh.samples.generated.JMHSample_35_Profilers_Atomic_test::test_AverageTime
+ 0.63% 0.00% org.openjdk.jmh.infra.Blackhole::consume
+ 0.23% 0.25% native_write_msr_safe ([kernel.kallsyms])
+ 0.09% 0.05% _raw_spin_unlock ([kernel.kallsyms])
+ 0.09% 0.00% [unknown] (libpthread-2.19.so)
+ 0.06% 0.07% _raw_spin_lock ([kernel.kallsyms])
+ 0.06% 0.04% _raw_spin_unlock_irqrestore ([kernel.kallsyms])
+ 0.06% 0.05% _IO_fwrite (libc-2.19.so)
+ 0.05% 0.03% __srcu_read_lock; __srcu_read_unlock ([kernel.kallsyms])
+ 0.04% 0.05% _raw_spin_lock_irqsave ([kernel.kallsyms])
+ 0.04% 0.06% vfprintf (libc-2.19.so)
+ 0.04% 0.01% mutex_unlock ([kernel.kallsyms])
+ 0.04% 0.01% _nv014306rm ([nvidia])
+ 0.04% 0.04% rcu_eqs_enter_common.isra.47 ([kernel.kallsyms])
+ 0.04% 0.02% mutex_lock ([kernel.kallsyms])
+ 0.03% 0.07% __acct_update_integrals ([kernel.kallsyms])
+ 0.03% 0.02% fget_light ([kernel.kallsyms])
+ 0.03% 0.01% fput ([kernel.kallsyms])
+ 0.03% 0.04% rcu_eqs_exit_common.isra.48 ([kernel.kallsyms])
+ 1.63% 2.26% <...other 319 warm methods...>
+ ....................................................................................................
+ 100.00% 98.97%
+
+ ....[Distribution by Area]..........................................................................
+ 97.44% 95.99%
+ 1.60% 2.42%
+ 0.47% 0.78%
+ 0.22% 0.29%
+ 0.15% 0.07%
+ 0.07% 0.38%
+ 0.05% 0.06%
+ 0.00% 0.00%
+ 0.00% 0.00%
+ ....................................................................................................
+ 100.00% 100.00%
+
+ Since program addresses change from fork to fork, it does not make sense to run perfasm with more than
+ a single fork.
+ */
+ }
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_36_BranchPrediction.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_36_BranchPrediction.java
new file mode 100644
index 00000000..aa3ab9bf
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_36_BranchPrediction.java
@@ -0,0 +1,138 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.profile.DTraceAsmProfiler;
+import org.openjdk.jmh.profile.LinuxPerfNormProfiler;
+import org.openjdk.jmh.profile.LinuxPerfProfiler;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 分支预测,底层做的一件很牛逼的运行优化
+ * @author childe
+ * @date 2018-10-20
+ */
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(5)
+@State(Scope.Benchmark)
+public class JMHSample_36_BranchPrediction {
+
+ /*
+ * This sample serves as a warning against regular data sets.
+ *
+ * It is very tempting to present a regular data set to benchmark, either due to
+ * naive generation strategy, or just from feeling better about regular data sets.
+ * Unfortunately, it frequently backfires: the regular datasets are known to be
+ * optimized well by software and hardware. This example exploits one of these
+ * optimizations: branch prediction.
+ *
+ * Imagine our benchmark selects the branch based on the array contents, as
+ * we are streaming through it:
+ *
+ * 这个例子用作对常规数据集的警告。
+ *
+ * 由于天真的生成策略,或者只是感觉对常规数据集更好,将常规数据集呈现为基准测试是非常诱人的。
+ * 不幸的是,它经常事与愿违:已知常规数据集可以通过软件和硬件很好地进行优化。
+ * 此示例利用了以下优化之一:分支预测。
+ *
+ * 假设我们的基准测试通过数组的内容来选择分支,因为我们正在通过它进行流式传输:
+ */
+
+ private static final int COUNT = 1024 * 1024;
+
+ private byte[] sorted;
+ private byte[] unsorted;
+
+ @Setup
+ public void setup() {
+ sorted = new byte[COUNT];
+ unsorted = new byte[COUNT];
+ Random random = new Random(1234);
+ random.nextBytes(sorted);
+ random.nextBytes(unsorted);
+ Arrays.sort(sorted);
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(COUNT)
+ public void sorted(Blackhole bh1, Blackhole bh2) {
+ for (byte v : sorted) {
+ if (v > 0) {
+ bh1.consume(v);
+ } else {
+ bh2.consume(v);
+ }
+ }
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(COUNT)
+ public void unsorted(Blackhole bh1, Blackhole bh2) {
+ for (byte v : unsorted) {
+ if (v > 0) {
+ bh1.consume(v);
+ } else {
+ bh2.consume(v);
+ }
+ }
+ }
+
+ /*
+ There is a substantial difference in performance for these benchmarks!
+
+ It is explained by good branch prediction in "sorted" case, and branch mispredicts in "unsorted"
+ case. -prof perfnorm conveniently highlights that, with larger "branch-misses", and larger "CPI"
+ for "unsorted" case:
+
+ Benchmark Mode Cnt Score Error Units
+ JMHSample_36_BranchPrediction.sorted avgt 25 2.160 ± 0.049 ns/op
+ JMHSample_36_BranchPrediction.sorted:·CPI avgt 5 0.286 ± 0.025 #/op
+ JMHSample_36_BranchPrediction.sorted:·branch-misses avgt 5 ≈ 10â»â´ #/op
+ JMHSample_36_BranchPrediction.sorted:·branches avgt 5 7.606 ± 1.742 #/op
+ JMHSample_36_BranchPrediction.sorted:·cycles avgt 5 8.998 ± 1.081 #/op
+ JMHSample_36_BranchPrediction.sorted:·instructions avgt 5 31.442 ± 4.899 #/op
+
+ JMHSample_36_BranchPrediction.unsorted avgt 25 5.943 ± 0.018 ns/op
+ JMHSample_36_BranchPrediction.unsorted:·CPI avgt 5 0.775 ± 0.052 #/op
+ JMHSample_36_BranchPrediction.unsorted:·branch-misses avgt 5 0.529 ± 0.026 #/op <--- OOPS
+ JMHSample_36_BranchPrediction.unsorted:·branches avgt 5 7.841 ± 0.046 #/op
+ JMHSample_36_BranchPrediction.unsorted:·cycles avgt 5 24.793 ± 0.434 #/op
+ JMHSample_36_BranchPrediction.unsorted:·instructions avgt 5 31.994 ± 2.342 #/op
+
+ It is an open question if you want to measure only one of these tests. In many cases, you have to measure
+ both to get the proper best-case and worst-case estimate!
+ */
+
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_36
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(".*" + JMHSample_36_BranchPrediction.class.getSimpleName() + ".*")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_37_CacheAccess.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_37_CacheAccess.java
new file mode 100644
index 00000000..5656583f
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_37_CacheAccess.java
@@ -0,0 +1,126 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/22 17:10
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(5)
+@State(Scope.Benchmark)
+public class JMHSample_37_CacheAccess {
+
+ /*
+ * This sample serves as a warning against subtle differences in cache access patterns.
+ *
+ * Many performance differences may be explained by the way tests are accessing memory.
+ * In the example below, we walLevelk the matrix either row-first, or col-first:
+ */
+
+ private final static int COUNT = 4096;
+ private final static int MATRIX_SIZE = COUNT * COUNT;
+
+ private int[][] matrix;
+
+ @Setup
+ public void setup() {
+ matrix = new int[COUNT][COUNT];
+ Random random = new Random(1234);
+ for (int i = 0; i < COUNT; i++) {
+ for (int j = 0; j < COUNT; j++) {
+ matrix[i][j] = random.nextInt();
+ }
+ }
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(MATRIX_SIZE)
+ public void colFirst(Blackhole bh) {
+ for (int c = 0; c < COUNT; c++) {
+ for (int r = 0; r < COUNT; r++) {
+ bh.consume(matrix[r][c]);
+ }
+ }
+ }
+
+ @Benchmark
+ @OperationsPerInvocation(MATRIX_SIZE)
+ public void rowFirst(Blackhole bh) {
+ for (int r = 0; r < COUNT; r++) {
+ for (int c = 0; c < COUNT; c++) {
+ bh.consume(matrix[r][c]);
+ }
+ }
+ }
+
+ /*
+ Notably, colFirst accesses are much slower, and that's not a surprise: Java's multidimensional
+ arrays are actually rigged, being one-dimensional arrays of one-dimensional arrays. Therefore,
+ pulling n-th element from each of the inner array induces more cache misses, when matrix is large.
+ -prof perfnorm conveniently highlights that, with >2 cache misses per one benchmark op:
+
+ 值得注意的是,colFirst访问速度要慢得多,这并不奇怪:
+ Java的多维数组实际上是被操纵的,是一维数组的一维数组。
+ 因此,当矩阵很大时,从每个内部阵列中拉出第n个元素会引起更多的高速缓存未命中。
+ -prof perfnorm清晰的展示出,每个基准操作有2个缓存未命中:
+
+ Benchmark Mode Cnt Score Error Units
+ JMHSample_37_MatrixCopy.colFirst avgt 25 5.306 ± 0.020 ns/op
+ JMHSample_37_MatrixCopy.colFirst:·CPI avgt 5 0.621 ± 0.011 #/op
+ JMHSample_37_MatrixCopy.colFirst:·L1-dcache-load-misses avgt 5 2.177 ± 0.044 #/op <-- OOPS
+ JMHSample_37_MatrixCopy.colFirst:·L1-dcache-loads avgt 5 14.804 ± 0.261 #/op
+ JMHSample_37_MatrixCopy.colFirst:·LLC-loads avgt 5 2.165 ± 0.091 #/op
+ JMHSample_37_MatrixCopy.colFirst:·cycles avgt 5 22.272 ± 0.372 #/op
+ JMHSample_37_MatrixCopy.colFirst:·instructions avgt 5 35.888 ± 1.215 #/op
+
+ JMHSample_37_MatrixCopy.rowFirst avgt 25 2.662 ± 0.003 ns/op
+ JMHSample_37_MatrixCopy.rowFirst:·CPI avgt 5 0.312 ± 0.003 #/op
+ JMHSample_37_MatrixCopy.rowFirst:·L1-dcache-load-misses avgt 5 0.066 ± 0.001 #/op
+ JMHSample_37_MatrixCopy.rowFirst:·L1-dcache-loads avgt 5 14.570 ± 0.400 #/op
+ JMHSample_37_MatrixCopy.rowFirst:·LLC-loads avgt 5 0.002 ± 0.001 #/op
+ JMHSample_37_MatrixCopy.rowFirst:·cycles avgt 5 11.046 ± 0.343 #/op
+ JMHSample_37_MatrixCopy.rowFirst:·instructions avgt 5 35.416 ± 1.248 #/op
+
+ So, when comparing two different benchmarks, you have to follow up if the difference is caused
+ by the memory locality issues.
+
+ 所以,在比较两个不同的基准时,如果差异是由内存局部性问题引起的,则必须跟进。
+ */
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_37
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(".*" + JMHSample_37_CacheAccess.class.getSimpleName() + ".*")
+ .output("JMHSample_37_CacheAccess.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
\ No newline at end of file
diff --git a/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_38_PerInvokeSetup.java b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_38_PerInvokeSetup.java
new file mode 100644
index 00000000..39ad0f77
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/jmh/JMHSample_38_PerInvokeSetup.java
@@ -0,0 +1,177 @@
+package com.renchao.jmh;
+
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * desc
+ *
+ * @author childe
+ * @date 2018/10/22 19:47
+ **/
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(5)
+public class JMHSample_38_PerInvokeSetup {
+
+ /*
+ * This example highlights the usual mistake in non-steady-state benchmarks.
+ *
+ * Suppose we want to test how long it takes to bubble sort an array. Naively,
+ * we could make the test that populates an array with random (unsorted) values,
+ * and calls sort on it over and over again:
+ *
+ * 此示例突显非稳态基准测试(non-steady-state benchmarks)中的常见错误。
+ *
+ * 假设我们要测试对数组进行冒泡排序的耗时。
+ * 天真地,我们可以使用随机(未排序)值填充数组,并一遍又一遍地调用sort测试:
+ */
+
+ private void bubbleSort(byte[] b) {
+ boolean changed = true;
+ while (changed) {
+ changed = false;
+ for (int c = 0; c < b.length - 1; c++) {
+ if (b[c] > b[c + 1]) {
+ byte t = b[c];
+ b[c] = b[c + 1];
+ b[c + 1] = t;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ // Could be an implicit State instead, but we are going to use it
+ // as the dependency in one of the tests below
+ // 可能是一个隐式状态,但我们将在下面的一个测试中依赖它
+
+ @State(Scope.Benchmark)
+ public static class Data {
+
+ @Param({"1", "16", "256"})
+ int count;
+
+ byte[] arr;
+
+ @Setup
+ public void setup() {
+ arr = new byte[count];
+ Random random = new Random(1234);
+ random.nextBytes(arr);
+ }
+ }
+
+ @Benchmark
+ public byte[] measureWrong(Data d) {
+ bubbleSort(d.arr);
+ return d.arr;
+ }
+
+ /*
+ * The method above is subtly wrong: it sorts the random array on the first invocation
+ * only. Every subsequent call will "sort" the already sorted array. With bubble sort,
+ * that operation would be significantly faster!
+ *
+ * This is how we might *try* to measure it right by making a copy in Level.Invocation
+ * setup. However, this is susceptible to the problems described in Level.Invocation
+ * Javadocs, READ AND UNDERSTAND THOSE DOCS BEFORE USING THIS APPROACH.
+ *
+ * 上面的方法是巧妙的错误:它只在第一次调用时对随机数组进行排序。
+ * 后续每个调用都将"排序"已排序的数组。
+ * 通过冒泡排序,操作速度会明显加快!
+ *
+ * 我们可以尝试通过在Level.Invocation中制作数组的副本来正确测量它。
+ * 在使用Level.Invocation这些方法之前请阅读并理解这些文档。
+ */
+
+ @State(Scope.Thread)
+ public static class DataCopy {
+ byte[] copy;
+
+ @Setup(Level.Invocation)
+ public void setup2(Data d) {
+ copy = Arrays.copyOf(d.arr, d.arr.length);
+ }
+ }
+
+ @Benchmark
+ public byte[] measureNeutral(DataCopy d) {
+ bubbleSort(d.copy);
+ return d.copy;
+ }
+
+ /*
+ * In an overwhelming majority of cases, the only sensible thing to do is to suck up
+ * the per-invocation setup costs into a benchmark itself. This work well in practice,
+ * especially when the payload costs dominate the setup costs.
+ *
+ * 在绝大多数情况下,唯一明智的做法是将每次调用设置成本吸收到基准测试本身。
+ *
+ * 这在实践中很有效,特别是当有效载荷成本主导设置成本时
+ * (即:测试本身耗时远远大于准备数据时,准备数据时间对测试本身的影响可以忽略)。
+ */
+
+ @Benchmark
+ public byte[] measureRight(Data d) {
+ byte[] c = Arrays.copyOf(d.arr, d.arr.length);
+ bubbleSort(c);
+ return c;
+ }
+
+ /*
+ Benchmark (count) Mode Cnt Score Error Units
+
+ JMHSample_38_PerInvokeSetup.measureWrong 1 avgt 25 2.408 ± 0.011 ns/op
+ JMHSample_38_PerInvokeSetup.measureWrong 16 avgt 25 8.286 ± 0.023 ns/op
+ JMHSample_38_PerInvokeSetup.measureWrong 256 avgt 25 73.405 ± 0.018 ns/op
+
+ JMHSample_38_PerInvokeSetup.measureNeutral 1 avgt 25 15.835 ± 0.470 ns/op
+ JMHSample_38_PerInvokeSetup.measureNeutral 16 avgt 25 112.552 ± 0.787 ns/op
+ JMHSample_38_PerInvokeSetup.measureNeutral 256 avgt 25 58343.848 ± 991.202 ns/op
+
+ JMHSample_38_PerInvokeSetup.measureRight 1 avgt 25 6.075 ± 0.018 ns/op
+ JMHSample_38_PerInvokeSetup.measureRight 16 avgt 25 102.390 ± 0.676 ns/op
+ JMHSample_38_PerInvokeSetup.measureRight 256 avgt 25 58812.411 ± 997.951 ns/op
+
+ We can clearly see that "measureWrong" provides a very weird result: it "sorts" way too fast.
+ "measureNeutral" is neither good or bad: while it prepares the data for each invocation correctly,
+ the timing overheads are clearly visible. These overheads can be overwhelming, depending on
+ the thread count and/or OS flavor.
+
+ 明显可以看出"measureWrong"跑出来一个奇怪的结果:它的排序太快了。
+ "measureNeutral"一般般:它正确地为每个调用准备数据,时间开销清晰可见。在不同的线程数 和/或 OS风格下,这些开销可能会非常大。
+ */
+
+ /*
+ * ============================== HOW TO RUN THIS TEST: ====================================
+ *
+ * You can run this test:
+ *
+ * a) Via the command line:
+ * $ mvn clean install
+ * $ java -jar target/benchmarks.jar JMHSample_38
+ *
+ * b) Via the Java API:
+ * (see the JMH homepage for possible caveats when running from IDE:
+ * http://openjdk.java.net/projects/code-tools/jmh/)
+ */
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(".*" + JMHSample_38_PerInvokeSetup.class.getSimpleName() + ".*")
+ .output("JMHSample_38_PerInvokeSetup.sampleLog")
+ .build();
+
+ new Runner(opt).run();
+ }
+
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/spring/AnnotationUtilsTest.java b/Test/MyMaven/src/main/java/com/renchao/spring/AnnotationUtilsTest.java
new file mode 100644
index 00000000..265069fb
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/spring/AnnotationUtilsTest.java
@@ -0,0 +1,14 @@
+package com.renchao.spring;
+
+import com.renchao.spring.bean.Anonymous;
+import com.renchao.spring.bean.TestController;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationUtils;
+
+public class AnnotationUtilsTest {
+ public static void main(String[] args) {
+ Anonymous annotation = AnnotationUtils.findAnnotation(TestController.class, Anonymous.class);
+ System.out.println(annotation);
+ System.out.println(AnnotatedElementUtils.isAnnotated(TestController.class, Anonymous.class));
+ }
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/spring/bean/Anonymous.java b/Test/MyMaven/src/main/java/com/renchao/spring/bean/Anonymous.java
new file mode 100644
index 00000000..faf076ab
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/spring/bean/Anonymous.java
@@ -0,0 +1,19 @@
+package com.renchao.spring.bean;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 匿名访问不鉴权注解
+ *
+ * @author admin
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous
+{
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/spring/bean/BaseController.java b/Test/MyMaven/src/main/java/com/renchao/spring/bean/BaseController.java
new file mode 100644
index 00000000..ae4fe40c
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/spring/bean/BaseController.java
@@ -0,0 +1,5 @@
+package com.renchao.spring.bean;
+
+@Anonymous
+public class BaseController {
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/spring/bean/TestController.java b/Test/MyMaven/src/main/java/com/renchao/spring/bean/TestController.java
new file mode 100644
index 00000000..bc2ed67a
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/spring/bean/TestController.java
@@ -0,0 +1,15 @@
+package com.renchao.spring.bean;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@Anonymous
+public class TestController extends BaseController {
+
+ @RequestMapping({"/cc","dd"})
+ @Anonymous
+ public String testF() {
+ return "testFeign.test01()";
+ }
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/test/DateDemo.java b/Test/MyMaven/src/main/java/com/renchao/test/DateDemo.java
new file mode 100644
index 00000000..d74c2770
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/test/DateDemo.java
@@ -0,0 +1,70 @@
+package com.renchao.test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+
+import lombok.Data;
+import org.hibernate.validator.HibernateValidator;
+import org.junit.Test;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.Arrays;
+import java.util.Set;
+
+
+public class DateDemo {
+ public static void main(String[] args) throws JsonProcessingException {
+ Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
+ SimpleModule simpleModule = new SimpleModule()
+// .addSerializer(Long.class, ToStringSerializer.instance)
+ .addSerializer(Long.TYPE, ToStringSerializer.instance);
+ builder.modules(simpleModule);
+ ObjectMapper build = builder.build();
+ String str = "{\"id\":22,\"name\":\"aaa\",\"age\":55}";
+ Bean bean1 = build.readValue(str, Bean.class);
+
+
+ Bean bean = new Bean();
+ bean.setId(22L);
+ bean.setName("aaa");
+ String s = build.writeValueAsString(bean);
+ System.out.println(s);
+ }
+
+ @Data
+ static class Bean {
+ @NotBlank(message = "aabb")
+ private String name;
+ @NotNull(message = "唯一标识不能为空")
+ private Long id;
+
+ @NotNull(message = "cc")
+ private String age;
+ }
+
+ @Test
+ public void test01() {
+ Bean bean = new Bean();
+ Validator validator = Validation.byProvider(HibernateValidator.class)
+ .configure().failFast(false).buildValidatorFactory().getValidator();
+ Set> validate = validator.validate(bean);
+ for (ConstraintViolation violation : validate) {
+ System.out.println(violation.getLeafBean());
+ System.out.println(violation.getMessage());
+ System.out.println(violation.getMessageTemplate());
+ System.out.println(violation.getPropertyPath());
+ System.out.println("======================");
+ }
+
+
+ }
+}
diff --git a/Test/MyMaven/src/main/java/com/renchao/test/DemoData.java b/Test/MyMaven/src/main/java/com/renchao/test/DemoData.java
new file mode 100644
index 00000000..0ca674c4
--- /dev/null
+++ b/Test/MyMaven/src/main/java/com/renchao/test/DemoData.java
@@ -0,0 +1,38 @@
+package com.renchao.test;
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.TypeReference;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class DemoData {
+ public static void main(String[] args) {
+ String filePath = "C:/Users/RENCHAO/Desktop/资料/easyexcel-user1.xls";
+ List list = EasyExcel.read(filePath).head(UserEntity.class).sheet().doReadSync();
+ System.out.println(list);
+ }
+
+
+ @Test
+ public void test01() {
+ String str = "[{\"component\":\"聚酯树脂\",\"content\":\"48%\"},{\"component\":\"乙酸乙酯\",\"content\":\"52%\"}]";
+// String str = "ssss";
+
+ System.out.println(JSON.isValid(str));
+ List