簡體   English   中英

如何測試使用 Boost.MPI 和 Boost.Test 的程序?

[英]How to test a program that uses Boost.MPI with Boost.Test?

我想用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() function。 我可以通過定義#define BOOST_TEST_NO_MAIN然后自己編寫main()來覆蓋這一點,按照上面的草圖。

但隨后問題就開始了。 如何告訴Boost.Test在 MPI 下運行測試用例? 應該像往常一樣將它們定義為BOOST_AUTO_TEST_CASE(...)宏還是有其他方法? 以及如何將communicator器 object( world )“傳遞”到測試用例? 它應該設置在全局夾具中嗎? 如果是,那么全局燈具如何與用戶提供的main一起工作?

我做了很多實驗,用谷歌搜索了更多,但沒有發現任何可用的東西。 有沒有人知道如何一起使用這兩個 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 未正確初始化。

我找到了兩種解決方案。

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

這是相當簡單和優雅的。 關鍵是在Boost.Test 全局配置class 中初始化 MPI(這與全局夾具不同)。

代碼:

#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() function,並手動組合測試套件。

代碼:

#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 ,編譯(在 Ubuntu 20.04 LTS 與g++ 9.3Boost 1.71下)如下:

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

預期 output:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM