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