Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Main/UnitTest.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief UnitTest's Charm++ main chare and main().
9 : : \details UnitTest's Charm++ main chare and main(). This file contains
10 : : the definition of the Charm++ main chare, equivalent to main() in Charm++-
11 : : land, running the serial and Charm++ unit tests as well as the ordinary
12 : : main() function, running the MPI unit test suite.
13 : : */
14 : : // *****************************************************************************
15 : :
16 : : #include <map>
17 : : #include <vector>
18 : : #include <string>
19 : : #include <iostream>
20 : : #include <utility>
21 : : #include <cstddef>
22 : :
23 : : #include "NoWarning/tut_runner.hpp"
24 : :
25 : : #include "NoWarning/tutsuite.decl.h"
26 : : #include "NoWarning/unittest.decl.h"
27 : :
28 : : #include "Print.hpp"
29 : : #include "Timer.hpp"
30 : : #include "Tags.hpp"
31 : : #include "Exception.hpp"
32 : : #include "Init.hpp"
33 : : #include "WalkerConfig.hpp"
34 : : #include "HelpFactory.hpp"
35 : : #include "Assessment.hpp"
36 : : #include "ProcessException.hpp"
37 : : #include "UnitTest/CmdLine/CmdLine.hpp"
38 : : #include "UnitTestPrint.hpp"
39 : : #include "UnitTestDriver.hpp"
40 : : #include "UnitTest/CmdLine/Parser.hpp"
41 : : #include "TUTConfig.hpp"
42 : : #include "ChareStateCollector.hpp"
43 : : #include "QuietCerr.hpp"
44 : :
45 : : #if defined(__clang__)
46 : : #pragma clang diagnostic push
47 : : #pragma clang diagnostic ignored "-Wmissing-variable-declarations"
48 : : #endif
49 : :
50 : : //! \brief Charm handle to the main proxy, facilitates call-back to finalize,
51 : : //! etc., must be in global scope, unique per executable
52 : : CProxy_Main mainProxy;
53 : :
54 : : //! Chare state collector Charm++ chare group proxy
55 : : tk::CProxy_ChareStateCollector stateProxy;
56 : :
57 : : //! If true, call and stack traces are to be output with exceptions
58 : : //! \note This is true by default so that the trace is always output between
59 : : //! program start and the Main ctor in which the user-input from command line
60 : : //! setting for this overrides this true setting.
61 : : bool g_trace = true;
62 : :
63 : : #if defined(__clang__)
64 : : #pragma clang diagnostic pop
65 : : #endif
66 : :
67 : : //! UnitTest declarations and definitions
68 : : namespace unittest {
69 : :
70 : : //! Global-scope data. Initialized by the main chare and distibuted to all PEs
71 : : //! by the Charm++ runtime system. Though semantically not const, all these
72 : : //! global data should be considered read-only. See also
73 : : //! http://charm.cs.illinois.edu/manuals/html/charm++/manual.html. The data
74 : : //! below is global-scope because they must be available to all PEs which could
75 : : //! be on different machines.
76 : :
77 : : #if defined(__clang__)
78 : : #pragma clang diagnostic push
79 : : #pragma clang diagnostic ignored "-Wmissing-variable-declarations"
80 : : #endif
81 : :
82 : : //! Template Unit Test test runner
83 : : tut::test_runner_singleton g_runner;
84 : :
85 : : //! Test suite Charm++ proxy facilitating call-back to unit test suite by
86 : : //! individual unit tests spawning Charm++ chares
87 : : CProxy_TUTSuite g_suiteProxy;
88 : :
89 : : //! UnitTest executable name. So that FileParser's unit tests can access a file
90 : : //! for opening.
91 : : std::string g_executable;
92 : :
93 : : //! Max number of tests in every group
94 : : int g_maxTestsInGroup = tut::MAX_TESTS_IN_GROUP;
95 : :
96 : : #if defined(__clang__)
97 : : #pragma clang diagnostic pop
98 : : #endif
99 : :
100 : : //! Pack/Unpack test runner. This Pack/Unpack method (re-)creates the
101 : : //! test runner singleton on all processing elements. Therefore we circumvent
102 : : //! Charm's usual pack/unpack for this type, and thus sizing does not make
103 : : //! sense: sizing is a no-op. We could initialize the stack in UnitTestDriver's
104 : : //! constructor and let this function re-create the runner only when unpacking,
105 : : //! but that leads to repeating the same code twice: once in UnitTestDriver's
106 : : //! constructor, once here. Another option is to use this pack/unpack routine to
107 : : //! both initially create (when packing) and to re-create (when unpacking) the
108 : : //! runner, which eliminates the need for pre-creating the object in
109 : : //! UnitTestDriver's constructor and therefore eliminates the repeated code.
110 : : //! This explains the guard for sizing: the code below is called for packing
111 : : //! only (in serial) and packing and unpacking (in parallel).
112 : 5 : inline void operator|( PUP::er& p, tut::test_runner_singleton& runner )
113 [ + + ]: 5 : { if (!p.isSizing()) runner = tut::test_runner_singleton(); }
114 : :
115 : : } // unittest::
116 : :
117 : : //! \brief Charm++ main chare for the unit test suite executable, unittest.
118 : : //! \details Note that this object should not be in a namespace.
119 : : // cppcheck-suppress noConstructor
120 : : class Main : public CBase_Main {
121 : :
122 : : public:
123 : : //! \brief Constructor
124 : : //! \details UnitTest's main chare constructor is the entry point of the
125 : : //! program, called by the Charm++ runtime system. The constructor does
126 : : //! basic initialization steps, e.g., parser the command-line, prints out
127 : : //! some useful information to screen (in verbose mode), and instantiates
128 : : //! a driver. Since Charm++ is fully asynchronous, the constructor
129 : : //! usually spawns asynchronous objects and immediately exits. Thus in the
130 : : //! body of the main chare constructor we fire up an 'execute' chare,
131 : : //! which then calls back to Main::execute(). Finishing the main chare
132 : : //! constructor the Charm++ runtime system then starts the
133 : : //! network-migration of all global-scope data (if any). The execute chare
134 : : //! calling back to Main::execute() signals the end of the migration of
135 : : //! the global-scope data. Then we are ready to execute the driver. Since
136 : : //! the unit test suite is parallel and asynchronous, its driver fires up
137 : : //! additional Charm++ chare objects which then call back to
138 : : //! Main::finalize() at some point in the future when all work has been
139 : : //! finished. finalize() then exits by calling Charm++'s CkExit(),
140 : : //! shutting down the runtime system.
141 : : //! \see http://charm.cs.illinois.edu/manuals/html/charm++/manual.html
142 : 1 : Main( CkArgMsg* msg )
143 : 1 : try :
144 : 2 : m_signal( tk::setSignalHandlers() ),
145 : : m_helped( false ),
146 : : m_cmdline(),
147 : : // Parse command line into m_cmdline using default simple pretty printer
148 [ + - ]: 2 : m_cmdParser( msg->argc, msg->argv, tk::Print(), m_cmdline, m_helped ),
149 : : // Create UnitTest driver
150 : : m_driver( tk::Main< unittest::UnitTestDriver >
151 : : ( msg->argc, msg->argv,
152 : 1 : m_cmdline,
153 : : tk::HeaderType::UNITTEST,
154 [ + - ]: 2 : tk::unittest_executable(),
155 : 1 : m_cmdline.get< tag::io, tag::screen >(),
156 [ + - ]: 2 : m_cmdline.get< tag::io, tag::nrestart >() ) ),
157 : : m_timer(1), // Start new timer measuring the serial+Charm++ runtime
158 [ + - ][ + - ]: 4 : m_timestamp()
[ + - ][ + - ]
[ + - ]
159 : : {
160 : 1 : g_trace = m_cmdline.get< tag::trace >();
161 : : // Immediately exit if any help was requested; help is printed in main()
162 [ - + ][ - - ]: 1 : if (m_helped) CkExit();
163 : : // Save executable name to global-scope string so FileParser can access it
164 [ + - ]: 1 : unittest::g_executable = msg->argv[0];
165 [ + - ][ + - ]: 1 : delete msg;
166 : : // Call generic mainchare contructor
167 [ + - ]: 1 : tk::MainCtor( mainProxy, thisProxy, m_timer, m_cmdline,
168 [ + - ][ + - ]: 2 : CkCallback( CkIndex_Main::quiescence(), thisProxy ) );
169 : : // If quiescence detection is on or user requested it, create chare state
170 : : // collector Charm++ chare group
171 [ + - ][ - + ]: 1 : if ( m_cmdline.get< tag::chare >() || m_cmdline.get< tag::quiescence >() )
[ - + ]
172 [ - - ][ - - ]: 0 : stateProxy = tk::CProxy_ChareStateCollector::ckNew();
173 : : // Fire up an asynchronous execute object, which when created at some
174 : : // future point in time will call back to this->execute(). This is
175 : : // necessary so that this->execute() can access already migrated
176 : : // global-scope data.
177 [ + - ]: 1 : CProxy_execute::ckNew();
178 : : // Quiet std::cerr
179 [ + - ]: 1 : tk::CProxy_QuietCerr::ckNew();
180 [ - - ]: 1 : } catch (...) { tk::processExceptionCharm(); }
181 : :
182 : 1 : void execute() {
183 : : try {
184 [ + - ][ + - ]: 1 : m_timestamp.emplace_back("Migrate global-scope data", m_timer[1].hms());
185 : 1 : m_driver.execute(); // fires up async chares
186 [ - - ]: 0 : } catch (...) { tk::processExceptionCharm(); }
187 : 1 : }
188 : :
189 : : //! Towards normal exit but collect chare state first (if any)
190 : 1 : void finalize( bool pass ) {
191 [ - - ]: 1 : tk::finalize( m_cmdline, m_timer, stateProxy, m_timestamp,
192 : 1 : m_cmdline.get< tag::io, tag::screen >(),
193 : 1 : m_cmdline.get< tag::io, tag::nrestart >(),
194 : 1 : CkCallback( CkIndex_Main::dumpstate(nullptr), thisProxy ),
195 : : pass );
196 : 0 : }
197 : :
198 : : //! Entry method triggered when quiescence is detected
199 : 0 : void quiescence() {
200 : : try {
201 [ - - ]: 0 : stateProxy.collect( /* error= */ true,
202 [ - - ][ - - ]: 0 : CkCallback( CkIndex_Main::dumpstate(nullptr), thisProxy ) );
203 [ - - ]: 0 : } catch (...) { tk::processExceptionCharm(); }
204 : 0 : }
205 : :
206 : : //! Dump chare state
207 : 0 : void dumpstate( CkReductionMsg* msg ) {
208 : 0 : tk::dumpstate( m_cmdline,
209 : 0 : m_cmdline.get< tag::io, tag::screen >(),
210 : 0 : m_cmdline.get< tag::io, tag::nrestart >(),
211 : : msg );
212 : 0 : }
213 : :
214 : : private:
215 : : int m_signal; //!< Used to set signal handlers
216 : : bool m_helped; //!< Indicates if help was requested on the command line
217 : : unittest::ctr::CmdLine m_cmdline; //!< Command line
218 : : unittest::CmdLineParser m_cmdParser; //!< Command line parser
219 : : unittest::UnitTestDriver m_driver; //!< Driver
220 : : std::vector< tk::Timer > m_timer; //!< Timers
221 : :
222 : : //! Time stamps in h:m:s with labels
223 : : std::vector< std::pair< std::string, tk::Timer::Watch > > m_timestamp;
224 : : };
225 : :
226 : : //! \brief Charm++ chare execute
227 : : //! \details By the time this object is constructed, the Charm++ runtime system
228 : : //! has finished migrating all global-scoped read-only objects which happens
229 : : //! after the main chare constructor has finished.
230 : : class execute : public CBase_execute {
231 [ + - ]: 1 : public: execute() { mainProxy.execute(); }
232 : : };
233 : :
234 : : #include "NoWarning/unittest.def.h"
|