Branch data Line data Source code
1 : : // ***************************************************************************** 2 : : /*! 3 : : \file src/Base/Progress.hpp 4 : : \copyright 2012-2015 J. Bakosi, 5 : : 2016-2018 Los Alamos National Security, LLC., 6 : : 2019-2021 Triad National Security, LLC., 7 : : 2022-2024 J. Bakosi 8 : : All rights reserved. See the LICENSE file for details. 9 : : \brief Simple progress indicator 10 : : \details Simple progress indicator. 11 : : */ 12 : : // ***************************************************************************** 13 : : #ifndef Progress_h 14 : : #define Progress_h 15 : : 16 : : #include <array> 17 : : #include <functional> 18 : : 19 : : #include "TaggedTuple.hpp" 20 : : #include "Print.hpp" 21 : : 22 : : namespace tk { 23 : : 24 : : //! Simple progress class for outputing progress indicators during a task 25 : : //! \details This is a helper class to abstract away the details of using 26 : : //! Print::progress() used to output progress reports to the screen during 27 : : //! a task consisting of multiple sub-tasks happening at the same time. The 28 : : //! template argument is a compile-time integer which is the number of 29 : : //! independent sub-tasks the progress indicator receives messages for and 30 : : //! counts them independtly toward multiple maxima. 31 : : template< std::size_t N > 32 : : class Progress { 33 : : 34 : : public: 35 : : //! Constructor 36 : : //! \param[in] feedback Whether to send sub-task feedback to host 37 : : //! \param[in] prefix Strings to output prefixing the progress report 38 : : //! \param[in] legend Legend for each prefix to output at start 39 : : //! \param[in] max Array of integers equaling the max number of items to be 40 : : //! expected per sub-task 41 : 506 : explicit Progress( bool feedback, 42 : : const std::array< std::string, N >& prefix, 43 : : const std::array< std::string, N >& legend, 44 : : std::array< int, N >&& max = std::array< int, N >() ) 45 : 506 : : m_feedback( feedback ), 46 : 506 : m_prefix( std::move(prefix) ), 47 [ + - ]: 506 : m_legend( std::move(legend) ), 48 : 506 : m_finished( false ), 49 : 506 : m_progress_size( 0 ), 50 : 506 : m_max( std::move(max) ) 51 : : { 52 [ + - ]: 506 : m_done.fill( 0 ); 53 : 506 : } 54 : : 55 : : //! Start counting sub-tasks outputing an intial task message 56 : : //! \param[in] print Pretty printer object to use for printing progress 57 : : //! \param[in] msg Message to output to screen. This message should be 58 : : //! descriptive of all the sub-tasks we are responsible for. I.e., this 59 : : //! is usually a list of multiple sub-tasks happening at the same time. 60 : : //! Appending to msg we also output the legend of subtasks in parentheses. 61 : 484 : void start( const Print& print, const std::string& msg ) { 62 : 484 : std::string legend; 63 [ + + ]: 484 : if (m_feedback) { 64 [ + - ]: 22 : legend.append( " (" ); 65 [ + - ][ + - ]: 110 : for (const auto& l : m_legend) legend.append( l + ", " ); [ + + ] 66 : 22 : legend.pop_back(); 67 : 22 : legend.pop_back(); 68 [ + - ]: 22 : legend.append( ")" ); 69 : : } 70 [ + - ]: 484 : legend.append( " ..." ); 71 [ + - ][ + - ]: 484 : print.diagstart( msg + legend ); 72 : 484 : m_progress_size = 0; 73 : 484 : } 74 : : 75 : : //! \brief Start counting sub-tasks outputing an intial task message and set 76 : : //! max number of items to be expected per sub-task 77 : : //! \param[in] print Pretty printer object to use for printing progress 78 : : //! \param[in] msg Message to output to screen. This message should be 79 : : //! descriptive of all the sub-tasks we are responsible for. I.e., this 80 : : //! is usually a list of multiple sub-tasks happening at the same time. 81 : : //! \param[in] max Array of integers equaling the max number of items to be 82 : : //! expected per sub-task 83 : : //! \details This function can be used to do the same as start( msg ) and 84 : : //! update/reset the max number of items per sub-task in case they are not 85 : : //! all yet available when the constructor is called. 86 : 484 : void start( const Print& print, 87 : : const std::string& msg, 88 : : std::array< int, N >&& max ) 89 : : { 90 : 484 : m_max = std::move(max); 91 : 484 : start( print, msg ); 92 : 484 : } 93 : : 94 : : //! Receive an update to a sub-task counter and update progress report 95 : : //! \param[in] print Pretty printer object to use for printing progress 96 : : //! \details The template argument indexes the sub-task. A compile-time 97 : : //! assert emits an error in case it is out of bounds. 98 : 272 : template< std::size_t i > void inc( const Print& print ) { 99 : : static_assert( i < N, "Indexing out of bounds" ); 100 : 272 : ++m_done[i]; 101 [ + + ]: 272 : if (!m_finished) report( print ); 102 : 272 : } 103 : : 104 : : //! Finish progress report updating it one last time 105 : : //! \param[in] print Pretty printer object to use for printing progress 106 : : //! \details When this function is called, all sub-tasks are assumed to be 107 : : //! finished, i.e., assumed to have reached their respective maximum 108 : : //! values. Thus we update our 'done' array to be equal to 'max' and output 109 : : //! the progress report one final time before outputing 'done'. When this 110 : : //! function is called it is possible that not all sub-task counters have 111 : : //! reached their maximum, which can happen if the final reduction (if 112 : : //! exists), signaling the absolute end of a task (consisting of multiple 113 : : //! sub-tasks we count counters for), is scheduled before (or is faster) 114 : : //! than as the individual sub-task counting messages arrive. Even if that 115 : : //! is the case, this call "officially" finishes all sub-tasks, and outputs 116 : : //! the progress report using the max values for all sub-tasks to leave a 117 : : //! consistent screen output finishing the task. 118 : 484 : void end( const Print& print ) { 119 : 484 : m_finished = true; 120 : 484 : m_done = m_max; 121 : 484 : report( print ); 122 [ + - ][ + - ]: 484 : print.diagend( "done" ); 123 : 484 : } 124 : : 125 : : private: 126 : : bool m_feedback; //!< Whether to send sub-task feedback to host 127 : : const std::array< std::string, N > m_prefix; //!< Sub-task prefixes 128 : : const std::array< std::string, N > m_legend; //!< Sub-task legend 129 : : bool m_finished; //!< Whether task has finished 130 : : std::size_t m_progress_size;//!< Size of previous progress report 131 : : std::array< int, N > m_max; //!< Max number of items per sub-task 132 : : std::array< int, N > m_done;//!< Number of items done per sub-task 133 : : 134 : : //! Output progress report to screen 135 : : //! \param[in] print Pretty printer object to use for printing progress 136 : : //! \details This output contains a status on each of the multiple sub-task 137 : : //! counters as they all work towards their respective maxima. 138 : : //! \see Print::progress() 139 : 727 : void report( const Print& print ) { 140 [ + + ]: 727 : if (m_feedback) 141 : 230 : print.progress< N >( m_prefix, m_done, m_max, m_progress_size ); 142 : 727 : } 143 : : }; 144 : : 145 : : } // tk:: 146 : : 147 : : #endif // Progress_h