我试图通过mpirun使用蚂蚁来运行我的单元测试。我已经指定了任务为
<target name="unitTest" depends="buildUnitTest">
<mkdir dir="reports"/>
<junit fork="yes" jvm="mpirun java" printsummary="yes" haltonfailure="yes">
<classpath>
<pathelement location="./bin"/>
<pathelement location="/usr/share/java/junit4.jar"/>
</classpath>
<jvmarg value="-DDIM=3"/>
<jvmarg value="-ea"/>
<formatter type="plain"/>
<batchtest todir="reports">
<fileset dir="test">
<include name="haparanda/utils/*Test.java"/>
<include name="haparanda/iterators/*Test.java"/>
<exclude name="haparanda/iterators/FieldIteratorTest.java"/>
<include name="haparanda/grid/*Test.java"/>
</fileset>
</batchtest>
</junit>
</target>
从命令行运行eg:
mpirun java -ea -DDIM=3 -cp ./bin:/usr/share/java/junit4.jar org.junit.runner.JUnitCore haparanda.grid.ComputationalComposedBlockTest
从命令行运行就可以了。然而,当我运行时。
ant unitTest
我得到了以下错误。
BUILD FAILED
.../build.xml:28: Process fork failed.
用 verbose 标志运行 ant,我被告知我得到了一个带有错误信息的 IOException。
Cannot run program "mpirun java": error=2, No such file or directory
当我指定了mpirun和Java的完整路径时也是如此。
<junit fork="yes" jvm="/home/malin/bin/openmpi/bin/mpirun /usr/bin/java" printsummary="yes" haltonfailure="yes">
给我。
.../build.xml:28: Process fork failed.
at ...
Caused by: java.io.IOException: Cannot run program "/home/malin/bin/openmpi/bin/mpirun /usr/bin/java": error=2, No such file or directory
我怎样才能让它工作?
这个问题很老了,似乎已经在Gilles Gouaillardet的评论中被成功解决了。在我工作的学术环境中,我也尝试使用Junit与Java和MPI。我无法成功地使用Gilles Gouaillardet提出的技巧,我最终采用了一个完全不同的解决方案。
使用MPI运行Junit测试的另一种方式包括实现一个自定义的Junit运行器。
在这个自定义的Junit运行器中,你可以使用ProcessLauncher启动你的自定义命令,而不是 "直接 "调用测试方法。在我的实现中,我让每个MPI进程都使用正常的Junit4运行时来运行测试方法。然而,我并没有使用正常的 RunNotifier
运行时,MPI进程使用我自定义的 RunNotifier
它将收到的调用写入一个文件。一个文件中包含了
在我的自定义运行程序中,一旦mpirun进程完成,我将每个MPI进程的每个测试方法的结果汇总,并将这些结果传送到正常的 RunNotifier
.
有了这个系统,你就可以呆在 "正常的 "Junit4框架内。在我的案例中,我试图从Maven运行Junit测试。我也可以成功地将测试结果与Eclipse Junit视图集成在一起(这需要一些技巧,下面的代码摘录中没有显示)。
下面是我的Eclipse环境在运行测试后的捕获(由于我的特定环境的一些额外的复杂情况,类名与下面摘录中所呈现的略有不同)。
只有最重要的定制部分 MpiRunner
和 MpiTestLauncher
显示。导入、trycatch结构和众多细节都已被删除。我最终会在GitHub上提供整个代码,但目前还没有完全准备好。
/** A test class using the custom "MpiRunner" */
@RunWith(MpiRunner.class)
public class TestUsingMpi {
@Test
public void test() {
assertTrue("Should run with multiple processes", MPI.COMM_WORLD.Size() > 1);
}
}
/** Curstom Junit4 Runner */
public class MpiRunner extends Runner {
// some methods skipped, try/catch blocks have been removed
@Override
public void run(RunNotifier notifier) {
// Build the command
final ArrayList<String> command = new ArrayList<>();
command.add("mpirun");
command.add("-np");
command.add(String.valueOf(processCount));
command.add("java");
// Classpath, UserDirectory, JavaLibraryPath ...
command.add("MpiTestLauncher "); // Class with main
command.add(testClass.getCanonicalName()); // Class under test as argument
ProcessBuilder pb = new ProcessBuilder(command);
File mpirunOutFile = new File("MpirunCommandOutput.txt");
pb.redirectOutput(Redirect.appendTo(mpirunOutFile));
pb.redirectError(Redirect.appendTo(mpirunOutFile));
Process p = pb.start(); // Launch the mpirun command
p.waitFor(); // Wait for termination
// Parse the notifications of each MPI process
for (int i = o; i < NbProcesses; i++) {
List<Notification> mpiRankNotifs = parse(i);
//Re-run those notifications on the parameter "notifier" of this method
for (Notification n : notifications) {
//Reconstitute the method call made in the mpi process
Class<?> paramClass = n.parameters[0].getClass();
Method m = RunNotifier.class.getDeclaredMethod(n.method, paramClass);
m.invoke(notifier, n.parameters);
}
}
}
}
/** Main class of the Mpirun java processes */
public class MpiTestLauncher {
public static void main(String[] args) throws Exception {
MPI.Init(args);
commRank = MPI.COMM_WORLD.Rank();
commSize = MPI.COMM_WORLD.Size();
Class<?> testClass = Class.forName(args[0]); // Class that contains the tests
String notificationFileName = testClass.getCanonicalName() + "_" +
commRank;
File f = new File(notificationFileName);
CustomNotifier notifier = new MpiApgasRunNotifier(f);
BlockJUnit4ClassRunner junitDefaultRunner = new BlockJUnit4ClassRunner(testClass);
junitDefaultRunner.run(notifier);
notifier.close(); //Flushes the underlying buffer
MPI.Finalize();
}
}