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