【问题标题】:How to test a program that uses Boost.MPI with Boost.Test?如何测试使用 Boost.MPI 和 Boost.Test 的程序?
【发布时间】:2021-07-25 19:15:35
【问题描述】:

我想用Boost.Test 对一个使用Boost.MPI 的并行程序进行单元测试。这些库的官方文档没有提供有关如何执行此操作的说明(或者我找不到它们)。问题是 MPI 代码需要只完成一次的初始化和终结,Boost.MPI 封装在environment(在某种程度上在communicator)对象中,RAII 样式。所以Boost.MPI 程序通常看起来像这样:

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>

int main(int argc, char *argv[]) {
  boost::mpi::environment env(argc, argv);
  boost::mpi::communicator world{};
  
  // ... parallel code here ...
}

但是,Boost.Test 在幕后提供了自己的 main() 函数。我可以通过定义#define BOOST_TEST_NO_MAIN 来覆盖这一点,然后自己编写main(),按照上面的草图。

但是问题开始了。如何告诉Boost.Test 在 MPI 下运行测试用例?应该像往常一样将它们定义为BOOST_AUTO_TEST_CASE(...) 宏还是有其他方法?又如何将communicator 对象(world)“传递”给测试用例?它应该设置在全局夹具中吗?如果是,那么全局固定装置如何与用户提供的main 一起工作?

我做了很多实验,用 Google 搜索了更多,但没有发现任何可用的东西。有没有人知道如何一起使用这两个 Boost 库?如果是,那么工作示例将不胜感激。谢谢。

编辑 SebastianH-s 的建议很快被拍了拍:

#define BOOST_TEST_MODULE mpitest
#define BOOST_TEST_NO_MAIN

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>

namespace bmpi = boost::mpi;

// Fixture
struct Fix {
    Fix(): env{}, world{} {}
    bmpi::environment env;
    bmpi::communicator world;
};

BOOST_FIXTURE_TEST_CASE(check_mpi, Fix) {
    if (world.rank() == 0) {
        std::cout << "MPI thread level: " <<
        bmpi::environment::thread_level() << std::endl;
    }
    std::cout << "I am process " << world.rank() << " of " << world.size()
            << "." << std::endl;
}

int main(int argc, char *argv[]) {
    // This runs the test cases.
    int retval = boost::unit_test::unit_test_main([](){ return true; }, argc, argv );
}

在 Ubuntu 下使用 g++ 9.3Boost 1.71 编译。但是当我运行它时:

Running 1 test case...
*** The MPI_Comm_set_errhandler() function was called before MPI_INIT was invoked.
*** This is disallowed by the MPI standard.
*** Your MPI job will now abort.

看,这就是问题所在:MPI 未正确初始化。

【问题讨论】:

  • @SebastianH 您如何将argcargv 放入夹具中以初始化boost::mpi::environment?我根据您的建议快速整理了一些东西(请参阅问题中的编辑),它不会按书面方式运行。欢迎具体改进。

标签: c++ unit-testing boost mpi


【解决方案1】:

我找到了两个解决方案。

解决方案 1:使用全局配置

这是相当简单和优雅的。关键是初始化MPI 在Boost.Test global configuration 类中(与global fixture 不同)。

代码:

#include "boost/mpi/environment.hpp"
#include "boost/mpi/communicator.hpp"
namespace bmpi = boost::mpi;

#define BOOST_TEST_MODULE mpitest
#include "boost/test/unit_test.hpp"
namespace bt = boost::unit_test;

#include <iostream>

struct GlobalConfig {
    GlobalConfig():
    env(
        bt::framework::master_test_suite().argc, 
        bt::framework::master_test_suite().argv,
        bmpi::threading::multiple)
    { }
    bmpi::environment env;
};

BOOST_TEST_GLOBAL_CONFIGURATION(GlobalConfig);
BOOST_AUTO_TEST_SUITE(mpitest);

BOOST_AUTO_TEST_CASE(check_mpi) {
    bmpi::communicator world;   // refers to global MPI_COMM_WORLD instance
    BOOST_CHECK(world.size() > 1);
    
    auto myrank = world.rank();
    if (myrank == 0) {
        std::cout << "MPI thread level: " << bmpi::environment::thread_level() << std::endl;
    }
    std::cout << "I am process " << myrank << " of " << world.size() << std::endl;
}

BOOST_AUTO_TEST_SUITE_END();

解决方案 2:手动构建测试套件

这比较复杂,因为你必须提供一个main() 函数, 并手动组合测试套件。

代码:

#include "boost/mpi/environment.hpp"
#include "boost/mpi/communicator.hpp"
namespace bmpi = boost::mpi;

#define BOOST_TEST_NO_MAIN
#define BOOST_TEST_MODULE mpitest
#define BOOST_TEST_DYN_LINK
#include "boost/test/unit_test.hpp"
namespace bt = boost::unit_test;

#include <iostream>

// This is a test case which we will add manually to the test suite.
// see `register_tests()`
void check_mpi() {
    bmpi::communicator world;   // refers to global MPI_COMM_WORLD instance
    BOOST_CHECK(world.size() > 1);
    
    auto myrank = world.rank();
    if (myrank == 0) {
        std::cout << "MPI thread level: " << bmpi::environment::thread_level() << std::endl;
    }
    std::cout << "I am process " << myrank << " of " << world.size() << std::endl;
}

// Put together a test suite manually.
void register_tests() {
    bt::test_suite* ts = BOOST_TEST_SUITE("mpitest");

    // Add a test case
    ts->add( BOOST_TEST_CASE( &check_mpi ));
    // ... add more test cases ...

    // Add the test suite to the "master" test suite
    // which is always provided by the Boost.Test framework
    bt::framework::master_test_suite().add(ts);
}

// == MAIN ==

int main(int argc, char *argv[]) {
    bmpi::environment env(argc, argv, bmpi::threading::multiple);
    bmpi::communicator world;

    register_tests();

    // Run the master test suite.
    // The lambda first argument has to be used if BOOST_TEST_DYN_LINK is set
    int retval = bt::unit_test_main([](){ return true; }, argc, argv );
    return retval;
}

将任一程序保存为mpitest.cc,编译(在带有g++ 9.3Boost 1.71 的Ubuntu 20.04 LTS 下)如下:

mpicxx -std=c++17  mpitest.cc -DBOOST_TEST_DYN_LINK \
   -L/usr/lib/x86_64-linux-gnu -lboost_unit_test_framework \
   -lboost_mpi -lboost_serialization  -o mpitest

运行如下:

mpirun -np 2 ./mpitest

预期输出:

Running 1 test case...
Running 1 test case...
I am process 1 of 2
MPI thread level: multiple
I am process 0 of 2

*** No errors detected
*** No errors detected

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多