MySQL  8.0.19
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, Oracle and/or its affiliates. All rights reserved.
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  See also NewIterator, below.
42  */
43 template <class RealIterator>
45  public:
46  template <class... Args>
47  TimingIterator(THD *thd, Args &&... args)
48  : RowIterator(thd), m_iterator(thd, std::forward<Args>(args)...) {}
49 
50  bool Init() override;
51  int Read() override;
52  void SetNullRowFlag(bool is_null_row) override {
53  m_iterator.SetNullRowFlag(is_null_row);
54  }
55  void UnlockRow() override { m_iterator.UnlockRow(); }
56  std::vector<Child> children() const override { return m_iterator.children(); }
57  std::vector<std::string> DebugString() const override {
58  return m_iterator.DebugString();
59  }
60  void StartPSIBatchMode() override { m_iterator.StartPSIBatchMode(); }
61  void EndPSIBatchModeIfStarted() override {
62  m_iterator.EndPSIBatchModeIfStarted();
63  }
64 
65  std::string TimingString() const override;
66 
67  RowIterator *real_iterator() override { return &m_iterator; }
68  const RowIterator *real_iterator() const override { return &m_iterator; }
69 
70  private:
71  // To avoid a lot of repetitive writing.
72  using steady_clock = std::chrono::steady_clock;
73  template <class T>
74  using duration = std::chrono::duration<T>;
75 
76  steady_clock::time_point now() const {
77 #ifdef __SUNPRO_CC
78  // This no-op cast works around an optimization bug in Developer Studio
79  // where it attempts to dereference an integral time value, leading to
80  // crashes.
81  return std::chrono::time_point_cast<std::chrono::nanoseconds>(
82  steady_clock::now());
83 #elif defined(__linux__)
84  // Work around very slow libstdc++ implementations of std::chrono
85  // (those compiled with _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL).
86  timespec tp;
87  clock_gettime(CLOCK_MONOTONIC, &tp);
88  return steady_clock::time_point(
89  steady_clock::duration(std::chrono::seconds(tp.tv_sec) +
90  std::chrono::nanoseconds(tp.tv_nsec)));
91 #else
92  return steady_clock::now();
93 #endif
94  }
95 
96  // These are at the same offset for all TimingIterator specializations,
97  // in the hope that the linker can manage to fold all the TimingString()
98  // implementations into one.
99  uint64_t m_num_rows = 0;
100  uint64_t m_num_init_calls = 0;
101  steady_clock::time_point::duration m_time_spent_in_first_row{0};
102  steady_clock::time_point::duration m_time_spent_in_other_rows{0};
104 
105  RealIterator m_iterator;
106 };
107 
108 template <class RealIterator>
110  ++m_num_init_calls;
111  steady_clock::time_point start = now();
112  bool err = m_iterator.Init();
113  steady_clock::time_point end = now();
114  m_time_spent_in_first_row += end - start;
115  m_first_row = true;
116  return err;
117 }
118 
119 template <class RealIterator>
121  steady_clock::time_point start = now();
122  int err = m_iterator.Read();
123  steady_clock::time_point end = now();
124  if (m_first_row) {
125  m_time_spent_in_first_row += end - start;
126  m_first_row = false;
127  } else {
128  m_time_spent_in_other_rows += end - start;
129  }
130  if (err == 0) {
131  ++m_num_rows;
132  }
133  return err;
134 }
135 
136 template <class RealIterator>
138  double first_row_ms =
139  duration<double>(m_time_spent_in_first_row).count() * 1e3;
140  double last_row_ms =
141  duration<double>(m_time_spent_in_first_row + m_time_spent_in_other_rows)
142  .count() *
143  1e3;
144  char buf[1024];
145  if (m_num_init_calls == 0) {
146  snprintf(buf, sizeof(buf), "(never executed)");
147  } else {
148  snprintf(buf, sizeof(buf),
149  "(actual time=%.3f..%.3f rows=%lld loops=%" PRIu64 ")",
150  first_row_ms / m_num_init_calls, last_row_ms / m_num_init_calls,
151  llrintf(static_cast<double>(m_num_rows) / m_num_init_calls),
152  m_num_init_calls);
153  }
154  return buf;
155 }
156 
157 // Allocates a new iterator on the given THD's MEM_ROOT. The MEM_ROOT must live
158 // for at least as long as the iterator does.
159 //
160 // If we are in EXPLAIN ANALYZE, the iterator is wrapped in a TimingIterator<T>,
161 // so that it collects timing information. For this reason, nearly all
162 // instantiations of iterators should go through this function.
163 
164 template <class RealIterator, class... Args>
166  if (thd->lex->is_explain_analyze) {
168  new (thd->mem_root)
169  TimingIterator<RealIterator>(thd, std::forward<Args>(args)...));
170  } else {
172  new (thd->mem_root) RealIterator(thd, std::forward<Args>(args)...));
173  }
174 }
175 
176 #endif // SQL_TIMING_ITERATOR_H_
sql_class.h
THD
Definition: sql_class.h:764
TimingIterator::UnlockRow
void UnlockRow() override
Definition: timing_iterator.h:55
TimingIterator::m_num_init_calls
uint64_t m_num_init_calls
Definition: timing_iterator.h:100
TimingIterator::now
steady_clock::time_point now() const
Definition: timing_iterator.h:76
sql_lex.h
row_iterator.h
THD::lex
LEX * lex
Definition: sql_class.h:824
TimingIterator::duration
std::chrono::duration< T > duration
Definition: timing_iterator.h:74
unique_ptr_destroy_only
std::unique_ptr< T, Destroy_only< T > > unique_ptr_destroy_only
std::unique_ptr, but only destroying.
Definition: my_alloc.h:408
TimingIterator::m_first_row
bool m_first_row
Definition: timing_iterator.h:103
TimingIterator::DebugString
std::vector< std::string > DebugString() const override
Returns a short string (used for EXPLAIN FORMAT=tree) with user-readable information for this iterato...
Definition: timing_iterator.h:57
TimingIterator::real_iterator
const RowIterator * real_iterator() const override
Definition: timing_iterator.h:68
TimingIterator::steady_clock
std::chrono::steady_clock steady_clock
Definition: timing_iterator.h:72
TimingIterator::children
std::vector< Child > children() const override
List of zero or more iterators which are direct children of this one.
Definition: timing_iterator.h:56
TimingIterator::m_time_spent_in_other_rows
steady_clock::time_point::duration m_time_spent_in_other_rows
Definition: timing_iterator.h:102
json_binary::err
static Value err()
Create a Value object that represents an error condition.
Definition: json_binary.cc:908
TimingIterator
An iterator template that wraps a RowIterator, such that all calls to Init() and Read() are timed (al...
Definition: timing_iterator.h:44
TimingIterator::m_iterator
RealIterator m_iterator
Definition: timing_iterator.h:105
NewIterator
unique_ptr_destroy_only< RowIterator > NewIterator(THD *thd, Args &&... args)
Definition: timing_iterator.h:165
my_alloc.h
TimingIterator::TimingIterator
TimingIterator(THD *thd, Args &&... args)
Definition: timing_iterator.h:47
TimingIterator::TimingString
std::string TimingString() const override
Definition: timing_iterator.h:137
TimingIterator::real_iterator
RowIterator * real_iterator() override
If this iterator is wrapping a different iterator (e.g.
Definition: timing_iterator.h:67
Query_arena::mem_root
MEM_ROOT * mem_root
Definition: sql_class.h:235
RowIterator
A context for reading through a single table using a chosen access method: index read,...
Definition: row_iterator.h:61
rules_table_service::end
Cursor end()
A past-the-end Cursor.
Definition: rules_table_service.cc:188
TimingIterator::SetNullRowFlag
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:52
TimingIterator::m_time_spent_in_first_row
steady_clock::time_point::duration m_time_spent_in_first_row
Definition: timing_iterator.h:101
TimingIterator::StartPSIBatchMode
void StartPSIBatchMode() override
Start performance schema batch mode, if supported (otherwise ignored).
Definition: timing_iterator.h:60
RowIterator::thd
THD * thd() const
Definition: row_iterator.h:254
TimingIterator::EndPSIBatchModeIfStarted
void EndPSIBatchModeIfStarted() override
Ends performance schema batch mode, if started.
Definition: timing_iterator.h:61
LEX::is_explain_analyze
bool is_explain_analyze
Definition: sql_lex.h:3248
TimingIterator::Init
bool Init() override
Initialize or reinitialize the iterator.
Definition: timing_iterator.h:109
std
Definition: varlen_sort.h:182
TimingIterator::m_num_rows
uint64_t m_num_rows
Definition: timing_iterator.h:99
seconds
double seconds()
Definition: task.c:298
TimingIterator::Read
int Read() override
Read a single row.
Definition: timing_iterator.h:120
start
static void start(PluginFuncEnv *env)
Definition: http_server_plugin.cc:572
final
#define final(a, b, c)
Definition: hash.c:109