MySQL  8.0.27
Source Code Documentation
timing_iterator.h
Go to the documentation of this file.
1 #ifndef SQL_TIMING_ITERATOR_H_
2 #define SQL_TIMING_ITERATOR_H_
3 
4 /* Copyright (c) 2019, 2021, Oracle and/or its affiliates.
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License, version 2.0,
8  as published by the Free Software Foundation.
9 
10  This program is also distributed with certain software (including
11  but not limited to OpenSSL) that is licensed under separate terms,
12  as designated in a particular file or component or in included license
13  documentation. The authors of MySQL hereby grant you an additional
14  permission to link the program and your derivative works with the
15  separately licensed software that they have included with MySQL.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License, version 2.0, for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
25 
26 #include <inttypes.h>
27 #include <stdio.h>
28 #include <chrono>
29 
30 #include "my_alloc.h"
31 #include "sql/row_iterator.h"
32 #include "sql/sql_class.h"
33 #include "sql/sql_lex.h"
34 
35 /**
36  An iterator template that wraps a RowIterator, such that all calls to Init()
37  and Read() are timed (all others are passed through unchanged, and possibly
38  even inlined, since all RowIterator implementations are final). This is used
39  for EXPLAIN ANALYZE.
40 
41  If RealIterator has a type called keeps_own_timing (no matter what it
42  is), it must contain num_rows() and num_init_calls() accessors that override
43  the number of Init() calls that is counted. This is useful for
44  MaterializeIterator, where most Init() calls don't actually cause a
45  rematerialization and are effectively free.
46 
47  See also NewIterator, below.
48  */
49 template <class RealIterator>
50 class TimingIterator final : public RowIterator {
51  public:
52  template <class... Args>
53  TimingIterator(THD *thd, Args &&... args)
54  : RowIterator(thd), m_iterator(thd, std::forward<Args>(args)...) {}
55 
56  bool Init() override;
57  int Read() override;
58  void SetNullRowFlag(bool is_null_row) override {
59  m_iterator.SetNullRowFlag(is_null_row);
60  }
61  void UnlockRow() override { m_iterator.UnlockRow(); }
62  void StartPSIBatchMode() override { m_iterator.StartPSIBatchMode(); }
63  void EndPSIBatchModeIfStarted() override {
64  m_iterator.EndPSIBatchModeIfStarted();
65  }
66 
67  std::string TimingString() const override;
68 
69  RowIterator *real_iterator() override { return &m_iterator; }
70  const RowIterator *real_iterator() const override { return &m_iterator; }
71 
72  private:
73  // To avoid a lot of repetitive writing.
74  using steady_clock = std::chrono::steady_clock;
75  template <class T>
76  using duration = std::chrono::duration<T>;
77 
78  steady_clock::time_point now() const {
79 #if defined(__linux__)
80  // Work around very slow libstdc++ implementations of std::chrono
81  // (those compiled with _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL).
82  timespec tp;
83  clock_gettime(CLOCK_MONOTONIC, &tp);
84  return steady_clock::time_point(
85  steady_clock::duration(std::chrono::seconds(tp.tv_sec) +
86  std::chrono::nanoseconds(tp.tv_nsec)));
87 #else
88  return steady_clock::now();
89 #endif
90  }
91 
92  // These are at the same offset for all TimingIterator specializations,
93  // in the hope that the linker can manage to fold all the TimingString()
94  // implementations into one.
95  uint64_t m_num_rows = 0;
96  uint64_t m_num_init_calls = 0;
97  steady_clock::time_point::duration m_time_spent_in_first_row{0};
98  steady_clock::time_point::duration m_time_spent_in_other_rows{0};
100 
101  RealIterator m_iterator;
102 };
103 
104 template <class RealIterator>
106  ++m_num_init_calls;
107  steady_clock::time_point start = now();
108  bool err = m_iterator.Init();
109  steady_clock::time_point end = now();
110  m_time_spent_in_first_row += end - start;
111  m_first_row = true;
112  return err;
113 }
114 
115 template <class RealIterator>
117  steady_clock::time_point start = now();
118  int err = m_iterator.Read();
119  steady_clock::time_point end = now();
120  if (m_first_row) {
121  m_time_spent_in_first_row += end - start;
122  m_first_row = false;
123  } else {
124  m_time_spent_in_other_rows += end - start;
125  }
126  if (err == 0) {
127  ++m_num_rows;
128  }
129  return err;
130 }
131 
132 // In the default implementation, just return default_num_init_calls.
133 template <class RealIterator, class = void>
135  inline uint64_t num_init_calls(const RealIterator &,
136  uint64_t default_num_init_calls) const {
137  return default_num_init_calls;
138  }
139  inline uint64_t num_rows(const RealIterator &,
140  uint64_t default_num_rows) const {
141  return default_num_rows;
142  }
143 };
144 
145 // However, if RealIterator::keeps_own_timing exists, call its
146 // num_init_calls(). (If it does not exist, this template is not considered
147 // due to SFINAE.)
148 template <class RealIterator>
149 struct GetTimingData<RealIterator, typename RealIterator::keeps_own_timing> {
150  inline uint64_t num_init_calls(const RealIterator &iterator, uint64_t) const {
151  return iterator.num_init_calls();
152  }
153  inline uint64_t num_rows(const RealIterator &iterator, uint64_t) const {
154  return iterator.num_rows();
155  }
156 };
157 
158 template <class RealIterator>
160  double first_row_ms =
161  duration<double>(m_time_spent_in_first_row).count() * 1e3;
162  double last_row_ms =
163  duration<double>(m_time_spent_in_first_row + m_time_spent_in_other_rows)
164  .count() *
165  1e3;
166  char buf[1024];
167  GetTimingData<RealIterator> timing_data;
168  const uint64_t num_init_calls =
169  timing_data.num_init_calls(m_iterator, m_num_init_calls);
170  const uint64_t num_rows = timing_data.num_rows(m_iterator, m_num_rows);
171  if (num_init_calls == 0) {
172  snprintf(buf, sizeof(buf), "(never executed)");
173  } else {
174  snprintf(buf, sizeof(buf),
175  "(actual time=%.3f..%.3f rows=%lld loops=%" PRIu64 ")",
176  first_row_ms / num_init_calls, last_row_ms / num_init_calls,
177  llrintf(static_cast<double>(num_rows) / num_init_calls),
178  num_init_calls);
179  }
180  return buf;
181 }
182 
183 // Allocates a new iterator on the given THD's MEM_ROOT. The MEM_ROOT must live
184 // for at least as long as the iterator does.
185 //
186 // If we are in EXPLAIN ANALYZE, the iterator is wrapped in a TimingIterator<T>,
187 // so that it collects timing information. For this reason, nearly all
188 // instantiations of iterators should go through this function.
189 
190 template <class RealIterator, class... Args>
192  if (thd->lex->is_explain_analyze) {
194  new (thd->mem_root)
195  TimingIterator<RealIterator>(thd, std::forward<Args>(args)...));
196  } else {
198  new (thd->mem_root) RealIterator(thd, std::forward<Args>(args)...));
199  }
200 }
201 
202 #endif // SQL_TIMING_ITERATOR_H_
MEM_ROOT * mem_root
Definition: sql_class.h:243
A context for reading through a single table using a chosen access method: index read,...
Definition: row_iterator.h:60
THD * thd() const
Definition: row_iterator.h:190
For each client connection we create a separate thread with THD serving as a thread/connection descri...
Definition: sql_class.h:821
LEX * lex
Definition: sql_class.h:879
An iterator template that wraps a RowIterator, such that all calls to Init() and Read() are timed (al...
Definition: timing_iterator.h:50
uint64_t m_num_rows
Definition: timing_iterator.h:95
std::chrono::duration< T > duration
Definition: timing_iterator.h:76
const RowIterator * real_iterator() const override
Definition: timing_iterator.h:70
RealIterator m_iterator
Definition: timing_iterator.h:101
RowIterator * real_iterator() override
If this iterator is wrapping a different iterator (e.g.
Definition: timing_iterator.h:69
int Read() override
Read a single row.
Definition: timing_iterator.h:116
bool Init() override
Initialize or reinitialize the iterator.
Definition: timing_iterator.h:105
steady_clock::time_point::duration m_time_spent_in_first_row
Definition: timing_iterator.h:97
void EndPSIBatchModeIfStarted() override
Ends performance schema batch mode, if started.
Definition: timing_iterator.h:63
std::chrono::steady_clock steady_clock
Definition: timing_iterator.h:74
uint64_t m_num_init_calls
Definition: timing_iterator.h:96
std::string TimingString() const override
Definition: timing_iterator.h:159
steady_clock::time_point::duration m_time_spent_in_other_rows
Definition: timing_iterator.h:98
steady_clock::time_point now() const
Definition: timing_iterator.h:78
void StartPSIBatchMode() override
Start performance schema batch mode, if supported (otherwise ignored).
Definition: timing_iterator.h:62
void UnlockRow() override
Definition: timing_iterator.h:61
void SetNullRowFlag(bool is_null_row) override
Mark the current row buffer as containing a NULL row or not, so that if you read from it and the flag...
Definition: timing_iterator.h:58
bool m_first_row
Definition: timing_iterator.h:99
TimingIterator(THD *thd, Args &&... args)
Definition: timing_iterator.h:53
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:165
This file follows Google coding style, except for the name MEM_ROOT (which is kept for historical rea...
std::unique_ptr< T, Destroy_only< T > > unique_ptr_destroy_only
std::unique_ptr, but only destroying.
Definition: my_alloc.h:464
Definition: buf0block_hint.cc:29
static Value err()
Create a Value object that represents an error condition.
Definition: json_binary.cc:908
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:191
Definition: varlen_sort.h:183
uint64_t num_init_calls(const RealIterator &iterator, uint64_t) const
Definition: timing_iterator.h:150
uint64_t num_rows(const RealIterator &iterator, uint64_t) const
Definition: timing_iterator.h:153
Definition: timing_iterator.h:134
uint64_t num_init_calls(const RealIterator &, uint64_t default_num_init_calls) const
Definition: timing_iterator.h:135
uint64_t num_rows(const RealIterator &, uint64_t default_num_rows) const
Definition: timing_iterator.h:139
bool is_explain_analyze
Definition: sql_lex.h:3683
double seconds()
Definition: task.cc:309
unique_ptr_destroy_only< RowIterator > NewIterator(THD *thd, Args &&... args)
Definition: timing_iterator.h:191