[英]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.3
和Boost
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.3
和Boost 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.