LCOV - code coverage report
Current view: top level - utilities/include/mcrl2/utilities - execution_timer.h (source / functions) Hit Total Coverage
Test: mcrl2_coverage.info.cleaned Lines: 25 53 47.2 %
Date: 2024-04-26 03:18:02 Functions: 5 7 71.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Author(s): Jeroen Keiren
       2             : // Copyright: see the accompanying file COPYING or copy at
       3             : // https://github.com/mCRL2org/mCRL2/blob/master/COPYING
       4             : //
       5             : // Distributed under the Boost Software License, Version 1.0.
       6             : // (See accompanying file LICENSE_1_0.txt or copy at
       7             : // http://www.boost.org/LICENSE_1_0.txt)
       8             : //
       9             : /// \file mcrl2/utilities/execution_timer.h
      10             : /// \brief Class to obtain running times of code.
      11             : 
      12             : #ifndef MCRL2_UTILITIES_EXECUTION_TIMER_H
      13             : #define MCRL2_UTILITIES_EXECUTION_TIMER_H
      14             : 
      15             : #include "mcrl2/utilities/exception.h"
      16             : 
      17             : #include <chrono>
      18             : #include <fstream>
      19             : #include <map>
      20             : #include <string>
      21             : 
      22             : namespace mcrl2
      23             : {
      24             : 
      25             : namespace utilities
      26             : {
      27             : 
      28             : /// \brief Simple timer to time the CPU time used by a piece of code.
      29             : ///
      30             : /// Example usage:
      31             : /// execution_timer timer("test_tool", "/path/to/file")
      32             : /// timer.start("hint")
      33             : /// ... (execute some code here) ...
      34             : /// timer.finish("hint")
      35             : /// timer.report()
      36             : ///
      37             : /// This will output the following to the file "/path/to/file", or
      38             : /// standard error if filename is empty, assuming that the time between
      39             : /// start and finish is n seconds (with precision of 2 decimal places).
      40             : /// - tool: test_tool
      41             : ///   timing:
      42             : ///     hint: n
      43             : ///
      44             : /// Note that this is an output format that can immediately be parsed using
      45             : /// YAML (http://www.yaml.org/)
      46             : class execution_timer
      47             : {
      48             :   protected:
      49             : 
      50             :     /// \brief Pair of start and finish times
      51             :     struct timing
      52             :     {
      53             :       std::chrono::steady_clock::time_point start;      
      54             :       std::chrono::steady_clock::time_point finish;
      55             : 
      56             :       clock_t start_user;      
      57             :       clock_t finish_user;
      58             : 
      59          20 :       timing() :
      60          20 :         start(),
      61          20 :         finish()
      62          20 :       {}
      63             :     };
      64             : 
      65             :     std::string m_tool_name; //!< name of the tool we are timing
      66             :     std::string m_filename; //!< name of the file to write timings to
      67             :     std::map<std::string, timing> m_timings; //!< collection of timings
      68             : 
      69             :     /// \brief Write the report to an output stream.
      70             :     /// \param[in] s The output stream to which the report is written.
      71           0 :     void write_report(std::ostream& s)
      72             :     {
      73           0 :       std::ios::fmtflags oldflags = s.setf(std::ios::fixed, std::ios::floatfield);
      74           0 :       s.precision(3);
      75             : 
      76           0 :       s << "- tool: " << m_tool_name << std::endl
      77           0 :         << "  timing:" << std::endl;
      78             : 
      79           0 :       for (std::map<std::string, timing>::const_iterator i = m_timings.begin(); i != m_timings.end(); ++i)
      80             :       {
      81           0 :         if (i->second.finish == std::chrono::steady_clock::time_point())
      82             :         {
      83           0 :           s << "    " << i->first << ": did not finish. " << std::endl;
      84             :         }
      85           0 :         else if (i->second.start > i->second.finish)
      86             :         {
      87           0 :           throw mcrl2::runtime_error("Start of " + i->first + " occurred after finish.");
      88             :         }
      89             :         else
      90             :         {
      91           0 :           s << "    " << i->first << ": "
      92           0 :             << std::chrono::duration_cast<std::chrono::milliseconds>(i->second.finish - i->second.start).count() / 1000.0
      93           0 :             << "s (user: " << static_cast<double>(i->second.finish_user - i->second.start_user) / CLOCKS_PER_SEC << "s)"
      94           0 :             << std::endl;
      95             :         }
      96             :       }
      97           0 :       s.flags(oldflags);
      98           0 :     }
      99             : 
     100             :   public:
     101             : 
     102             :     /// \brief Constructor of a simple execution timer
     103             :     /// \param[in] tool_name Name of the tool that does the measurements
     104             :     /// \param[in] filename Name of the file to which the measurements are written
     105          13 :     execution_timer(const std::string& tool_name = "", std::string const& filename = "") :
     106          13 :       m_tool_name(tool_name),
     107          13 :       m_filename(filename)
     108          13 :     {}
     109             : 
     110             :     /// \brief Destructor
     111          13 :     ~execution_timer()
     112          13 :     {}
     113             : 
     114             :     /// \brief Start measurement with a hint
     115             :     /// \param[in] timing_name Name of the measurement being started
     116             :     /// \pre No start(timing_name) has occurred before
     117             :     /// \post The current time has been recorded as starting time of timing_name
     118          20 :     void start(const std::string& timing_name)
     119             :     {
     120          20 :       std::map<std::string, timing>::iterator t = m_timings.lower_bound(timing_name);
     121          20 :       if (t != m_timings.end() && t->first == timing_name)
     122             :       {
     123           0 :         throw mcrl2::runtime_error("Starting already known timing '" + timing_name + "'. This causes unreliable results.");
     124             :       }
     125          20 :       t = m_timings.insert(t, make_pair(timing_name, timing()));
     126             : 
     127          20 :       t->second.start = std::chrono::steady_clock::now();
     128          20 :       t->second.start_user = clock();
     129          20 :     }
     130             : 
     131             :     /// \brief Finish a measurement with a hint
     132             :     /// \param[in] timing_name Name of the measurment being finished
     133             :     /// \pre A start(timing_name) was executed before
     134             :     /// \post The current time has been recorded as end time of timing_name
     135          20 :     void finish(const std::string& timing_name)
     136             :     {
     137          20 :       std::chrono::steady_clock::time_point finish = std::chrono::steady_clock::now();
     138          20 :       const std::map<std::string, timing>::iterator t = m_timings.find(timing_name);
     139          20 :       if (t == m_timings.end())
     140             :       {
     141           0 :         throw mcrl2::runtime_error("Finishing timing '" + timing_name + "' that was not started.");
     142             :       }
     143          20 :       if (std::chrono::steady_clock::time_point() != t->second.finish)
     144             :       {
     145           0 :         throw mcrl2::runtime_error("Finishing timing '" + timing_name + "' for the second time.");
     146             :       }
     147             : 
     148          20 :       t->second.finish = finish;
     149          20 :       t->second.finish_user = clock();
     150          20 :     }
     151             : 
     152             :     /// \brief Write all timing information that has been recorded.
     153             :     ///
     154             :     /// Timing information is written to the filename that was provided in
     155             :     /// the constructor. If no filename was provided (i.e. the filename is
     156             :     /// empty) the information is written to standard error.
     157             :     /// The output is in YAML compatible format.
     158           0 :     void report()
     159             :     {
     160           0 :       if (m_filename.empty())
     161             :       {
     162           0 :         write_report(std::cerr);
     163             :       }
     164             :       else
     165             :       {
     166           0 :         std::ofstream out;
     167           0 :         out.open(m_filename.c_str(), std::ios::app);
     168           0 :         write_report(out);
     169           0 :         out.close();
     170           0 :       }
     171           0 :     }
     172             : 
     173             : };
     174             : 
     175             : } // namespace utilities
     176             : 
     177             : } // namespace mcrl2
     178             : 
     179             : #endif // MCRL2_UTILITIES_EXECUTION_TIMER_H

Generated by: LCOV version 1.14