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-1335  USA */
15 
16 #ifndef _SQL_PROFILE_H
17 #define _SQL_PROFILE_H
18 
19 class Item;
20 struct TABLE_LIST;
21 class THD;
22 typedef struct st_field_info ST_FIELD_INFO;
23 typedef struct st_schema_table ST_SCHEMA_TABLE;
24 
25 extern ST_FIELD_INFO query_profile_statistics_info[];
26 int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
27 int 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 
55 class PROF_MEASUREMENT;
56 class QUERY_PROFILE;
57 class 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 */
64 template <class T> class Queue
65 {
66 private:
67 
68   struct queue_item
69   {
70     T *payload;
71     struct queue_item *next, *previous;
72   };
73 
74   struct queue_item *first, *last;
75 
76 public:
Queue()77   Queue()
78   {
79     elements= 0;
80     first= last= NULL;
81   }
82 
empty()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 
push_back(T * payload)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 
pop()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 
is_empty()142   bool is_empty()
143   {
144     DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL)));
145     return (elements == 0);
146   }
147 
new_iterator()148   void *new_iterator()
149   {
150     return first;
151   }
152 
iterator_next(void * current)153   void *iterator_next(void *current)
154   {
155     return ((struct queue_item *) current)->next;
156   }
157 
iterator_value(void * current)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 */
169 class PROF_MEASUREMENT
170 {
171 private:
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 */
211 class QUERY_PROFILE
212 {
213 private:
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 */
248 class PROFILING
249 {
250 private:
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 
next_profile_id()266   query_id_t next_profile_id() { return(profile_id_counter++); }
267 
268 public:
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   */
set_query_source(char * query_source_arg,size_t query_length_arg)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 
finish_current_query()299   void finish_current_query()
300   {
301     if (unlikely(current))
302       finish_current_query_impl();
303   }
304 
305   void finish_current_query_impl();
306 
status_change(const char * status_arg,const char * function_arg,const char * file_arg,unsigned int line_arg)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 
set_thd(THD * thd_arg)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