【问题标题】:Running unit tests with mpirun using ant使用 ant 使用 mpirun 运行单元测试
【发布时间】:2019-06-24 17:20:21
【问题描述】:

我正在尝试使用 ant 通过 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>

运行例如:

 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.

使用详细标志运行 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

我怎样才能做到这一点?

【问题讨论】:

  • 编写一个名为mpirun_java.sh 的脚本调用mpirun java,并让jvm 指向它。
  • 有效!谢谢!你知道为什么我不能让jvm直接指向“mpirun java”吗?
  • 我猜ant 需要一个文件来执行,而不是一个文件后跟参数。
  • 看看stackoverflow.com/questions/25039864/… ant try jvmarg,如果可行,那就更优雅了。
  • 确实如此! (是的,它奏效了!)

标签: junit ant mpi


【解决方案1】:

这个问题已经很老了,似乎 Gilles Gouaillardet 在 cmets 中已成功解决。在我工作的学术环境中,我还尝试将 Junit 与 Java 和 MPI 一起使用。我无法成功使用 Gilles Gouaillardet 提出的技巧,最终得到了一个完全不同的解决方案。

自定义 Junit4 跑步者 - 总体思路

使用 MPI 运行 Junit 测试的另一种方法是实现自定义 Junit 运行器。

在此自定义 Junit 运行器中,您可以使用 ProcessLauncher 启动自定义命令,而不是“直接”调用测试方法。在我的实现中,我让每个 MPI 进程都使用普通的 Junit4 运行时来运行测试方法。但是,MPI 进程没有使用 Junit 运行时的普通 RunNotifier,而是使用我的自定义 RunNotifier,它将接收到的调用写入文件。调用

的文件

回到我的自定义运行程序,一旦 mpirun 进程完成,我会汇总每个 MPI 进程的每个测试方法的结果,并将这些结果传输到普通的RunNotifier

好处

使用此系统,您将停留在“正常”的 Junit4 框架内。就我而言,我试图从 Maven 运行 Junit 测试。我还可以成功地将测试结果与 Eclipse Junit 视图集成(这需要一些技巧,这些技巧未在下面的代码摘录中显示)。

这是运行测试后我的 Eclipse 环境的捕获(由于我的特定环境的一些额外复杂性,类名与下面摘录中的类名略有不同)。

部分选定代码详情

仅显示自定义MpiRunnerMpiTestLauncher 中最重要的部分。导入、try/catch 结构和许多细节已被删除。我最终会在 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();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-13
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    相关资源
    最近更新 更多