MySQL 9.3.0
Source Code Documentation
profiling.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018, 2025, Oracle and/or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is designed to work with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have either included with
14 * the program or referenced in the documentation.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
19 * the GNU General Public License, version 2.0, for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26#ifndef MYSQLSHDK_LIBS_UTILS_PROFILING_H_
27#define MYSQLSHDK_LIBS_UTILS_PROFILING_H_
28
29#include <chrono>
30#include <functional>
31#include <iostream>
32#include <list>
33#include <map>
34#include <mutex>
35#include <string>
36#include <thread>
37#include <utility>
38#include <vector>
39
40// #include "mysqlshdk/libs/utils/utils_general.h"
41
42namespace shcore {
43namespace utils {
44
45class Duration {
46 public:
47 Duration() = default;
48
49 Duration(const Duration &) = default;
50 Duration(Duration &&) = default;
51
52 Duration &operator=(const Duration &) = default;
53 Duration &operator=(Duration &&) = default;
54
55 virtual ~Duration() = default;
56
57 void start() { m_start = std::chrono::high_resolution_clock::now(); }
58
59 void finish() { m_finish = std::chrono::high_resolution_clock::now(); }
60
61 std::chrono::high_resolution_clock::duration elapsed() const {
62 return m_finish - m_start;
63 }
64
65 uint64_t nanoseconds_elapsed() const {
66 return std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed())
67 .count();
68 }
69
70 double milliseconds_elapsed() const {
71 return nanoseconds_elapsed() / 1000000.0;
72 }
73
74 double seconds_elapsed() const {
75 return nanoseconds_elapsed() / 1000000000.0;
76 }
77
78 private:
79 std::chrono::high_resolution_clock::time_point m_start;
80 std::chrono::high_resolution_clock::time_point m_finish;
81};
82
84 public:
86 _trace_points.reserve(32);
87 _nesting_levels.reserve(32);
88 }
89
90 inline void reserve(size_t space) { _trace_points.reserve(space); }
91
92 inline void stage_begin(const char *note) {
93 _trace_points.emplace_back(note, _depth).start();
94 _nesting_levels.emplace_back(_trace_points.size() - 1);
95 ++_depth;
96 }
97
98 inline void stage_end() {
99 size_t stage = _nesting_levels.back();
100 _nesting_levels.pop_back();
101 --_depth;
102 _trace_points.at(stage).finish();
103 }
104
105 uint64_t total_nanoseconds_elapsed() const {
106 auto dur = std::chrono::high_resolution_clock::duration::zero();
107 for (const auto &tp : _trace_points) {
108 if (tp.depth == 0) dur += tp.elapsed();
109 }
110 return std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count();
111 }
112
114 return total_nanoseconds_elapsed() / 1000000.0;
115 }
116
117 double total_seconds_elapsed() const {
118 return total_nanoseconds_elapsed() / 1000000000.0;
119 }
120
121 public:
122 struct Trace_point : public Duration {
123 char note[33];
124 int depth;
125
126 Trace_point(const char *n, int d) : depth(d) {
127 snprintf(note, sizeof(note), "%s", n);
128 }
129 };
130
131 const std::vector<Trace_point> &trace_points() const { return _trace_points; }
132
133 private:
134 std::vector<Trace_point> _trace_points;
135 std::vector<size_t> _nesting_levels;
136 int _depth = 0;
137};
138
139/**
140 * This class keeps track execution time on specifics blocks of code
141 * during a complete session. A session is defined by the time when the
142 * global profiler is enabled and the time is finished.
143 *
144 * The execution time is recorded by thread/stage groups.
145 *
146 * This class is NOT intended to be used (instantiated) within the shell
147 * functionality, but to be used as a global profiler which will record
148 * execution time associated to specific IDs and then print accumulated
149 * statistics.
150 *
151 * Use it throught the following functions in the profiling namespace:
152 *
153 * - activate
154 * - deactivate
155 * - stage_begin
156 * - stage_end
157 */
159 public:
161 void stage_begin(const std::string &id) {
162 std::lock_guard<std::mutex> lock(m_mutex);
163 m_time_profilers[std::this_thread::get_id()][id].stage_begin(id.c_str());
164 }
165
166 void stage_end(const std::string &id) {
167 std::lock_guard<std::mutex> lock(m_mutex);
168 m_time_profilers.at(std::this_thread::get_id()).at(id).stage_end();
169 }
170
171 void print_stats();
172
173 void reset();
174
175 using Time_profilers = std::map<std::string, Profile_timer>;
176
177 private:
178 std::mutex m_mutex;
179 std::map<std::thread::id, Time_profilers> m_time_profilers;
180};
181
182} // namespace utils
183
184/**
185 * This namespace provides the functions required to perform profiling
186 * of specific sections of code.
187 *
188 * TO ACTIVATE THE PROFILER
189 * ------------------------
190 * Call the following functions to activate/deactivate it as needed:
191 * - mysqlshdk::profiling::activate();
192 * - mysqlshdk::profiling::deactivate();
193 *
194 * Or do as follows to ensure it is active within a specific context:
195 *
196 * mysqlshdk::profiling::activate();
197 * auto finally =
198 * shcore::on_leave_scope([]() { mysqlshdk::profiling::deactivate(); });
199 *
200 * TO ADD A MEASURING POINT WITHIN A THREAD
201 * ----------------------------------------
202 * Call the following functions to measure the time spent between them:
203 *
204 * - mysqlshdk::profiling::stage_begin("<MEASURE ID>");
205 * - mysqlshdk::profiling::stage_end("<MEASURE ID>");
206 *
207 * "<MEASURE ID>": Text to identify the context being measured.
208 *
209 * Make sure the measure ID passed to both functions is the same. It will
210 * record a the number of milliseconds spend between both calls for each time
211 * the code is hit while the profiling is active.
212 *
213 * To measure the time within a specific scope you can also use:
214 *
215 * mysqlshdk::profiling::stage_begin("<MEASURE ID>");
216 * shcore::on_leave_scope end_stage(
217 * []() { mysqlshdk::profiling::stage_end("<MEASURE ID>"); });
218 *
219 * You can add as many measure points as needed.
220 */
221namespace profiling {
223
224void activate(bool trace_total = true);
225void deactivate(bool trace_total = true);
226
227inline void print_stats() {
229}
230
231inline void reset() {
233}
234
235inline void stage_begin(const std::string &id) {
237}
238
239inline void stage_end(const std::string &id) {
241}
242
243} // namespace profiling
244
245} // namespace shcore
246
247#endif // MYSQLSHDK_LIBS_UTILS_PROFILING_H_
Definition: profiling.h:45
void start()
Definition: profiling.h:57
uint64_t nanoseconds_elapsed() const
Definition: profiling.h:65
Duration & operator=(const Duration &)=default
double seconds_elapsed() const
Definition: profiling.h:74
virtual ~Duration()=default
std::chrono::high_resolution_clock::time_point m_start
Definition: profiling.h:79
double milliseconds_elapsed() const
Definition: profiling.h:70
void finish()
Definition: profiling.h:59
Duration(Duration &&)=default
std::chrono::high_resolution_clock::duration elapsed() const
Definition: profiling.h:61
Duration & operator=(Duration &&)=default
std::chrono::high_resolution_clock::time_point m_finish
Definition: profiling.h:80
Duration(const Duration &)=default
This class keeps track execution time on specifics blocks of code during a complete session.
Definition: profiling.h:158
std::map< std::string, Profile_timer > Time_profilers
Definition: profiling.h:175
std::map< std::thread::id, Time_profilers > m_time_profilers
Definition: profiling.h:179
std::mutex m_mutex
Definition: profiling.h:178
~Global_profiler()
Definition: profiling.h:160
void print_stats()
Definition: profiling.cc:36
void stage_end(const std::string &id)
Definition: profiling.h:166
void stage_begin(const std::string &id)
Definition: profiling.h:161
void reset()
Definition: profiling.cc:79
Definition: profiling.h:83
const std::vector< Trace_point > & trace_points() const
Definition: profiling.h:131
void reserve(size_t space)
Definition: profiling.h:90
void stage_end()
Definition: profiling.h:98
uint64_t total_nanoseconds_elapsed() const
Definition: profiling.h:105
double total_milliseconds_elapsed() const
Definition: profiling.h:113
double total_seconds_elapsed() const
Definition: profiling.h:117
std::vector< Trace_point > _trace_points
Definition: profiling.h:134
void stage_begin(const char *note)
Definition: profiling.h:92
Profile_timer()
Definition: profiling.h:85
int _depth
Definition: profiling.h:136
std::vector< size_t > _nesting_levels
Definition: profiling.h:135
void stage_begin(const std::string &id)
Definition: profiling.h:235
shcore::utils::Global_profiler * g_active_profiler
Definition: profiling.cc:87
void stage_end(const std::string &id)
Definition: profiling.h:239
void print_stats()
Definition: profiling.h:227
void reset()
Definition: profiling.h:231
void deactivate(bool trace_total)
Definition: profiling.cc:99
void activate(bool trace_total)
Definition: profiling.cc:89
Definition: file_system_exceptions.h:34
pid_type get_id()
Definition: process.h:48
static std::mutex lock
Definition: net_ns.cc:56
Trace_point(const char *n, int d)
Definition: profiling.h:126
int depth
Definition: profiling.h:124
char note[33]
Definition: profiling.h:123
unsigned long id[MAX_DEAD]
Definition: xcom_base.cc:510
int n
Definition: xcom_base.cc:509