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