在研究使用和将整数原语转换为字符串的一些小辩论时"" + n,Integer.toString(int)我编写了这个JMH微基准测试:
@Fork(1)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class IntStr {
protected int counter;
@GenerateMicroBenchmark
public String integerToString() {
return Integer.toString(this.counter++);
}
@GenerateMicroBenchmark
public String stringBuilder0() {
return new StringBuilder().append(this.counter++).toString();
}
@GenerateMicroBenchmark
public String stringBuilder1() {
return new StringBuilder().append("").append(this.counter++).toString();
}
@GenerateMicroBenchmark
public String stringBuilder2() {
return new StringBuilder().append("").append(Integer.toString(this.counter++)).toString();
}
@GenerateMicroBenchmark
public String stringFormat() {
return String.format("%d", this.counter++);
}
@Setup(Level.Iteration)
public void prepareIteration() {
this.counter = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
我使用默认的JMH选项运行它,我的Linux机器上都存在两个Java VM(最新的Mageia 4 64位,Intel i7-3770 CPU,32GB …
我们正在开发一个对延迟敏感的应用程序,并已对所有类型的方法进行微基准测试(使用jmh).在对查找方法进行微基准测试并对结果感到满意之后,我实现了最终版本,但却发现最终版本比我刚刚基准测试的版本慢了3倍.
罪魁祸首是实现的方法返回一个enum对象而不是一个int.以下是基准代码的简化版本:
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
public class ReturnEnumObjectVersusPrimitiveBenchmark {
enum Category {
CATEGORY1,
CATEGORY2,
}
@Param( {"3", "2", "1" })
String value;
int param;
@Setup
public void setUp() {
param = Integer.parseInt(value);
}
@Benchmark
public int benchmarkReturnOrdinal() {
if (param < 2) {
return Category.CATEGORY1.ordinal();
}
return Category.CATEGORY2.ordinal();
}
@Benchmark
public Category benchmarkReturnReference() {
if (param < 2) {
return Category.CATEGORY1;
}
return Category.CATEGORY2;
}
public static void main(String[] …Run Code Online (Sandbox Code Playgroud) 作为我研究在流中使用复杂过滤器或多个过滤器之间区别的一部分,我注意到Java 12的性能比Java 8慢。
这些奇怪的结果有什么解释吗?我在这里想念什么吗?
组态:
Java 8
Java 12
VM选项: -XX:+UseG1GC -server -Xmx1024m -Xms1024m
JMH吞吐量结果:
流+复杂过滤器
public void complexFilter(ExecutionPlan plan, Blackhole blackhole) {
long count = plan.getDoubles()
.stream()
.filter(d -> d < Math.PI
&& d > Math.E
&& d != 3
&& d != 2)
.count();
blackhole.consume(count);
}
Run Code Online (Sandbox Code Playgroud)
流+多个过滤器
public void multipleFilters(ExecutionPlan plan, Blackhole blackhole) {
long count = plan.getDoubles()
.stream() …Run Code Online (Sandbox Code Playgroud) 更新:看到每个方法可能会遇到不同的性能问题,我决定将这个问题分成两个:
最初的讨论可以在下面找到......
当我遇到一些令人惊讶的数据时,我正在比较我的库在Java 8和11下的性能.这是基准代码:
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 java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class MyBenchmark
{
@Benchmark
public void emptyMethod()
{
}
@Benchmark
public void throwAndConsumeStacktrace(Blackhole bh)
{
try
{
throw new IllegalArgumentException("I love benchmarks");
}
catch (IllegalArgumentException e)
{
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
bh.consume(sw.toString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行jmh 1.21,OracleJDK 1.8.0_192返回:
MyBenchmark.emptyMethod avgt 25 0.363 ± 0.001 ns/op
MyBenchmark.throwAndConsumeStacktrace avgt …Run Code Online (Sandbox Code Playgroud) 我正在使用Java 8流来迭代包含子列表的列表.外部列表大小在100到1000之间(不同的测试运行),内部列表大小始终为5.
有2个基准测试运行显示意外的性能偏差.
package benchmark;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
@Threads(32)
@Warmup(iterations = 25)
@Measurement(iterations = 5)
@State(Scope.Benchmark)
@Fork(1)
@BenchmarkMode(Mode.Throughput)
public class StreamBenchmark {
@Param({"700", "600", "500", "400", "300", "200", "100"})
int outerListSizeParam;
final static int INNER_LIST_SIZE = 5;
List<List<Integer>> list;
Random rand() {
return ThreadLocalRandom.current();
}
final BinaryOperator<Integer> reducer = (val1, val2) -> val1 + val2;
final Supplier<List<Integer>> supplier = () -> IntStream
.range(0, INNER_LIST_SIZE)
.mapToObj(ptr -> rand().nextInt(100))
.collect(Collectors.toList());
@Setup …Run Code Online (Sandbox Code Playgroud) 我有一个微基准测试,显示非常奇怪的结果:
@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
@Measurement(iterations = 40, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
public class Chaining {
private String a1 = "111111111111111111111111";
private String a2 = "222222222222222222222222";
private String a3 = "333333333333333333333333";
@Benchmark
public String typicalChaining() {
return new StringBuilder().append(a1).append(a2).append(a3).toString();
}
@Benchmark
public String noChaining() {
StringBuilder sb = new StringBuilder();
sb.append(a1);
sb.append(a2);
sb.append(a3);
return sb.toString();
}
}
Run Code Online (Sandbox Code Playgroud)
我期待两个测试的结果相同或至少非常接近.但是,差异几乎是5倍:
# Run complete. Total time: 00:01:41 …Run Code Online (Sandbox Code Playgroud) 我偶然发现了一个非常不稳定的性能曲线实例,它对原始数组进行了非常简单的map/reduce操作.这是我的jmh基准代码:
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@OperationsPerInvocation(Measure.ARRAY_SIZE)
@Warmup(iterations = 300, time = 200, timeUnit=MILLISECONDS)
@Measurement(iterations = 1, time = 1000, timeUnit=MILLISECONDS)
@State(Scope.Thread)
@Threads(1)
@Fork(1)
public class Measure
{
static final int ARRAY_SIZE = 1<<20;
final int[] ds = new int[ARRAY_SIZE];
private IntUnaryOperator mapper;
@Setup public void setup() {
setAll(ds, i->(int)(Math.random()*(1<<7)));
final int multiplier = (int)(Math.random()*10);
mapper = d -> multiplier*d;
}
@Benchmark public double multiply() {
return Arrays.stream(ds).map(mapper).sum();
}
}
Run Code Online (Sandbox Code Playgroud)
以下是典型输出的片段:
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 300 iterations, …Run Code Online (Sandbox Code Playgroud) 我在这里看到很多线程比较并尝试回答哪个更快:newInstance或者new operator.
看看源代码,它看起来newInstance应该慢得多,我的意思是它做了很多安全检查并使用反射.而且我决定先测量一下jdk-8.这是使用的代码jmh.
@BenchmarkMode(value = { Mode.AverageTime, Mode.SingleShotTime })
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class TestNewObject {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(TestNewObject.class.getSimpleName()).build();
new Runner(opt).run();
}
@Fork(1)
@Benchmark
public Something newOperator() {
return new Something();
}
@SuppressWarnings("deprecation")
@Fork(1)
@Benchmark
public Something newInstance() throws InstantiationException, IllegalAccessException {
return Something.class.newInstance(); …Run Code Online (Sandbox Code Playgroud) 我编写了一些 Scala 代码来对集合执行元素操作。在这里,我定义了两个执行相同任务的方法。一种方法使用zip,另一种使用zipped.
def ES (arr :Array[Double], arr1 :Array[Double]) :Array[Double] = arr.zip(arr1).map(x => x._1 + x._2)
def ES1(arr :Array[Double], arr1 :Array[Double]) :Array[Double] = (arr,arr1).zipped.map((x,y) => x + y)
Run Code Online (Sandbox Code Playgroud)
为了在速度方面比较这两种方法,我编写了以下代码:
def fun (arr : Array[Double] , arr1 : Array[Double] , f :(Array[Double],Array[Double]) => Array[Double] , itr : Int) ={
val t0 = System.nanoTime()
for (i <- 1 to itr) {
f(arr,arr1)
}
val t1 = System.nanoTime()
println("Total Time Consumed:" + ((t1 - t0).toDouble / 1000000000).toDouble + "Seconds") …Run Code Online (Sandbox Code Playgroud) performance scala scala-collections jmh elementwise-operations
如何使用JUnit测试在现有项目中运行JMH基准测试?官方文档建议使用Maven shade插件创建一个单独的项目,并在main方法中启动JMH .这是必要的,为什么推荐?
jmh ×10
java ×8
performance ×6
java-8 ×4
java-stream ×2
benchmarking ×1
java-11 ×1
java-12 ×1
java-7 ×1
java-9 ×1
junit ×1
lambda ×1
low-latency ×1
scala ×1