diff options
Diffstat (limited to 'sql/sql_profile.h')
-rw-r--r-- | sql/sql_profile.h | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/sql/sql_profile.h b/sql/sql_profile.h new file mode 100644 index 00000000000..b82b5ce090c --- /dev/null +++ b/sql/sql_profile.h @@ -0,0 +1,346 @@ +/* Copyright (C) 2007 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _SQL_PROFILE_H +#define _SQL_PROFILE_H + +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; +# endif +#elif defined(_MSC_VER) +# if _MSC_VER < 1300 +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; +# else +# define __func__ __FUNCTION__ +# endif +#elif defined(__BORLANDC__) +# define __func__ __FUNC__ +#else +# define __func__ _unknown_func_ +extern const char * const _unknown_func_; +#endif + +extern ST_FIELD_INFO query_profile_statistics_info[]; +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); + + +#define PROFILE_NONE 0 +#define PROFILE_CPU (1<<0) +#define PROFILE_MEMORY (1<<1) +#define PROFILE_BLOCK_IO (1<<2) +#define PROFILE_CONTEXT (1<<3) +#define PROFILE_PAGE_FAULTS (1<<4) +#define PROFILE_IPC (1<<5) +#define PROFILE_SWAPS (1<<6) +#define PROFILE_SOURCE (1<<16) +#define PROFILE_ALL (~0) + + +#ifndef ENABLED_PROFILING + +# define thd_proc_info(thd, msg) do { (thd)->proc_info= (msg); } while (0) + +#else + +# define thd_proc_info(thd, msg) \ + do { \ + if (unlikely(((thd)->options & OPTION_PROFILING) != 0)) \ + { \ + (thd)->profiling.status_change((msg), __func__, __FILE__, __LINE__); \ + } \ + else \ + { \ + (thd)->proc_info= (msg); \ + } \ + } while (0) + +#include "mysql_priv.h" + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + + +class PROFILE_ENTRY; +class QUERY_PROFILE; +class PROFILING; + + +/** + Implements a persistent FIFO using server List method names. Not + thread-safe. Intended to be used on thread-local data only. +*/ +template <class T> class Queue +{ +private: + + struct queue_item + { + T *payload; + struct queue_item *next, *previous; + }; + + struct queue_item *first, *last; + +public: + Queue() + { + elements= 0; + first= last= NULL; + } + + void empty() + { + struct queue_item *i, *after_i; + for (i= first; i != NULL; i= after_i) + { + after_i= i->next; + my_free((char *) i, MYF(0)); + } + elements= 0; + } + + ulong elements; /* The count of items in the Queue */ + + void push_back(T *payload) + { + struct queue_item *new_item; + + new_item= (struct queue_item *) my_malloc(sizeof(struct queue_item), MYF(0)); + + new_item->payload= payload; + + if (first == NULL) + first= new_item; + if (last != NULL) + { + DBUG_ASSERT(last->next == NULL); + last->next= new_item; + } + new_item->previous= last; + new_item->next= NULL; + last= new_item; + + elements++; + } + + T *pop() + { + struct queue_item *old_item= first; + T *ret= NULL; + + if (first == NULL) + { + DBUG_PRINT("warning", ("tried to pop nonexistent item from Queue")); + return NULL; + } + + ret= old_item->payload; + if (first->next != NULL) + first->next->previous= NULL; + else + last= NULL; + first= first->next; + + my_free((char *)old_item, MYF(0)); + elements--; + + return ret; + } + + bool is_empty() + { + DBUG_ASSERT(((elements > 0) && (first != NULL)) || ((elements == 0) || (first == NULL))); + return (elements == 0); + } + + void *new_iterator() + { + return first; + } + + void *iterator_next(void *current) + { + return ((struct queue_item *) current)->next; + } + + T *iterator_value(void *current) + { + return ((struct queue_item *) current)->payload; + } + +}; + + +/** + A single entry in a single profile. +*/ +class PROFILE_ENTRY +{ +private: + friend class QUERY_PROFILE; + friend class PROFILING; + + QUERY_PROFILE *profile; + char *status; +#ifdef HAVE_GETRUSAGE + struct rusage rusage; +#endif + + char *function; + char *file; + unsigned int line; + + double time_usecs; + char *allocated_status_memory; + + void set_status(const char *status_arg, const char *function_arg, + const char *file_arg, unsigned int line_arg); + void clean_up(); + + PROFILE_ENTRY(); + PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg); + PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + ~PROFILE_ENTRY(); + void collect(); +}; + + +/** + The full profile for a single query, and includes multiple PROFILE_ENTRY + objects. +*/ +class QUERY_PROFILE +{ +private: + friend class PROFILING; + + PROFILING *profiling; + + query_id_t server_query_id; /* Global id. */ + query_id_t profiling_query_id; /* Session-specific id. */ + char *query_source; + PROFILE_ENTRY profile_start; + PROFILE_ENTRY *profile_end; + Queue<PROFILE_ENTRY> entries; + + + QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, uint query_length_arg); + ~QUERY_PROFILE(); + + void set_query_source(char *query_source_arg, uint query_length_arg); + + /* Add a profile status change to the current profile. */ + void status(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + + /* Reset the contents of this profile entry. */ + void reset(); + + /* Show this profile. This is called by PROFILING. */ + bool show(uint options); +}; + + +/** + Profiling state for a single THD; contains multiple QUERY_PROFILE objects. +*/ +class PROFILING +{ +private: + friend class PROFILE_ENTRY; + friend class QUERY_PROFILE; + + /* + Not the system query_id, but a counter unique to profiling. + */ + query_id_t profile_id_counter; + THD *thd; + bool keeping; + bool enabled; + + QUERY_PROFILE *current; + QUERY_PROFILE *last; + Queue<QUERY_PROFILE> history; + + query_id_t next_profile_id() { return(profile_id_counter++); } + +public: + PROFILING(); + ~PROFILING(); + void set_query_source(char *query_source_arg, uint query_length_arg); + + /** Reset the current profile and state of profiling for the next query. */ + void reset(); + + /** + Do we intend to keep the currently collected profile? + + We don't keep profiles for some commands, such as SHOW PROFILE, SHOW + PROFILES, and some SQLCOM commands which aren't useful to profile. The + keep() and discard() functions can be called many times, only the final + setting when the query finishes is used to decide whether to discard the + profile. + + The default is to keep the profile for all queries. + */ + inline void keep() { keeping= true; }; + + /** + Do we intend to keep the currently collected profile? + @see keep() + */ + inline void discard() { keeping= false; }; + + /** + Stash this profile in the profile history and remove the oldest + profile if the history queue is full, as defined by the + profiling_history_size system variable. + */ + void store(); + + /** + Called with every update of the status via thd_proc_info() , and is + therefore the main hook into the profiling code. + */ + void status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg); + + inline void set_thd(THD *thd_arg) { thd= thd_arg; }; + + /* SHOW PROFILES */ + bool show_profiles(); + + /* SHOW PROFILE FOR QUERY query_id */ + bool show(uint options, uint profiling_query_id); + + /* SHOW PROFILE */ + bool show_last(uint options); + + /* ... from INFORMATION_SCHEMA.PROFILING ... */ + int fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond); +}; + +# endif /* HAVE_PROFILING */ +#endif /* _SQL_PROFILE_H */ |