简而言之,我的问题是:为什么 JMH 基准测试结果在分叉内可以稳定,但分叉之间差异很大。
我在许多基准测试中观察到了这一点(通常涉及数据集的处理)。这是一个简单的例子:
import static java.util.concurrent.TimeUnit.*;
import static java.util.stream.Collectors.*;
import java.util.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.annotations.*;
@Warmup(iterations = 5, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 15, time = 1, timeUnit = SECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(MICROSECONDS)
@Fork(50)
@State(Scope.Benchmark)
public class AvgTest {
private long[] longs = new Random(1).longs(1000).toArray();
@Benchmark
public void test(Blackhole bh) {
bh.consume(Arrays.stream(longs).boxed().collect(averagingLong(x->x)));
}
}
Run Code Online (Sandbox Code Playgroud)
我使用 5 次一秒预热迭代和 15 次一秒测量迭代。按照指定,整个过程重复 50 次(同时 JVM 重新启动)@Fork(50)。常见的叉子看起来像这样:
# Run progress: 8,00% complete, ETA 00:15:34
# Fork: 5 of 50 …Run Code Online (Sandbox Code Playgroud) 我正在将集成的基准测试开发到应用程序中。我想使用JMH作为我的框架。
如何以 JSON 对象的形式接收结果?
我知道我可以使用以下运行选项将其保存在文件中:
org.openjdk.jmh.runner.options.Options opt = new OptionsBuilder()
.include(WorkerBenBenchmarkObject.class.getSimpleName())
.shouldDoGC(true)
.resultFormat(ResultFormatType.JSON)
.result("benchmark-result/" + System.currentTimeMillis() + ".json")
.addProfiler(StackProfiler.class)
.jvmArgsAppend("-Djmh.stack.period=1")
.warmupIterations(5)
.measurementIterations(5)
.forks(1)
.build();
new Runner(opt).run();
Run Code Online (Sandbox Code Playgroud)
如何在无需读取文件的情况下接收此结果?
在我的示例中,理论上 2 种方法的性能应该非常相似。在第一种情况下,我使用数组,在第二种情况下 - ArrayList 具有保证的容量。
结果如下:
LessonBenchmark2.capacityTestArray avgt 5 1,354 ± 0,057 ms/op
LessonBenchmark2.capacityTestArrayListEnsured avgt 5 32,018 ± 81,911 ms/op
这里似乎数组要快得多(1.354 vs 32.018 ms/op)。可能是我的 JMH 基准测试设置不正确。如何做对?
此外,如果我使用 @Setup(Level.Invocation),那么结果很接近(1,405 对 1,496 ms/op):
LessonBenchmark.capacityTestArray avgt 5 1,405 ± 0,143 ms/op
LessonBenchmark.capacityTestArrayListEnsured avgt 5 1,496 ± 0,104 ms/op
但是据说要小心使用 Invocation 。此外,迭代模式在逻辑上似乎是正确的。
这是代码:
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
static final int iter = 5;
static final int fork = 1;
static final int warmIter = 5;
@State(Scope.Benchmark)
public …Run Code Online (Sandbox Code Playgroud) JMH看起来像卡尺一样或者比卡尺更好,但是我无法弄清楚如何测量分配率,这对于能够在微基准测试中看是非常有用的.JMH是衡量分配率的错误工具吗?
我刚刚使用这个命令创建了一个Maven项目:
$ mvn archetype:generate \
-DinteractiveMode=false \
-DarchetypeGroupId=org.openjdk.jmh \
-DarchetypeArtifactId=jmh-java-benchmark-archetype \
-DgroupId=org.sample \
-DartifactId=test \
-Dversion=1.0
Run Code Online (Sandbox Code Playgroud)
然后我做了一个mvn clean install跟着java -jar test-1.0.jar
该程序给了我这个消息
no main manifest attribute, in target/test-1.0.jar
Run Code Online (Sandbox Code Playgroud)
我查看了清单,没有Main-Class属性.
这应该产生它:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${uberjar.name}</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<!--
Shading signed JARs will fail without this.
http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
-->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
Run Code Online (Sandbox Code Playgroud) 我正在比较两种方法来过滤列表,使用和不使用流.事实证明,对于10,000个项目的列表,不使用流的方法更快.我有兴趣理解为什么会这样.有人能解释一下结果吗?
public static int countLongWordsWithoutUsingStreams(
final List<String> words, final int longWordMinLength) {
words.removeIf(word -> word.length() <= longWordMinLength);
return words.size();
}
public static int countLongWordsUsingStreams(final List<String> words, final int longWordMinLength) {
return (int) words.stream().filter(w -> w.length() > longWordMinLength).count();
}
Run Code Online (Sandbox Code Playgroud)
使用JMH的Microbenchmark:
@Benchmark
@BenchmarkMode(Throughput)
@OutputTimeUnit(MILLISECONDS)
public void benchmarkCountLongWordsWithoutUsingStreams() {
countLongWordsWithoutUsingStreams(nCopies(10000, "IAmALongWord"), 3);
}
@Benchmark
@BenchmarkMode(Throughput)
@OutputTimeUnit(MILLISECONDS)
public void benchmarkCountLongWordsUsingStreams() {
countLongWordsUsingStreams(nCopies(10000, "IAmALongWord"), 3);
}
public static void main(String[] args) throws RunnerException {
final Options opts = new OptionsBuilder()
.include(PracticeQuestionsCh8Benchmark.class.getSimpleName())
.warmupIterations(5).measurementIterations(5).forks(1).build();
new Runner(opts).run();
} …Run Code Online (Sandbox Code Playgroud) 所以这是我试图测试的简单事情,什么是更快的mod操作或AND一个(假设2的幂) - 这就是hashMap内部的作用.这是一个拼写正确的"测试"吗?我不得不承认jmh的内部结构并且在经过所有样本(我认为第3次)之后编写正确的微基准测试是一个相当大的挑战.:)
@State(Scope.Thread)
@BenchmarkMode(org.openjdk.jmh.annotations.Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MeasureSpeedModuleVsAnd {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(MeasureSpeedModuleVsAnd.class.getSimpleName())
.forks(1)
.warmupIterations(1)
.measurementIterations(5)
.warmupTime(TimeValue.seconds(2))
.build();
new Runner(opt).run();
}
@Param({ "16", "32", "256", "1048576" /* 2 power of 10 */ })
public int number_of_buckets;
@Param({ "345984", "123456", "111", "98653" })
public int hashcode;
@Benchmark
public int benchamark_modulo() {
return hashcode % number_of_buckets;
}
@Benchmark
public int benchmark_and() {
return (number_of_buckets - 1) & hashcode;
}
}
Run Code Online (Sandbox Code Playgroud) 我一般都是微型基准测试的新手.当我在项目中执行JMH任务时,我得到"错误:无法找到资源:/ META-INF/BenchmarkList",我相信是由jmh-generator-annprocess创建的.我正在使用Gradle,我试图找出jmh-generator-annprocess是否正常工作?它是否适用于Gradle或我是否需要使用Maven插件?
https://github.com/coderrick/JMH-Studies.git如果你想要git clone我的项目并自己运行它.
我是jmh的新手并且了解线程背后发生的事情等等.
所以,我开始阅读并陷入@State注释并共享vs非共享状态.
我读了这个例子:http://hg.openjdk.java.net/code-tools/jmh/file/ecd9e76155fe/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_03_States.java 并且有关于它的几个问题.
第一个问题,国家阶级的确切作用是什么?保持参数?假设我想对以两种不同方式加密密钥的程序进行基准测试.我应该将键(String对象)保存在以特定状态注释的状态类中吗?或者只是将String对象保留在基准类上?对此的解释会很棒.
第二个问题,为什么在上面的例子中,非共享状态类性能比共享状态好得多?多线程状态如何改变它?
我觉得自己真的很模糊,因为我刚接触到这个东西,并且找不到"像我这样解释我的5个"jmh的例子,这是它的选择.
根据JEP 230:Microbenchmark Suite,存在Java 12内置的微基准套件。JEP解释说它基本上是JMH,但无需使用Maven / Gradle明确依赖它。但是,它没有指定如何访问属于该套件的类/注释来执行基准测试。
我的问题是:
module-info.java要使用此套件,我是否需要一个特定的Java模块?jmh ×10
java ×8
benchmarking ×4
performance ×3
build.gradle ×1
gradle ×1
java-12 ×1
java-8 ×1
java-stream ×1
json ×1
list ×1