Coverage Report

Created: 2024-06-28 06:08

/src/botan/src/lib/utils/timer.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 2018 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#include <botan/internal/timer.h>
8
9
#include <botan/internal/os_utils.h>
10
#include <algorithm>
11
#include <iomanip>
12
#include <sstream>
13
14
namespace Botan {
15
16
namespace {
17
18
0
std::string format_timer_name(std::string_view name, std::string_view provider) {
19
0
   if(provider.empty() || provider == "base") {
20
0
      return std::string(name);
21
0
   }
22
23
0
   std::ostringstream out;
24
0
   out << name << " [" << provider << "]";
25
0
   return out.str();
26
0
}
27
28
}  // namespace
29
30
Timer::Timer(std::string_view name,
31
             std::string_view provider,
32
             std::string_view doing,
33
             uint64_t event_mult,
34
             size_t buf_size,
35
             double clock_cycle_ratio,
36
             uint64_t clock_speed) :
37
      m_name(format_timer_name(name, provider)),
38
      m_doing(doing),
39
      m_buf_size(buf_size),
40
      m_event_mult(event_mult),
41
      m_clock_cycle_ratio(clock_cycle_ratio),
42
0
      m_clock_speed(clock_speed) {}
43
44
0
void Timer::start() {
45
0
   stop();
46
0
   m_timer_start = OS::get_system_timestamp_ns();
47
0
   m_cpu_cycles_start = OS::get_cpu_cycle_counter();
48
0
}
49
50
0
void Timer::stop() {
51
0
   if(m_timer_start) {
52
0
      if(m_cpu_cycles_start != 0) {
53
0
         const uint64_t cycles_taken = OS::get_cpu_cycle_counter() - m_cpu_cycles_start;
54
0
         if(cycles_taken > 0) {
55
0
            m_cpu_cycles_used += static_cast<size_t>(cycles_taken * m_clock_cycle_ratio);
56
0
         }
57
0
      }
58
59
0
      const uint64_t now = OS::get_system_timestamp_ns();
60
61
0
      if(now > m_timer_start) {
62
0
         const uint64_t dur = now - m_timer_start;
63
64
0
         m_time_used += dur;
65
66
0
         if(m_event_count == 0) {
67
0
            m_min_time = m_max_time = dur;
68
0
         } else {
69
0
            m_max_time = std::max(m_max_time, dur);
70
0
            m_min_time = std::min(m_min_time, dur);
71
0
         }
72
0
      }
73
74
0
      m_timer_start = 0;
75
0
      ++m_event_count;
76
0
   }
77
0
}
78
79
0
bool Timer::operator<(const Timer& other) const {
80
0
   if(this->doing() != other.doing()) {
81
0
      return (this->doing() < other.doing());
82
0
   }
83
84
0
   return (this->get_name() < other.get_name());
85
0
}
86
87
0
std::string Timer::to_string() const {
88
0
   if(!m_custom_msg.empty()) {
89
0
      return m_custom_msg;
90
0
   } else if(this->buf_size() == 0) {
91
0
      return result_string_ops();
92
0
   } else {
93
0
      return result_string_bps();
94
0
   }
95
0
}
96
97
0
std::string Timer::result_string_bps() const {
98
0
   const size_t MiB = 1024 * 1024;
99
100
0
   const double MiB_total = static_cast<double>(events()) / MiB;
101
0
   const double MiB_per_sec = MiB_total / seconds();
102
103
0
   std::ostringstream oss;
104
0
   oss << get_name();
105
106
0
   if(!doing().empty()) {
107
0
      oss << " " << doing();
108
0
   }
109
110
0
   if(buf_size() > 0) {
111
0
      oss << " buffer size " << buf_size() << " bytes:";
112
0
   }
113
114
0
   if(events() == 0) {
115
0
      oss << " "
116
0
          << "N/A";
117
0
   } else {
118
0
      oss << " " << std::fixed << std::setprecision(3) << MiB_per_sec << " MiB/sec";
119
0
   }
120
121
0
   if(cycles_consumed() != 0) {
122
0
      const double cycles_per_byte = static_cast<double>(cycles_consumed()) / events();
123
0
      oss << " " << std::fixed << std::setprecision(2) << cycles_per_byte << " cycles/byte";
124
0
   }
125
126
0
   oss << " (" << MiB_total << " MiB in " << milliseconds() << " ms)\n";
127
128
0
   return oss.str();
129
0
}
130
131
0
std::string Timer::result_string_ops() const {
132
0
   std::ostringstream oss;
133
134
0
   oss << get_name() << " ";
135
136
0
   if(events() == 0) {
137
0
      oss << "no events\n";
138
0
   } else {
139
0
      oss << static_cast<uint64_t>(events_per_second()) << ' ' << doing() << "/sec; " << std::setprecision(2)
140
0
          << std::fixed << ms_per_event() << " ms/op";
141
142
0
      if(cycles_consumed() != 0) {
143
0
         const double cycles_per_op = static_cast<double>(cycles_consumed()) / events();
144
0
         const int precision = (cycles_per_op < 10000) ? 2 : 0;
145
0
         oss << " " << std::fixed << std::setprecision(precision) << cycles_per_op << " cycles/op";
146
0
      }
147
148
0
      oss << " (" << events() << " " << (events() == 1 ? "op" : "ops") << " in " << milliseconds() << " ms)\n";
149
0
   }
150
151
0
   return oss.str();
152
0
}
153
154
}  // namespace Botan