1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// *****************************************************************************
/*!
  \file      src/Base/Progress.hpp
  \copyright 2012-2015 J. Bakosi,
             2016-2018 Los Alamos National Security, LLC.,
             2019-2021 Triad National Security, LLC.,
             2022-2025 J. Bakosi
             All rights reserved. See the LICENSE file for details.
  \brief     Simple progress indicator
  \details   Simple progress indicator.
*/
// *****************************************************************************
#ifndef Progress_h
#define Progress_h

#include <array><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <functional><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include "TaggedTuple.hpp"
#include "Print.hpp"

namespace tk {

//! Simple progress class for outputting progress indicators during a task
//! \details This is a helper class to abstract away the details of using
//!   Print::progress() used to output progress reports to the screen during
//!   a task consisting of multiple sub-tasks happening at the same time. The
//!   template argument is a compile-time integer which is the number of
//!   independent sub-tasks the progress indicator receives messages for and
//!   counts them independently toward multiple maxima.
template< std::size_t N >
class Progress {

  public:
    //! Constructor
    //! \param[in] feedback Whether to send sub-task feedback to host    
    //! \param[in] prefix Strings to output prefixing the progress report
    //! \param[in] legend Legend for each prefix to output at start
    //! \param[in] max Array of integers equaling the max number of items to be
    //!   expected per sub-task
    explicit Progress( bool feedback,
                       const std::array< std::string, N >& prefix,
                       const std::array< std::string, N >& legend,
                       std::array< int, N >&& max = std::array< int, N >() )
    : m_feedback( feedback ),
      m_prefix( std::move(prefix) ),
      m_legend( std::move(legend) ),
      m_finished( false ),
      m_progress_size( 0 ),
      m_max( std::move(max) )
    {
      m_done.fill( 0 ); 
    }

   //! Start counting sub-tasks outputting an initial task message
   //! \param[in] print Pretty printer object to use for printing progress
   //! \param[in] msg Message to output to screen. This message should be
   //!   descriptive of all the sub-tasks we are responsible for. I.e., this
   //!   is usually a list of multiple sub-tasks happening at the same time.
   //!   Appending to msg we also output the legend of subtasks in parentheses.
   void start( const Print& print, const std::string& msg ) {
     std::string legend;
     if (m_feedback) {
       legend.append( " (" );
       for (const auto& l : m_legend) legend.append( l + ", " );
       legend.pop_back();
       legend.pop_back();
       legend.append( ")" );
     }
     legend.append( " ..." );
     print.diagstart( msg + legend );
     m_progress_size = 0;
   }

   //! \brief Start counting sub-tasks outputting an initial task message and set
   //!   max number of items to be expected per sub-task
   //! \param[in] print Pretty printer object to use for printing progress
   //! \param[in] msg Message to output to screen. This message should be
   //!   descriptive of all the sub-tasks we are responsible for. I.e., this
   //!   is usually a list of multiple sub-tasks happening at the same time.
   //! \param[in] max Array of integers equaling the max number of items to be
   //!   expected per sub-task
   //! \details This function can be used to do the same as start( msg ) and
   //!   update/reset the max number of items per sub-task in case they are not
   //!   all yet available when the constructor is called.
   void start( const Print& print,
               const std::string& msg,
               std::array< int, N >&& max )
   {
     m_max = std::move(max);
     start( print, msg );
   }

   //! Receive an update to a sub-task counter and update progress report
   //! \param[in] print Pretty printer object to use for printing progress
   //! \details The template argument indexes the sub-task. A compile-time
   //!   assert emits an error in case it is out of bounds.
   template< std::size_t i > void inc( const Print& print ) {
     static_assert( i < N, "Indexing out of bounds" );
     ++m_done[i];
     if (!m_finished) report( print );
   }

   //! Finish progress report updating it one last time
   //! \param[in] print Pretty printer object to use for printing progress
   //! \details When this function is called, all sub-tasks are assumed to be
   //!   finished, i.e., assumed to have reached their respective maximum
   //!   values. Thus we update our 'done' array to be equal to 'max' and output
   //!   the progress report one final time before outputting 'done'. When this
   //!   function is called it is possible that not all sub-task counters have
   //!   reached their maximum, which can happen if the final reduction (if
   //!   exists), signaling the absolute end of a task (consisting of multiple
   //!   sub-tasks we count counters for), is scheduled before (or is faster)
   //!   than as the individual sub-task counting messages arrive. Even if that
   //!   is the case, this call "officially" finishes all sub-tasks, and outputs
   //!   the progress report using the max values for all sub-tasks to leave a
   //!   consistent screen output finishing the task.
   void end( const Print& print ) {
     m_finished = true;
     m_done = m_max;
     report( print );
     print.diagend( "done" );
   }

  private:
    bool m_feedback;            //!< Whether to send sub-task feedback to host
    const std::array< std::string, N > m_prefix;        //!< Sub-task prefixes
    const std::array< std::string, N > m_legend;        //!< Sub-task legend
    bool m_finished;            //!< Whether task has finished
    std::size_t m_progress_size;//!< Size of previous progress report
    std::array< int, N > m_max; //!< Max number of items per sub-task
    std::array< int, N > m_done;//!< Number of items done per sub-task

   //! Output progress report to screen
   //! \param[in] print Pretty printer object to use for printing progress
   //! \details This output contains a status on each of the multiple sub-task
   //!   counters as they all work towards their respective maxima.
   //! \see Print::progress()
   void report( const Print& print ) {
     if (m_feedback)
       print.progress< N >( m_prefix, m_done, m_max, m_progress_size );
   }
};

} // tk::

#endif // Progress_h