如何使用 exec:java 而不是 exec:exec 在 Maven 中 运行 JMH 基准?
How to Run a JMH Benchmark in Maven Using exec:java Instead of exec:exec?
通过键入 mvn exec:exec
在 Maven 中进行此 post on javapapers.com shows how to run a JMH 基准测试。 运行在 Maven 中使用 JMH 非常方便,因为您可以从 Eclipse 运行 配置甚至在 Maven 阶段轻松地 运行 它。
但是,此设置有两个问题:
当您终止 Maven 时,JMH 将在后台继续 运行ning,因为 exec:exec
在单独的 VM 中启动它。
通常,JMH 会启动 另一个 VM 以 运行 基准测试,因此您最终将至少拥有 3 个 VM 运行同时.
幸运的是,Exec Maven Plugin 带有第二个目标,exec:java
,它直接在 VM Maven 运行s 中执行一个主要的 class。但是,当我尝试使用 exec:java
将 Maven 配置为 运行 JMH 时,基准测试因缺少 classes:
而崩溃
# JMH 1.11.3 (released 40 days ago)
# VM version: Error: Could not find or load main class org.openjdk.jmh.runner.VersionMain
# VM invoker: C:\Program Files\Java\jdk1.7.0\jre\bin\java.exe
[...]
# Run progress: 0.00% complete, ETA 00:02:40
# Fork: 1 of 1
Error: Could not find or load main class org.openjdk.jmh.runner.ForkedMain
<forked VM failed with exit code 1>
这里是pom.xml
的相关部分:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<mainClass>my.Benchmark</mainClass>
</configuration>
</plugin>
这就是我 运行 来自 my.Benchmark
的 JMH:
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder().include(my.Benchmark.class.getSimpleName())
.forks(1).build();
new Runner(options).run();
}
我意识到 JMH 使用 java.class.path
系统 属性 来确定分支 VM 的 class 路径并且这个 属性 不包含 Maven 的项目依赖项。但是处理这个问题的首选方法是什么?
解决此问题的一种方法是在调用 JMH 之前从 my.Benchmark
class 的 class 加载程序中提取 "effective" class 路径来自我的主要方法:
URLClassLoader classLoader = (URLClassLoader) my.Benchmark.class.getClassLoader();
StringBuilder classpath = new StringBuilder();
for(URL url : classLoader.getURLs())
classpath.append(url.getPath()).append(File.pathSeparator);
System.setProperty("java.class.path", classpath.toString());
这似乎可行,但感觉很像一个不必要的 hack...
虽然我之前的回答需要修改基准程序,但这里是一个仅 POM 的解决方案,它在 java.class.path
系统 属性 的帮助下将 runtime
类路径设置为 Dependency Plugin:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>build-classpath</id>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputProperty>depClasspath</outputProperty>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>my.Benchmark</mainClass>
<systemProperties>
<systemProperty>
<key>java.class.path</key>
<value>${project.build.outputDirectory}${path.separator}${depClasspath}</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>
通过键入 mvn exec:exec
在 Maven 中进行此 post on javapapers.com shows how to run a JMH 基准测试。 运行在 Maven 中使用 JMH 非常方便,因为您可以从 Eclipse 运行 配置甚至在 Maven 阶段轻松地 运行 它。
但是,此设置有两个问题:
当您终止 Maven 时,JMH 将在后台继续 运行ning,因为
exec:exec
在单独的 VM 中启动它。通常,JMH 会启动 另一个 VM 以 运行 基准测试,因此您最终将至少拥有 3 个 VM 运行同时.
幸运的是,Exec Maven Plugin 带有第二个目标,exec:java
,它直接在 VM Maven 运行s 中执行一个主要的 class。但是,当我尝试使用 exec:java
将 Maven 配置为 运行 JMH 时,基准测试因缺少 classes:
# JMH 1.11.3 (released 40 days ago)
# VM version: Error: Could not find or load main class org.openjdk.jmh.runner.VersionMain
# VM invoker: C:\Program Files\Java\jdk1.7.0\jre\bin\java.exe
[...]
# Run progress: 0.00% complete, ETA 00:02:40
# Fork: 1 of 1
Error: Could not find or load main class org.openjdk.jmh.runner.ForkedMain
<forked VM failed with exit code 1>
这里是pom.xml
的相关部分:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<mainClass>my.Benchmark</mainClass>
</configuration>
</plugin>
这就是我 运行 来自 my.Benchmark
的 JMH:
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder().include(my.Benchmark.class.getSimpleName())
.forks(1).build();
new Runner(options).run();
}
我意识到 JMH 使用 java.class.path
系统 属性 来确定分支 VM 的 class 路径并且这个 属性 不包含 Maven 的项目依赖项。但是处理这个问题的首选方法是什么?
解决此问题的一种方法是在调用 JMH 之前从 my.Benchmark
class 的 class 加载程序中提取 "effective" class 路径来自我的主要方法:
URLClassLoader classLoader = (URLClassLoader) my.Benchmark.class.getClassLoader();
StringBuilder classpath = new StringBuilder();
for(URL url : classLoader.getURLs())
classpath.append(url.getPath()).append(File.pathSeparator);
System.setProperty("java.class.path", classpath.toString());
这似乎可行,但感觉很像一个不必要的 hack...
虽然我之前的回答需要修改基准程序,但这里是一个仅 POM 的解决方案,它在 java.class.path
系统 属性 的帮助下将 runtime
类路径设置为 Dependency Plugin:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>build-classpath</id>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputProperty>depClasspath</outputProperty>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>my.Benchmark</mainClass>
<systemProperties>
<systemProperty>
<key>java.class.path</key>
<value>${project.build.outputDirectory}${path.separator}${depClasspath}</value>
</systemProperty>
</systemProperties>
</configuration>
</plugin>