1 /*
2    Portions Copyright (c) 2015-Present, Facebook, Inc.
3    Portions Copyright (c) 2012, Monty Program Ab
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; version 2 of the License.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
17 
18 /* This C++ file's header file */
19 #include "./rdb_perf_context.h"
20 
21 /* C++ system header files */
22 #include <string>
23 
24 /* RocksDB header files */
25 #include "rocksdb/iostats_context.h"
26 #include "rocksdb/perf_context.h"
27 
28 /* MyRocks header files */
29 #include "./ha_rocksdb_proto.h"
30 
31 namespace myrocks {
32 
33 // To add a new metric:
34 //   1. Update the PC enum in rdb_perf_context.h
35 //   2. Update sections (A), (B), and (C) below
36 //   3. Update perf_context.test and show_engine.test
37 
38 std::string rdb_pc_stat_types[] = {
39     // (A) These should be in the same order as the PC enum
40     "USER_KEY_COMPARISON_COUNT",
41     "BLOCK_CACHE_HIT_COUNT",
42     "BLOCK_READ_COUNT",
43     "BLOCK_READ_BYTE",
44     "BLOCK_READ_TIME",
45     "BLOCK_CHECKSUM_TIME",
46     "BLOCK_DECOMPRESS_TIME",
47     "INTERNAL_KEY_SKIPPED_COUNT",
48     "INTERNAL_DELETE_SKIPPED_COUNT",
49     "GET_SNAPSHOT_TIME",
50     "GET_FROM_MEMTABLE_TIME",
51     "GET_FROM_MEMTABLE_COUNT",
52     "GET_POST_PROCESS_TIME",
53     "GET_FROM_OUTPUT_FILES_TIME",
54     "SEEK_ON_MEMTABLE_TIME",
55     "SEEK_ON_MEMTABLE_COUNT",
56     "SEEK_CHILD_SEEK_TIME",
57     "SEEK_CHILD_SEEK_COUNT",
58     "SEEK_IN_HEAP_TIME",
59     "SEEK_INTERNAL_SEEK_TIME",
60     "FIND_NEXT_USER_ENTRY_TIME",
61     "WRITE_WAL_TIME",
62     "WRITE_MEMTABLE_TIME",
63     "WRITE_DELAY_TIME",
64     "WRITE_PRE_AND_POST_PROCESS_TIME",
65     "DB_MUTEX_LOCK_NANOS",
66     "DB_CONDITION_WAIT_NANOS",
67     "MERGE_OPERATOR_TIME_NANOS",
68     "READ_INDEX_BLOCK_NANOS",
69     "READ_FILTER_BLOCK_NANOS",
70     "NEW_TABLE_BLOCK_ITER_NANOS",
71     "NEW_TABLE_ITERATOR_NANOS",
72     "BLOCK_SEEK_NANOS",
73     "FIND_TABLE_NANOS",
74     "IO_THREAD_POOL_ID",
75     "IO_BYTES_WRITTEN",
76     "IO_BYTES_READ",
77     "IO_OPEN_NANOS",
78     "IO_ALLOCATE_NANOS",
79     "IO_WRITE_NANOS",
80     "IO_READ_NANOS",
81     "IO_RANGE_SYNC_NANOS",
82     "IO_LOGGER_NANOS"};
83 
84 #define IO_PERF_RECORD(_field_)                                                \
85   do {                                                                         \
86     if (rocksdb::perf_context._field_ > 0)                                     \
87       counters->m_value[idx] += rocksdb::perf_context._field_;                 \
88     idx++;                                                                     \
89   } while (0)
90 #define IO_STAT_RECORD(_field_)                                                \
91   do {                                                                         \
92     if (rocksdb::iostats_context._field_ > 0)                                  \
93       counters->m_value[idx] += rocksdb::iostats_context._field_;              \
94     idx++;                                                                     \
95   } while (0)
96 
harvest_diffs(Rdb_atomic_perf_counters * const counters)97 static void harvest_diffs(Rdb_atomic_perf_counters *const counters) {
98   // (C) These should be in the same order as the PC enum
99   size_t idx = 0;
100   IO_PERF_RECORD(user_key_comparison_count);
101   IO_PERF_RECORD(block_cache_hit_count);
102   IO_PERF_RECORD(block_read_count);
103   IO_PERF_RECORD(block_read_byte);
104   IO_PERF_RECORD(block_read_time);
105   IO_PERF_RECORD(block_checksum_time);
106   IO_PERF_RECORD(block_decompress_time);
107   IO_PERF_RECORD(internal_key_skipped_count);
108   IO_PERF_RECORD(internal_delete_skipped_count);
109   IO_PERF_RECORD(get_snapshot_time);
110   IO_PERF_RECORD(get_from_memtable_time);
111   IO_PERF_RECORD(get_from_memtable_count);
112   IO_PERF_RECORD(get_post_process_time);
113   IO_PERF_RECORD(get_from_output_files_time);
114   IO_PERF_RECORD(seek_on_memtable_time);
115   IO_PERF_RECORD(seek_on_memtable_count);
116   IO_PERF_RECORD(seek_child_seek_time);
117   IO_PERF_RECORD(seek_child_seek_count);
118   IO_PERF_RECORD(seek_min_heap_time);
119   IO_PERF_RECORD(seek_internal_seek_time);
120   IO_PERF_RECORD(find_next_user_entry_time);
121   IO_PERF_RECORD(write_wal_time);
122   IO_PERF_RECORD(write_memtable_time);
123   IO_PERF_RECORD(write_delay_time);
124   IO_PERF_RECORD(write_pre_and_post_process_time);
125   IO_PERF_RECORD(db_mutex_lock_nanos);
126   IO_PERF_RECORD(db_condition_wait_nanos);
127   IO_PERF_RECORD(merge_operator_time_nanos);
128   IO_PERF_RECORD(read_index_block_nanos);
129   IO_PERF_RECORD(read_filter_block_nanos);
130   IO_PERF_RECORD(new_table_block_iter_nanos);
131   IO_PERF_RECORD(new_table_iterator_nanos);
132   IO_PERF_RECORD(block_seek_nanos);
133   IO_PERF_RECORD(find_table_nanos);
134   IO_STAT_RECORD(thread_pool_id);
135   IO_STAT_RECORD(bytes_written);
136   IO_STAT_RECORD(bytes_read);
137   IO_STAT_RECORD(open_nanos);
138   IO_STAT_RECORD(allocate_nanos);
139   IO_STAT_RECORD(write_nanos);
140   IO_STAT_RECORD(read_nanos);
141   IO_STAT_RECORD(range_sync_nanos);
142   IO_STAT_RECORD(logger_nanos);
143 }
144 
145 #undef IO_PERF_DIFF
146 #undef IO_STAT_DIFF
147 
148 static Rdb_atomic_perf_counters rdb_global_perf_counters;
149 
rdb_get_global_perf_counters(Rdb_perf_counters * const counters)150 void rdb_get_global_perf_counters(Rdb_perf_counters *const counters) {
151   DBUG_ASSERT(counters != nullptr);
152 
153   counters->load(rdb_global_perf_counters);
154 }
155 
load(const Rdb_atomic_perf_counters & atomic_counters)156 void Rdb_perf_counters::load(const Rdb_atomic_perf_counters &atomic_counters) {
157   for (int i = 0; i < PC_MAX_IDX; i++) {
158     m_value[i] = atomic_counters.m_value[i].load(std::memory_order_relaxed);
159   }
160 }
161 
start(const uint32_t perf_context_level)162 bool Rdb_io_perf::start(const uint32_t perf_context_level) {
163   const rocksdb::PerfLevel perf_level =
164       static_cast<rocksdb::PerfLevel>(perf_context_level);
165 
166   if (rocksdb::GetPerfLevel() != perf_level) {
167     rocksdb::SetPerfLevel(perf_level);
168   }
169 
170   if (perf_level == rocksdb::kDisable) {
171     return false;
172   }
173 
174   rocksdb::perf_context.Reset();
175   rocksdb::iostats_context.Reset();
176   return true;
177 }
178 
end_and_record(const uint32_t perf_context_level)179 void Rdb_io_perf::end_and_record(const uint32_t perf_context_level) {
180   const rocksdb::PerfLevel perf_level =
181       static_cast<rocksdb::PerfLevel>(perf_context_level);
182 
183   if (perf_level == rocksdb::kDisable) {
184     return;
185   }
186 
187   if (m_atomic_counters) {
188     harvest_diffs(m_atomic_counters);
189   }
190   harvest_diffs(&rdb_global_perf_counters);
191 
192   if (m_shared_io_perf_read && (rocksdb::perf_context.block_read_byte != 0 ||
193                                 rocksdb::perf_context.block_read_count != 0 ||
194                                 rocksdb::perf_context.block_read_time != 0)) {
195     my_io_perf_t io_perf_read;
196 
197     io_perf_read.init();
198     io_perf_read.bytes = rocksdb::perf_context.block_read_byte;
199     io_perf_read.requests = rocksdb::perf_context.block_read_count;
200 
201     /*
202       Rocksdb does not distinguish between I/O service and wait time, so just
203       use svc time.
204      */
205     io_perf_read.svc_time_max = io_perf_read.svc_time =
206         rocksdb::perf_context.block_read_time;
207 
208     m_shared_io_perf_read->sum(io_perf_read);
209   }
210 }
211 
212 }  // namespace myrocks
213