1/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16#ifndef _SQL_PROFILE_H
17#define _SQL_PROFILE_H
18
19class Item;
20struct TABLE_LIST;
21class THD;
22typedef struct st_field_info ST_FIELD_INFO;
23typedef struct st_schema_table ST_SCHEMA_TABLE;
24
25extern ST_FIELD_INFO query_profile_statistics_info[];
26int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
27int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table);
28
29
30#define PROFILE_NONE (uint)0
31#define PROFILE_CPU (uint)(1<<0)
32#define PROFILE_MEMORY (uint)(1<<1)
33#define PROFILE_BLOCK_IO (uint)(1<<2)
34#define PROFILE_CONTEXT (uint)(1<<3)
35#define PROFILE_PAGE_FAULTS (uint)(1<<4)
36#define PROFILE_IPC (uint)(1<<5)
37#define PROFILE_SWAPS (uint)(1<<6)
38#define PROFILE_SOURCE (uint)(1<<16)
39#define PROFILE_ALL (uint)(~0)
40
41
42#if defined(ENABLED_PROFILING)
43#include "sql_priv.h"
44#include "unireg.h"
45
46#ifdef __WIN__
47#include <psapi.h>
48#endif
49
50#ifdef HAVE_SYS_RESOURCE_H
51#include <sys/resource.h>
52#endif
53
54
55class PROF_MEASUREMENT;
56class QUERY_PROFILE;
57class PROFILING;
58
59
60/**
61 Implements a persistent FIFO using server List method names. Not
62 thread-safe. Intended to be used on thread-local data only.
63*/
64template <class T> class Queue
65{
66private:
67
68 struct queue_item
69 {
70 T *payload;
71 struct queue_item *next, *previous;
72 };
73
74 struct queue_item *first, *last;
75
76public:
77 Queue()
78 {
79 elements= 0;
80 first= last= NULL;
81 }
82
83 void empty()
84 {
85 struct queue_item *i, *after_i;
86 for (i= first; i != NULL; i= after_i)
87 {
88 after_i= i->next;
89 my_free(i);
90 }
91 elements= 0;
92 }
93
94 ulong elements; /* The count of items in the Queue */
95
96 void push_back(T *payload)
97 {
98 struct queue_item *new_item;
99
100 new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0));
101
102 new_item->payload= payload;
103
104 if (first == NULL)
105 first= new_item;
106 if (last != NULL)
107 {
108 DBUG_ASSERT(last->next == NULL);
109 last->next= new_item;
110 }
111 new_item->previous= last;
112 new_item->next= NULL;
113 last= new_item;
114
115 elements++;
116 }
117
118 T *pop()
119 {
120 struct queue_item *old_item= first;
121 T *ret= NULL;
122
123 if (first == NULL)
124 {
125 DBUG_PRINT("warning", ("tried to pop nonexistent item from Queue"));
126 return NULL;
127 }
128
129 ret= old_item->payload;
130 if (first->next != NULL)
131 first->next->previous= NULL;
132 else
133 last= NULL;
134 first= first->next;
135
136 my_free(old_item);
137 elements--;
138
139 return ret;
140 }
141
142 bool is_empty()
143 {
144 DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL)));
145 return (elements == 0);
146 }
147
148 void *new_iterator()
149 {
150 return first;
151 }
152
153 void *iterator_next(void *current)
154 {
155 return ((struct queue_item *) current)->next;
156 }
157
158 T *iterator_value(void *current)
159 {
160 return ((struct queue_item *) current)->payload;
161 }
162
163};
164
165
166/**
167 A single entry in a single profile.
168*/
169class PROF_MEASUREMENT
170{
171private:
172 friend class QUERY_PROFILE;
173 friend class PROFILING;
174
175 QUERY_PROFILE *profile;
176 char *status;
177#ifdef HAVE_GETRUSAGE
178 struct rusage rusage;
179#elif defined(_WIN32)
180 FILETIME ftKernel, ftUser;
181 IO_COUNTERS io_count;
182 PROCESS_MEMORY_COUNTERS mem_count;
183#endif
184
185 char *function;
186 char *file;
187 unsigned int line;
188
189 ulong m_seq;
190 double time_usecs;
191 char *allocated_status_memory;
192
193 void set_label(const char *status_arg, const char *function_arg,
194 const char *file_arg, unsigned int line_arg);
195 void clean_up();
196
197 PROF_MEASUREMENT();
198 PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char *status_arg);
199 PROF_MEASUREMENT(QUERY_PROFILE *profile_arg, const char *status_arg,
200 const char *function_arg,
201 const char *file_arg, unsigned int line_arg);
202 ~PROF_MEASUREMENT();
203 void collect();
204};
205
206
207/**
208 The full profile for a single query, and includes multiple PROF_MEASUREMENT
209 objects.
210*/
211class QUERY_PROFILE
212{
213private:
214 friend class PROFILING;
215
216 PROFILING *profiling;
217
218 query_id_t profiling_query_id; /* Session-specific id. */
219 char *query_source;
220
221 double m_start_time_usecs;
222 double m_end_time_usecs;
223 ulong m_seq_counter;
224 Queue<PROF_MEASUREMENT> entries;
225
226
227 QUERY_PROFILE(PROFILING *profiling_arg, const char *status_arg);
228 ~QUERY_PROFILE();
229
230 void set_query_source(char *query_source_arg, size_t query_length_arg);
231
232 /* Add a profile status change to the current profile. */
233 void new_status(const char *status_arg,
234 const char *function_arg,
235 const char *file_arg, unsigned int line_arg);
236
237 /* Reset the contents of this profile entry. */
238 void reset();
239
240 /* Show this profile. This is called by PROFILING. */
241 bool show(uint options);
242};
243
244
245/**
246 Profiling state for a single THD; contains multiple QUERY_PROFILE objects.
247*/
248class PROFILING
249{
250private:
251 friend class PROF_MEASUREMENT;
252 friend class QUERY_PROFILE;
253
254 /*
255 Not the system query_id, but a counter unique to profiling.
256 */
257 query_id_t profile_id_counter;
258 THD *thd;
259 bool keeping;
260 bool enabled;
261
262 QUERY_PROFILE *current;
263 QUERY_PROFILE *last;
264 Queue<QUERY_PROFILE> history;
265
266 query_id_t next_profile_id() { return(profile_id_counter++); }
267
268public:
269 PROFILING();
270 ~PROFILING();
271
272 /**
273 At a point in execution where we know the query source, save the text
274 of it in the query profile.
275
276 This must be called exactly once per descrete statement.
277 */
278 void set_query_source(char *query_source_arg, size_t query_length_arg)
279 {
280 if (unlikely(current))
281 current->set_query_source(query_source_arg, query_length_arg);
282 }
283
284 /**
285 Prepare to start processing a new query. It is an error to do this
286 if there's a query already in process; nesting is not supported.
287
288 @param initial_state (optional) name of period before first state change
289 */
290 void start_new_query(const char *initial_state= "Starting")
291 {
292 DBUG_ASSERT(!current);
293 if (unlikely(enabled))
294 current= new QUERY_PROFILE(this, initial_state);
295 }
296
297 void discard_current_query();
298
299 void finish_current_query()
300 {
301 if (unlikely(current))
302 finish_current_query_impl();
303 }
304
305 void finish_current_query_impl();
306
307 void status_change(const char *status_arg,
308 const char *function_arg,
309 const char *file_arg, unsigned int line_arg)
310 {
311 if (unlikely(current))
312 current->new_status(status_arg, function_arg, file_arg, line_arg);
313 }
314
315 inline void set_thd(THD *thd_arg)
316 {
317 thd= thd_arg;
318 reset();
319 }
320
321 /* SHOW PROFILES */
322 bool show_profiles();
323
324 /* ... from INFORMATION_SCHEMA.PROFILING ... */
325 int fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
326 void reset();
327 void restart();
328};
329
330# endif /* ENABLED_PROFILING */
331#endif /* _SQL_PROFILE_H */
332