JMH 迭代次数从 >300,000 ops/sec 到 < 1 op/sec
JMH iterations go from >300,000 ops/sec to < 1 op/sec
我的mainclass包含多线程要使用的数据结构。在我原来的程序中,我也是在这里启动线程。
public class JDKSolution {
public static final ConcurrentHashMap<Long, Book> books = new ConcurrentHashMap<>();
public static void main(String[] args) throws RunnerException{
Options opt = new OptionsBuilder()
.include(JDKSolutionThread.class.getSimpleName())
.forks(1)
.jvmArgsAppend("-XX:MaxInlineLevel=12")
.verbosity(VerboseMode.EXTRA)
.build();
new Runner(opt).run();
}
}
书简直了
public class Book {
static long count = 0;
long id;
Book(){
synchronized(this){
id = count;
count++;
}
}
long getID(){
return id;
}
}
我有另一个扩展线程的 class;这里是要分析的方法。
@State(Scope.Benchmark)
public class JDKSolutionThread extends Thread{
@Benchmark
public void addBook(){
Book b = new Book();
books.put(b.getID(), b);
}
}
输出看起来像这样
# Warmup Iteration 15: 329731.671 ops/s
# Warmup Iteration 16: 23160.167 ops/s
# Warmup Iteration 17: 55316.913 ops/s
# Warmup Iteration 18: 30454.814 ops/s
# Warmup Iteration 19: 0.316 ops/s
# Warmup Iteration 20: 0.880 ops/s
Iteration 1: 0.085 ops/s
Iteration 2: 1.349 ops/s
...
Iteration 20: 4.508 ops/s
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 24 seconds more...>
Thread[DestroyJavaVM,5,main]
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1245)
at java.lang.Thread.join(Thread.java:1319)
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106)
at java.lang.ApplicationShutdownHooks.run(ApplicationShutdownHooks.java:46)
at java.lang.Shutdown.runHooks(Shutdown.java:123)
at java.lang.Shutdown.sequence(Shutdown.java:167)
at java.lang.Shutdown.shutdown(Shutdown.java:234)
Thread[Thread-0,5,main]
at java.lang.StringCoding.deref(StringCoding.java:63)
at java.lang.StringCoding.encode(StringCoding.java:330)
at java.lang.String.getBytes(String.java:918)
at java.io.UnixFileSystem.getBooleanAttributes0(Native Method)
at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:242)
at java.io.File.exists(File.java:819)
at sun.misc.URLClassPath$FileLoader.getResource(URLClassPath.java:1245)
at sun.misc.URLClassPath.getResource(URLClassPath.java:212)
at java.net.URLClassLoader.run(URLClassLoader.java:365)
at java.net.URLClassLoader.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.openjdk.jmh.runner.link.BinaryLinkClient.close(BinaryLinkClient.java:141)
at org.openjdk.jmh.runner.ForkedMain.hangup(ForkedMain.java:136)
at org.openjdk.jmh.runner.ForkedMain$HangupThread.run(ForkedMain.java:157)
<shutdown timeout of 30 seconds expired, forcing forked VM to exit>
每秒的操作应该在每次迭代 ~300000 的范围内。什么会导致少至 1 次操作?
在大多数基准测试模式中,JMH 一遍又一遍地调用 @Benchmark
。
假设 books
是一个集合,实际发生的是使集合饱和,并且每个 put
调用都会添加到越来越大的集合中。您必须在达到某个大小后清除集合,或者在 put
之后删除其他一些 Book
以保持恒定大小,或者将集合模拟为 "skip" 添加等。所有这些措施会对实验设计和您从实验中获得的数据产生影响,因此您有责任选择并面对后果。
我的mainclass包含多线程要使用的数据结构。在我原来的程序中,我也是在这里启动线程。
public class JDKSolution {
public static final ConcurrentHashMap<Long, Book> books = new ConcurrentHashMap<>();
public static void main(String[] args) throws RunnerException{
Options opt = new OptionsBuilder()
.include(JDKSolutionThread.class.getSimpleName())
.forks(1)
.jvmArgsAppend("-XX:MaxInlineLevel=12")
.verbosity(VerboseMode.EXTRA)
.build();
new Runner(opt).run();
}
}
书简直了
public class Book {
static long count = 0;
long id;
Book(){
synchronized(this){
id = count;
count++;
}
}
long getID(){
return id;
}
}
我有另一个扩展线程的 class;这里是要分析的方法。
@State(Scope.Benchmark)
public class JDKSolutionThread extends Thread{
@Benchmark
public void addBook(){
Book b = new Book();
books.put(b.getID(), b);
}
}
输出看起来像这样
# Warmup Iteration 15: 329731.671 ops/s
# Warmup Iteration 16: 23160.167 ops/s
# Warmup Iteration 17: 55316.913 ops/s
# Warmup Iteration 18: 30454.814 ops/s
# Warmup Iteration 19: 0.316 ops/s
# Warmup Iteration 20: 0.880 ops/s
Iteration 1: 0.085 ops/s
Iteration 2: 1.349 ops/s
...
Iteration 20: 4.508 ops/s
<JMH had finished, but forked VM did not exit, are there stray running threads? Waiting 24 seconds more...>
Thread[DestroyJavaVM,5,main]
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1245)
at java.lang.Thread.join(Thread.java:1319)
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106)
at java.lang.ApplicationShutdownHooks.run(ApplicationShutdownHooks.java:46)
at java.lang.Shutdown.runHooks(Shutdown.java:123)
at java.lang.Shutdown.sequence(Shutdown.java:167)
at java.lang.Shutdown.shutdown(Shutdown.java:234)
Thread[Thread-0,5,main]
at java.lang.StringCoding.deref(StringCoding.java:63)
at java.lang.StringCoding.encode(StringCoding.java:330)
at java.lang.String.getBytes(String.java:918)
at java.io.UnixFileSystem.getBooleanAttributes0(Native Method)
at java.io.UnixFileSystem.getBooleanAttributes(UnixFileSystem.java:242)
at java.io.File.exists(File.java:819)
at sun.misc.URLClassPath$FileLoader.getResource(URLClassPath.java:1245)
at sun.misc.URLClassPath.getResource(URLClassPath.java:212)
at java.net.URLClassLoader.run(URLClassLoader.java:365)
at java.net.URLClassLoader.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.openjdk.jmh.runner.link.BinaryLinkClient.close(BinaryLinkClient.java:141)
at org.openjdk.jmh.runner.ForkedMain.hangup(ForkedMain.java:136)
at org.openjdk.jmh.runner.ForkedMain$HangupThread.run(ForkedMain.java:157)
<shutdown timeout of 30 seconds expired, forcing forked VM to exit>
每秒的操作应该在每次迭代 ~300000 的范围内。什么会导致少至 1 次操作?
在大多数基准测试模式中,JMH 一遍又一遍地调用 @Benchmark
。
假设 books
是一个集合,实际发生的是使集合饱和,并且每个 put
调用都会添加到越来越大的集合中。您必须在达到某个大小后清除集合,或者在 put
之后删除其他一些 Book
以保持恒定大小,或者将集合模拟为 "skip" 添加等。所有这些措施会对实验设计和您从实验中获得的数据产生影响,因此您有责任选择并面对后果。