1#include "mysql_version.h"
2#include "my_global.h"
3#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
4#include "mysql_com.h"
5#include "rpl_tblmap.h"
6#include "table.h"
7#include "field.h"
8#include "sql_show.h"
9#include "query_response_time.h"
10
11#define TIME_STRING_POSITIVE_POWER_LENGTH QRT_TIME_STRING_POSITIVE_POWER_LENGTH
12#define TIME_STRING_NEGATIVE_POWER_LENGTH 6
13#define TOTAL_STRING_POSITIVE_POWER_LENGTH QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH
14#define TOTAL_STRING_NEGATIVE_POWER_LENGTH 6
15#define MINIMUM_BASE 2
16#define MAXIMUM_BASE QRT_MAXIMUM_BASE
17#define POSITIVE_POWER_FILLER QRT_POSITIVE_POWER_FILLER
18#define NEGATIVE_POWER_FILLER QRT_NEGATIVE_POWER_FILLER
19#define TIME_OVERFLOW QRT_TIME_OVERFLOW
20#define DEFAULT_BASE QRT_DEFAULT_BASE
21
22#define do_xstr(s) do_str(s)
23#define do_str(s) #s
24#define do_format(filler,width) "%" filler width "lld"
25/*
26 Format strings for snprintf. Generate from:
27 POSITIVE_POWER_FILLER and TIME_STRING_POSITIVE_POWER_LENGTH
28 NEFATIVE_POWER_FILLER and TIME_STRING_NEGATIVE_POWER_LENGTH
29*/
30#define TIME_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TIME_STRING_POSITIVE_POWER_LENGTH))
31#define TIME_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TIME_STRING_NEGATIVE_POWER_LENGTH))
32#define TIME_STRING_FORMAT TIME_STRING_POSITIVE_POWER_FORMAT "." TIME_STRING_NEGATIVE_POWER_FORMAT
33
34#define TOTAL_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TOTAL_STRING_POSITIVE_POWER_LENGTH))
35#define TOTAL_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TOTAL_STRING_NEGATIVE_POWER_LENGTH))
36#define TOTAL_STRING_FORMAT TOTAL_STRING_POSITIVE_POWER_FORMAT "." TOTAL_STRING_NEGATIVE_POWER_FORMAT
37
38#define TIME_STRING_LENGTH QRT_TIME_STRING_LENGTH
39#define TIME_STRING_BUFFER_LENGTH (TIME_STRING_LENGTH + 1 /* '\0' */)
40
41#define TOTAL_STRING_LENGTH QRT_TOTAL_STRING_LENGTH
42#define TOTAL_STRING_BUFFER_LENGTH (TOTAL_STRING_LENGTH + 1 /* '\0' */)
43
44/*
45 Calculate length of "log linear"
46 1)
47 (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) < (MINIMUM_BASE ^ (result + 1))
48
49 2)
50 (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH)
51 and
52 (MINIMUM_BASE ^ (result + 1)) > (10 ^ STRING_POWER_LENGTH)
53
54 3)
55 result <= LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
56 result + 1 > LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
57
58 4) STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) - 1 < result <= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
59
60 MINIMUM_BASE= 2 always, LOG(MINIMUM_BASE,10)= 3.3219280948873626, result= (int)3.3219280948873626 * STRING_POWER_LENGTH
61
62 Last counter always use for time overflow
63*/
64#define POSITIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_POSITIVE_POWER_LENGTH))
65#define NEGATIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_NEGATIVE_POWER_LENGTH))
66#define OVERALL_POWER_COUNT (NEGATIVE_POWER_COUNT + 1 + POSITIVE_POWER_COUNT)
67
68#define MILLION ((unsigned long)1000 * 1000)
69
70namespace query_response_time
71{
72
73class utility
74{
75public:
76 utility() : m_base(0)
77 {
78 m_max_dec_value= MILLION;
79 for(int i= 0; TIME_STRING_POSITIVE_POWER_LENGTH > i; ++i)
80 m_max_dec_value *= 10;
81 setup(DEFAULT_BASE);
82 }
83public:
84 uint base() const { return m_base; }
85 uint negative_count() const { return m_negative_count; }
86 uint positive_count() const { return m_positive_count; }
87 uint bound_count() const { return m_bound_count; }
88 ulonglong max_dec_value() const { return m_max_dec_value; }
89 ulonglong bound(uint index) const { return m_bound[ index ]; }
90public:
91 void setup(uint base)
92 {
93 if(base != m_base)
94 {
95 m_base= base;
96
97 const ulonglong million= 1000 * 1000;
98 ulonglong value= million;
99 m_negative_count= 0;
100 while(value > 0)
101 {
102 m_negative_count += 1;
103 value /= m_base;
104 }
105 m_negative_count -= 1;
106
107 value= million;
108 m_positive_count= 0;
109 while(value < m_max_dec_value)
110 {
111 m_positive_count += 1;
112 value *= m_base;
113 }
114 m_bound_count= m_negative_count + m_positive_count;
115
116 value= million;
117 for(uint i= 0; i < m_negative_count; ++i)
118 {
119 value /= m_base;
120 m_bound[m_negative_count - i - 1]= value;
121 }
122 value= million;
123 for(uint i= 0; i < m_positive_count; ++i)
124 {
125 m_bound[m_negative_count + i]= value;
126 value *= m_base;
127 }
128 }
129 }
130private:
131 uint m_base;
132 uint m_negative_count;
133 uint m_positive_count;
134 uint m_bound_count;
135 ulonglong m_max_dec_value; /* for TIME_STRING_POSITIVE_POWER_LENGTH=7 is 10000000 */
136 ulonglong m_bound[OVERALL_POWER_COUNT];
137};
138
139static
140void print_time(char* buffer, std::size_t buffer_size, const char* format,
141 uint64 value)
142{
143 ulonglong second= (value / MILLION);
144 ulonglong microsecond= (value % MILLION);
145 my_snprintf(buffer, buffer_size, format, second, microsecond);
146}
147
148class time_collector
149{
150public:
151 time_collector(utility& u) : m_utility(&u)
152 { }
153 ~time_collector()
154 { }
155 uint32 count(uint index)
156 {
157 return my_atomic_load32((int32*)&m_count[index]);
158 }
159 uint64 total(uint index)
160 {
161 return my_atomic_load64((int64*)&m_total[index]);
162 }
163public:
164 void flush()
165 {
166 memset((void*)&m_count,0,sizeof(m_count));
167 memset((void*)&m_total,0,sizeof(m_total));
168 }
169 void collect(uint64 time)
170 {
171 int i= 0;
172 for(int count= m_utility->bound_count(); count > i; ++i)
173 {
174 if(m_utility->bound(i) > time)
175 {
176 my_atomic_add32((int32*)(&m_count[i]), 1);
177 my_atomic_add64((int64*)(&m_total[i]), time);
178 break;
179 }
180 }
181 }
182private:
183 utility* m_utility;
184 uint32 m_count[OVERALL_POWER_COUNT + 1];
185 uint64 m_total[OVERALL_POWER_COUNT + 1];
186};
187
188class collector
189{
190public:
191 collector() : m_time(m_utility)
192 {
193 m_utility.setup(DEFAULT_BASE);
194 m_time.flush();
195 }
196public:
197 void flush()
198 {
199 m_utility.setup(opt_query_response_time_range_base);
200 m_time.flush();
201 }
202 int fill(THD* thd, TABLE_LIST *tables, COND *cond)
203 {
204 DBUG_ENTER("fill_schema_query_response_time");
205 TABLE *table= static_cast<TABLE*>(tables->table);
206 Field **fields= table->field;
207 for(uint i= 0, count= bound_count() + 1 /* with overflow */; count > i; ++i)
208 {
209 char time[TIME_STRING_BUFFER_LENGTH];
210 char total[TOTAL_STRING_BUFFER_LENGTH];
211 if(i == bound_count())
212 {
213 assert(sizeof(TIME_OVERFLOW) <= TIME_STRING_BUFFER_LENGTH);
214 assert(sizeof(TIME_OVERFLOW) <= TOTAL_STRING_BUFFER_LENGTH);
215 memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
216 memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
217 }
218 else
219 {
220 print_time(time, sizeof(time), TIME_STRING_FORMAT, this->bound(i));
221 print_time(total, sizeof(total), TOTAL_STRING_FORMAT, this->total(i));
222 }
223 fields[0]->store(time,strlen(time),system_charset_info);
224 fields[1]->store((longlong)this->count(i),true);
225 fields[2]->store(total,strlen(total),system_charset_info);
226 if (schema_table_store_record(thd, table))
227 {
228 DBUG_RETURN(1);
229 }
230 }
231 DBUG_RETURN(0);
232 }
233 void collect(ulonglong time)
234 {
235 m_time.collect(time);
236 }
237 uint bound_count() const
238 {
239 return m_utility.bound_count();
240 }
241 ulonglong bound(uint index)
242 {
243 return m_utility.bound(index);
244 }
245 ulonglong count(uint index)
246 {
247 return m_time.count(index);
248 }
249 ulonglong total(uint index)
250 {
251 return m_time.total(index);
252 }
253private:
254 utility m_utility;
255 time_collector m_time;
256};
257
258static collector g_collector;
259
260} // namespace query_response_time
261
262void query_response_time_init()
263{
264}
265
266void query_response_time_free()
267{
268 query_response_time::g_collector.flush();
269}
270
271int query_response_time_flush()
272{
273 query_response_time::g_collector.flush();
274 return 0;
275}
276void query_response_time_collect(ulonglong query_time)
277{
278 query_response_time::g_collector.collect(query_time);
279}
280
281int query_response_time_fill(THD* thd, TABLE_LIST *tables, COND *cond)
282{
283 return query_response_time::g_collector.fill(thd,tables,cond);
284}
285#endif // HAVE_RESPONSE_TIME_DISTRIBUTION
286