GEOS icon indicating copy to clipboard operation
GEOS copied to clipboard

Suggestion for better GTEST output with MPI.

Open corbett5 opened this issue 4 years ago • 0 comments

I figured out a way to greatly reduce the extra test output when running gtest with MPI. All the common stuff like

[ RUN      ] BoundaryID.info
[       OK ] BoundaryID.info (0 ms)

that is normally printed by every single rank is now only printed by rank 0. Furthermore every EXPECT/ASSERT message includes the rank the error occurred on. If anyone finds this useful go ahead and steal it, the MPI calls will need to be renamed but I think that's it.

/**
 *
 */
class MPITestPrinter : public ::testing::TestEventListener
{
public:
  MPITestPrinter( ::testing::TestEventListener * defaultListener ):
    _defaultListener( defaultListener )
  {}

private:

  void OnTestProgramStart( ::testing::UnitTest const & unitTest ) override
  { if( _rank == 0 ) _defaultListener->OnTestProgramStart( unitTest ); }

  void OnTestIterationStart( ::testing::UnitTest const & unitTest, int const iteration ) override
  { if( _rank == 0 ) _defaultListener->OnTestIterationStart( unitTest, iteration ); }

  void OnEnvironmentsSetUpStart( ::testing::UnitTest const & unitTest ) override
  { if( _rank == 0 ) _defaultListener->OnEnvironmentsSetUpStart( unitTest ); }

  void OnEnvironmentsSetUpEnd( ::testing::UnitTest const & unitTest ) override
  { if( _rank == 0 ) _defaultListener->OnEnvironmentsSetUpEnd( unitTest ); }

  void OnTestStart( ::testing::TestInfo const & testInfo ) override
  {
    mpi::barrier( MPI_COMM_WORLD );
    if( _rank == 0 ) _defaultListener->OnTestStart( testInfo );
  }

  void OnTestPartResult( ::testing::TestPartResult const & testPartialResult ) override
  {
    std::cout << "Rank " << _rank << " ";
    _defaultListener->OnTestPartResult( testPartialResult );
  }

  void OnTestEnd( ::testing::TestInfo const & testInfo ) override
  {
    int const failed = testInfo.result()->Failed();
    int const numFailed = mpi::sum( failed, MPI_COMM_WORLD );

    if( _rank == 0 )
    {
      if( numFailed > 0 && !failed )
      {
        std::string const msg = std::to_string( numFailed ) + " ranks failed this test.";
        GTEST_NONFATAL_FAILURE_( msg.data() );
      }

      _defaultListener->OnTestEnd( testInfo );
    }
  }

  void OnEnvironmentsTearDownStart( ::testing::UnitTest const & unitTest ) override
  { if( _rank == 0 ) _defaultListener->OnEnvironmentsTearDownStart( unitTest ); }

  void OnEnvironmentsTearDownEnd( ::testing::UnitTest const & unitTest ) override
  { if( _rank == 0 ) _defaultListener->OnEnvironmentsTearDownEnd( unitTest ); }

  void OnTestIterationEnd( ::testing::UnitTest const & unitTest, int const iteration ) override
  { if( _rank == 0 ) _defaultListener->OnTestIterationEnd( unitTest, iteration ); }

  virtual void OnTestProgramEnd( ::testing::UnitTest const & unitTest ) override
  { if( _rank == 0 ) _defaultListener->OnTestProgramEnd( unitTest ); }

  std::unique_ptr< ::testing::TestEventListener > _defaultListener;
  
  int const _rank = mpi::commRank( MPI_COMM_WORLD );
};

/**
 *
 */
void addMPITestPrinter()
{
  ::testing::TestEventListeners & listeners = ::testing::UnitTest::GetInstance()->listeners();
  listeners.Append( new MPITestPrinter( listeners.Release( listeners.default_result_printer() ) ) );
}

To use call addMPITestPrinter inbetween InitGoogleTest and RUN_ALL_TESTS.

* According to the GTEST docs what I'm doing isn't allowed since it violates point 2 (http://google.github.io/googletest/advanced.html#generating-failures-in-listeners), but it would be simple to make it compliant by adding another listener.

corbett5 avatar Jan 11 '22 06:01 corbett5