Below is the list of changes that have just been committed into a local
5.0 repository of cmiller. When cmiller does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-01-31 10:08:24-05:00, cmiller@stripped +16 -0
Bug#24795: SHOW PROFILE patch by Jeremy Cole
Significant changes over last changeset:
- Support disabling and enabling profiling from inside the server.
- Support setting the history size of profiling data.
- Use the 5.1 naming standard for setting thread info.
- Make profiling conditionally compiled in, at configure time.
Syntax this adds:
SHOW PROFILES
SHOW PROFILE [types] [FOR QUERY n] [OFFSET n] [LIMIT n]
where "n" is an integer
and "types" is zero or many (comma-separated) of
"CPU"
"MEMORY" (not presently supported)
"BLOCK IO"
"CONTEXT SWITCHES"
"PAGE FAULTS"
"IPC"
"SWAPS"
"SOURCE"
"ALL"
configure.in@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +14 -0
Add a configure-time option to enable/disable query profiling. The
default is enabled.
mysql-test/r/profiling.result@stripped, 2007-01-31 10:08:23-05:00, cmiller@stripped +71 -0
Result of tests. Most don't include output, since that will vary
greatly.
mysql-test/r/profiling.result@stripped, 2007-01-31 10:08:23-05:00, cmiller@stripped +0 -0
mysql-test/t/profiling-master.opt@stripped, 2007-01-31 10:08:23-05:00, cmiller@stripped +1 -0
A HACK to make the server restart so that the test gets knowable
query_ids.
If the test suite ever supports restarting in a general way, remove
this.
mysql-test/t/profiling-master.opt@stripped, 2007-01-31 10:08:23-05:00, cmiller@stripped +0 -0
mysql-test/t/profiling.test@stripped, 2007-01-31 10:08:23-05:00, cmiller@stripped +93 -0
Illustrate that profiling works.
But, hide the interesting parts, because
1) execution times vary between runs, and
2) the execution paths and source lines will vary as the server is
modified or optimized.
Even the query IDs will change eventually, but that's not likely
to happen often.
mysql-test/t/profiling.test@stripped, 2007-01-31 10:08:23-05:00, cmiller@stripped +0 -0
sql/mysql_priv.h@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +40 -33
Use 64-bit constants for the 64-bit bit field.
Add a new option bit for whether profiling is active or not.
sql/mysqld.cc@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +7 -1
Add semicolon to DBUG statement.
Add a new system variable and set it.
sql/set_var.cc@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +14 -0
Make a new system global variable and session variable, to determine
behavior of profiling.
sql/set_var.h@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +2 -2
The THD::options bit field is ulonglong, not ulong.
sql/sql_class.cc@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +2 -1
Remove redundent profiling call.
sql/sql_class.h@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +7 -0
Create a new system variable, profiling_history_size.
Conditionally insert profiling symbol to thread.
sql/sql_lex.cc@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +2 -1
Don't set profile options if not present.
sql/sql_lex.h@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +17 -4
Reuse memory addresses of uints that can't occur in the same state-
ment.
This is dangerous because it involves knowledge of what symbols are
never used together, which is information stored obliquely in another
file.
sql/sql_parse.cc@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +33 -14
Use 5.1-compatible case.
If profiling is not present, then return an error message upon being
used.
sql/sql_profile.cc@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +190 -84
Provide as much information as possible, but return NULLs on
platforms that don't support some statistic.
Clean up after myself properly, to avoid valgrind warnings.
On being asked for a query number that doesn't exist in the history,
return an error.
Make the history length a system-settable variable.
sql/sql_profile.h@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +111 -82
Use platform-independent naming for the function name.
If profiling is not present, then use the original code of setting
the thread state.
Make as many members as possible private.
sql/sql_yacc.yy@stripped, 2007-01-31 10:08:22-05:00, cmiller@stripped +57 -19
Make the SHOW PROFILE FOR QUERY x syntax correct.
Conditionally use profiling constants in setting lex flags.
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: cmiller
# Host: zippy.cornsilk.net
# Root: /home/cmiller/work/mysql/mysql-5.0-community-2--bug24795
--- 1.420/configure.in 2007-01-31 10:08:30 -05:00
+++ 1.421/configure.in 2007-01-31 10:08:30 -05:00
@@ -667,6 +667,20 @@ else
AC_MSG_RESULT([no])
fi
+# Add query profiler
+AC_ARG_ENABLE(profiling,
+ [ --disable-profiling Build a version without query profiling code ],
+ [ ENABLED_PROFILING=$enableval ],
+ [ ENABLED_PROFILING=yes ])
+
+if test "$ENABLED_PROFILING" = "yes"
+then
+ AC_DEFINE([ENABLED_PROFILING], [1],
+ [If SHOW PROFILE should be enabled by default])
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
# Use this to set the place used for unix socket used to local communication.
AC_ARG_WITH(unix-socket-path,
--- 1.429/sql/mysql_priv.h 2007-01-31 10:08:30 -05:00
+++ 1.430/sql/mysql_priv.h 2007-01-31 10:08:30 -05:00
@@ -20,6 +20,9 @@
except the part which must be in the server and in the client.
*/
+#ifndef MYSQL_PRIV_H_INCLUDED
+#define MYSQL_PRIV_H_INCLUDED
+
#ifndef MYSQL_CLIENT
#include <my_global.h>
@@ -298,55 +301,57 @@ MY_LOCALE *my_locale_by_name(const char
TODO: separate three contexts above, move them to separate bitfields.
*/
-#define SELECT_DISTINCT (1L << 0) // SELECT, user
-#define SELECT_STRAIGHT_JOIN (1L << 1) // SELECT, user
-#define SELECT_DESCRIBE (1L << 2) // SELECT, user
-#define SELECT_SMALL_RESULT (1L << 3) // SELECT, user
-#define SELECT_BIG_RESULT (1L << 4) // SELECT, user
-#define OPTION_FOUND_ROWS (1L << 5) // SELECT, user
-#define OPTION_TO_QUERY_CACHE (1L << 6) // SELECT, user
-#define SELECT_NO_JOIN_CACHE (1L << 7) // intern
-#define OPTION_BIG_TABLES (1L << 8) // THD, user
-#define OPTION_BIG_SELECTS (1L << 9) // THD, user
-#define OPTION_LOG_OFF (1L << 10) // THD, user
-#define OPTION_UPDATE_LOG (1L << 11) // THD, user, unused
-#define TMP_TABLE_ALL_COLUMNS (1L << 12) // SELECT, intern
-#define OPTION_WARNINGS (1L << 13) // THD, user
-#define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog
-#define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser
-#define OPTION_SAFE_UPDATES (1L << 16) // THD, user
-#define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user
-#define OPTION_BIN_LOG (1L << 18) // THD, user
-#define OPTION_NOT_AUTOCOMMIT (1L << 19) // THD, user
-#define OPTION_BEGIN (1L << 20) // THD, intern
-#define OPTION_TABLE_LOCK (1L << 21) // THD, intern
-#define OPTION_QUICK (1L << 22) // SELECT (for DELETE)
-#define OPTION_QUOTE_SHOW_CREATE (1L << 23) // THD, user
+#define SELECT_DISTINCT (1ULL << 0) // SELECT, user
+#define SELECT_STRAIGHT_JOIN (1ULL << 1) // SELECT, user
+#define SELECT_DESCRIBE (1ULL << 2) // SELECT, user
+#define SELECT_SMALL_RESULT (1ULL << 3) // SELECT, user
+#define SELECT_BIG_RESULT (1ULL << 4) // SELECT, user
+#define OPTION_FOUND_ROWS (1ULL << 5) // SELECT, user
+#define OPTION_TO_QUERY_CACHE (1ULL << 6) // SELECT, user
+#define SELECT_NO_JOIN_CACHE (1ULL << 7) // intern
+#define OPTION_BIG_TABLES (1ULL << 8) // THD, user
+#define OPTION_BIG_SELECTS (1ULL << 9) // THD, user
+#define OPTION_LOG_OFF (1ULL << 10) // THD, user
+#define OPTION_UPDATE_LOG (1ULL << 11) // THD, user, unused
+#define TMP_TABLE_ALL_COLUMNS (1ULL << 12) // SELECT, intern
+#define OPTION_WARNINGS (1ULL << 13) // THD, user
+#define OPTION_AUTO_IS_NULL (1ULL << 14) // THD, user, binlog
+#define OPTION_FOUND_COMMENT (1ULL << 15) // SELECT, intern, parser
+#define OPTION_SAFE_UPDATES (1ULL << 16) // THD, user
+#define OPTION_BUFFER_RESULT (1ULL << 17) // SELECT, user
+#define OPTION_BIN_LOG (1ULL << 18) // THD, user
+#define OPTION_NOT_AUTOCOMMIT (1ULL << 19) // THD, user
+#define OPTION_BEGIN (1ULL << 20) // THD, intern
+#define OPTION_TABLE_LOCK (1ULL << 21) // THD, intern
+#define OPTION_QUICK (1ULL << 22) // SELECT (for DELETE)
+#define OPTION_QUOTE_SHOW_CREATE (1ULL << 23) // THD, user
/* Thr following is used to detect a conflict with DISTINCT
in the user query has requested */
-#define SELECT_ALL (1L << 24) // SELECT, user, parser
+#define SELECT_ALL (1ULL << 24) // SELECT, user, parser
/* Set if we are updating a non-transaction safe table */
-#define OPTION_STATUS_NO_TRANS_UPDATE (1L << 25) // THD, intern
+#define OPTION_STATUS_NO_TRANS_UPDATE (1ULL << 25) // THD, intern
/* The following can be set when importing tables in a 'wrong order'
to suppress foreign key checks */
-#define OPTION_NO_FOREIGN_KEY_CHECKS (1L << 26) // THD, user, binlog
+#define OPTION_NO_FOREIGN_KEY_CHECKS (1ULL << 26) // THD, user, binlog
/* The following speeds up inserts to InnoDB tables by suppressing unique
key checks in some cases */
-#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) // THD, user, binlog
-#define SELECT_NO_UNLOCK (1L << 28) // SELECT, intern
-#define OPTION_SCHEMA_TABLE (1L << 29) // SELECT, intern
+#define OPTION_RELAXED_UNIQUE_CHECKS (1ULL << 27) // THD, user, binlog
+#define SELECT_NO_UNLOCK (1ULL << 28) // SELECT, intern
+#define OPTION_SCHEMA_TABLE (1ULL << 29) // SELECT, intern
/* Flag set if setup_tables already done */
-#define OPTION_SETUP_TABLES_DONE (1L << 30) // intern
+#define OPTION_SETUP_TABLES_DONE (1ULL << 30) // intern
/* If not set then the thread will ignore all warnings with level notes. */
-#define OPTION_SQL_NOTES (1UL << 31) // THD, user
+#define OPTION_SQL_NOTES (1ULL << 31) // THD, user
/*
Force the used temporary table to be a MyISAM table (because we will use
fulltext functions when reading from it.
*/
-#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32)
+#define TMP_TABLE_FORCE_MYISAM (1ULL << 32)
+#define OPTION_PROFILING (1ULL << 33)
+
/*
Maximum length of time zone name that we support
@@ -1686,3 +1691,5 @@ inline void kill_delayed_threads(void) {
#endif
#endif /* MYSQL_CLIENT */
+
+#endif
--- 1.588/sql/mysqld.cc 2007-01-31 10:08:30 -05:00
+++ 1.589/sql/mysqld.cc 2007-01-31 10:08:30 -05:00
@@ -1657,7 +1657,7 @@ void end_thread(THD *thd, bool put_in_ca
! abort_loop && !kill_cached_threads)
{
/* Don't kill the thread, just put it in cache for reuse */
- DBUG_PRINT("info", ("Adding thread to cache"))
+ DBUG_PRINT("info", ("Adding thread to cache"));
cached_thread_count++;
while (!abort_loop && ! wake_thread && ! kill_cached_threads)
(void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count);
@@ -5257,6 +5257,12 @@ Disable with --skip-ndbcluster (will sav
"Maximum time in seconds to wait for the port to become free. "
"(Default: no wait)", (gptr*) &mysqld_port_timeout,
(gptr*) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef ENABLED_PROFILING
+ {"profiling_history_size", 0, "Limit of query profiling memory",
+ (gptr*) &global_system_variables.profiling_history_size,
+ (gptr*) &max_system_variables.profiling_history_size,
+ 0, GET_UINT, REQUIRED_ARG, 15, 50, 100, 0, 0, 0},
+#endif
{"relay-log", OPT_RELAY_LOG,
"The location and name to use for relay logs.",
(gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
--- 1.257/sql/sql_class.cc 2007-01-31 10:08:30 -05:00
+++ 1.258/sql/sql_class.cc 2007-01-31 10:08:30 -05:00
@@ -247,7 +247,9 @@ THD::THD()
init();
/* Initialize sub structures */
init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
+#ifdef ENABLED_PROFILING
profiling.set_thd(this);
+#endif
user_connect=(USER_CONN *)0;
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
@@ -330,7 +332,6 @@ void THD::init_for_queries()
variables.trans_alloc_block_size,
variables.trans_prealloc_size);
#endif
- profiling.reset();
transaction.xid_state.xid.null();
transaction.xid_state.in_thd=1;
}
--- 1.315/sql/sql_class.h 2007-01-31 10:08:30 -05:00
+++ 1.316/sql/sql_class.h 2007-01-31 10:08:30 -05:00
@@ -521,6 +521,7 @@ struct system_variables
ulong optimizer_prune_level;
ulong optimizer_search_depth;
ulong preload_buff_size;
+ ulong profiling_history_size;
ulong query_cache_type;
ulong read_buff_size;
ulong read_rnd_buff_size;
@@ -1072,6 +1073,7 @@ public:
};
+
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -1154,6 +1156,9 @@ public:
Points to info-string that we show in SHOW PROCESSLIST
You are supposed to update thd->proc_info only if you have coded
a time-consuming piece that MySQL can get stuck in for a long time.
+
+ Set it using the thd_proc_info(THD *thread, const char *message)
+ macro/function.
*/
const char *proc_info;
@@ -1309,7 +1314,9 @@ public:
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count;
+#ifdef ENABLED_PROFILING
PROFILING profiling;
+#endif
/*
Id of current query. Statement can be reused to execute several queries
--- 1.210/sql/sql_lex.cc 2007-01-31 10:08:30 -05:00
+++ 1.211/sql/sql_lex.cc 2007-01-31 10:08:30 -05:00
@@ -173,8 +173,9 @@ void lex_start(THD *thd, uchar *buf,uint
lex->proc_list.first= 0;
lex->escape_used= FALSE;
lex->reset_query_tables_list(FALSE);
+#ifdef ENABLED_PROFILING
lex->profile_options= PROFILE_NONE;
-
+#endif
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
--- 1.237/sql/sql_lex.h 2007-01-31 10:08:30 -05:00
+++ 1.238/sql/sql_lex.h 2007-01-31 10:08:30 -05:00
@@ -939,10 +939,23 @@ typedef struct st_lex : public Query_tab
enum enum_var_type option_type;
enum enum_view_create_mode create_view_mode;
enum enum_drop_mode drop_mode;
+
+ /*
+ Save space by reusing memory addresses where two uses
+ of a varialbe is impossible in the same statement. This
+ is dangerous because it implies some intimacy with the
+ grammar and we're duplicating information, even if it is
+ implicit.
+ */
+ union {
+ uint uint_geom_type;
uint profile_options;
+ };
+ union {
uint profile_query_id;
- uint uint_geom_type;
- uint grant, grant_tot_col, which_columns;
+ uint grant;
+ };
+ uint grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt;
int nest_level;
--- 1.594/sql/sql_parse.cc 2007-01-31 10:08:30 -05:00
+++ 1.595/sql/sql_parse.cc 2007-01-31 10:08:30 -05:00
@@ -1058,7 +1058,7 @@ void execute_init_command(THD *thd, sys_
Vio* save_vio;
ulong save_client_capabilities;
- THD_PROC_INFO(thd, "Execution of init_command");
+ thd_proc_info(thd, "Execution of init_command");
/*
We need to lock init_command_var because
during execution of init_command_var query
@@ -1158,7 +1158,7 @@ pthread_handler_t handle_one_connection(
net->compress=1; // Use compression
thd->version= refresh_version;
- THD_PROC_INFO(thd, 0);
+ thd_proc_info(thd, 0);
thd->command= COM_SLEEP;
thd->set_time();
thd->init_for_queries();
@@ -1175,7 +1175,7 @@ pthread_handler_t handle_one_connection(
sctx->host_or_ip, "init_connect command failed");
sql_print_warning("%s", net->last_error);
}
- THD_PROC_INFO(thd, 0);
+ thd_proc_info(thd, 0);
thd->set_time();
thd->init_for_queries();
}
@@ -1258,7 +1258,7 @@ pthread_handler_t handle_bootstrap(void
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
- THD_PROC_INFO(thd, 0);
+ thd_proc_info(thd, 0);
thd->version=refresh_version;
thd->security_ctx->priv_user=
thd->security_ctx->user= (char*) my_strdup("boot", MYF(MY_WME));
@@ -2105,7 +2105,7 @@ bool dispatch_command(enum enum_server_c
if (thd->lock || thd->open_tables || thd->derived_tables ||
thd->prelocked_mode)
{
- THD_PROC_INFO(thd, "closing tables");
+ thd_proc_info(thd, "closing tables");
close_thread_tables(thd); /* Free tables */
}
/*
@@ -2128,9 +2128,9 @@ bool dispatch_command(enum enum_server_c
log_slow_statement(thd);
- THD_PROC_INFO(thd, "cleaning up");
+ thd_proc_info(thd, "cleaning up");
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
- THD_PROC_INFO(thd, 0);
+ thd_proc_info(thd, 0);
thd->command=COM_SLEEP;
thd->query=0;
thd->query_length=0;
@@ -2171,7 +2171,7 @@ void log_slow_statement(THD *thd)
/* == SQLCOM_END unless this is a SHOW command */
thd->lex->orig_sql_command == SQLCOM_END)
{
- THD_PROC_INFO(thd, "logging slow query");
+ thd_proc_info(thd, "logging slow query");
thd->status_var.long_query_count++;
mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
}
@@ -2698,16 +2698,33 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_SHOW_PROFILES:
{
+#ifdef ENABLED_PROFILING
thd->profiling.store();
thd->profiling.discard();
res= thd->profiling.show_profiles();
+ if (res)
+ goto error;
+#else
+ my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling");
+ goto error;
+#endif
break;
}
case SQLCOM_SHOW_PROFILE:
{
+#ifdef ENABLED_PROFILING
thd->profiling.store();
thd->profiling.discard(); // will get re-enabled by reset()
+ if (lex->profile_query_id != 0)
+ res= thd->profiling.show(lex->profile_options, lex->profile_query_id);
+ else
res= thd->profiling.show_last(lex->profile_options);
+ if (res)
+ goto error;
+#else
+ my_error(ER_FEATURE_DISABLED, MYF(0), "query profiling", "enable-profiling");
+ goto error;
+#endif
break;
}
case SQLCOM_SHOW_NEW_MASTER:
@@ -3557,7 +3574,7 @@ end_with_restore_list:
if (add_item_to_list(thd, new Item_null()))
goto error;
- THD_PROC_INFO(thd, "init");
+ thd_proc_info(thd, "init");
if ((res= open_and_lock_tables(thd, all_tables)))
break;
@@ -4986,7 +5003,7 @@ create_sp_error:
send_ok(thd);
break;
}
- THD_PROC_INFO(thd, "query end");
+ thd_proc_info(thd, "query end");
/* Two binlog-related cleanups: */
/*
@@ -5157,7 +5174,7 @@ check_access(THD *thd, ulong want_access
else
save_priv= &dummy;
- THD_PROC_INFO(thd, "checking permissions");
+ thd_proc_info(thd, "checking permissions");
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
@@ -5605,6 +5622,9 @@ mysql_init_query(THD *thd, uchar *buf, u
DBUG_ENTER("mysql_init_query");
lex_start(thd, buf, length);
mysql_reset_thd_for_next_command(thd);
+#ifdef ENABLED_PROFILING
+ thd->profiling.reset();
+#endif
DBUG_VOID_RETURN;
}
@@ -5646,7 +5666,6 @@ void mysql_reset_thd_for_next_command(TH
thd->total_warn_count=0; // Warnings for this query
thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0;
- thd->profiling.reset();
}
DBUG_VOID_RETURN;
}
@@ -5870,7 +5889,7 @@ void mysql_parse(THD *thd, char *inBuf,
query_cache_abort(&thd->net);
lex->unit.cleanup();
}
- THD_PROC_INFO(thd, "freeing items");
+ thd_proc_info(thd, "freeing items");
thd->end_statement();
thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
--- 1.501/sql/sql_yacc.yy 2007-01-31 10:08:30 -05:00
+++ 1.502/sql/sql_yacc.yy 2007-01-31 10:08:30 -05:00
@@ -928,7 +928,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
union_opt select_derived_init option_type2
%type <ulong_num>
- ulong_num raid_types merge_insert_types opt_profile_query_arg
+ ulong_num raid_types merge_insert_types
%type <ulonglong_number>
ulonglong_num
@@ -6678,36 +6678,74 @@ profile_defs:
profile_def:
CPU_SYM
- { Lex->profile_options|= PROFILE_CPU; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_CPU;
+#endif
+ }
| MEMORY_SYM
- { Lex->profile_options|= PROFILE_MEMORY; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_MEMORY;
+#endif
+ }
| BLOCK_SYM IO_SYM
- { Lex->profile_options|= PROFILE_BLOCK_IO; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_BLOCK_IO;
+#endif
+ }
| CONTEXT_SYM SWITCHES_SYM
- { Lex->profile_options|= PROFILE_CONTEXT; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_CONTEXT;
+#endif
+ }
| PAGE_SYM FAULTS_SYM
- { Lex->profile_options|= PROFILE_PAGE_FAULTS; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_PAGE_FAULTS;
+#endif
+ }
| IPC_SYM
- { Lex->profile_options|= PROFILE_IPC; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_IPC;
+#endif
+ }
| SWAPS_SYM
- { Lex->profile_options|= PROFILE_SWAPS; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_SWAPS;
+#endif
+ }
| SOURCE_SYM
- { Lex->profile_options|= PROFILE_SOURCE; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_SOURCE;
+#endif
+ }
| ALL
- { Lex->profile_options|= PROFILE_ALL; }
- ;
-
-opt_profile_query_arg:
- /* empty */
- { $$= 0; }
- | QUERY_SYM NUM
- { $$= atoi($2.str); }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_options|= PROFILE_ALL;
+#endif
+ }
;
opt_profile_args:
/* empty */
- | FOR_SYM opt_profile_query_arg
- { Lex->profile_query_id = $2; }
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_query_id= 0;
+#endif
+ }
+ | FOR_SYM QUERY_SYM NUM
+ {
+#ifdef ENABLED_PROFILING
+ Lex->profile_query_id= atoi($3.str);
+#endif
+ }
;
/* Show things */
--- New file ---
+++ mysql-test/r/profiling.result 07/01/31 10:08:23
show session variables like 'profil%';
Variable_name Value
profiling OFF
profiling_history_size 15
select @@profiling;
@@profiling
0
set global profiling = ON;
ERROR HY000: Variable 'profiling' is a SESSION variable and can't be used with SET GLOBAL
set global profiling_history_size=100;
show global variables like 'profil%';
Variable_name Value
profiling OFF
profiling_history_size 100
set session profiling = ON;
set session profiling_history_size=97;
show session variables like 'profil%';
Variable_name Value
profiling ON
profiling_history_size 97
select @@profiling;
@@profiling
1
create table t1 (
a int,
b int
);
insert into t1 values (1,1), (2,null), (3, 4);
insert into t1 values (5,1), (6,null), (7, 4);
insert into t1 values (1,1), (2,null), (3, 4);
insert into t1 values (5,1), (6,null), (7, 4);
select max(x) from (select sum(a) as x from t1 group by b) as teeone;
insert into t1 select * from t1;
select count(*) from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
select count(*) from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
select count(*) from t1;
select sum(a) from t1;
select sum(a) from t1 group by b;
select sum(a) + sum(b) from t1 group by b;
select max(x) from (select sum(a) as x from t1 group by b) as teeone;
show profiles;
show profile for query 15;
show profile cpu for query 15;
show profile cpu, block io for query 15;
show profile cpu for query 9 limit 2 offset 2;
show profile cpu for query 10 limit 0;
show profile cpu for query 65534;
show profile memory;
show profile block io;
show profile context switches;
show profile page faults;
show profile ipc;
show profile swaps limit 1 offset 2;
show profile source;
show profile all for query 0 limit 0;
show profile all for query 15;
show profile all for query 29;
set session profiling = OFF;
insert into t1 values (5,1), (6,null), (7, 4);
insert into t1 values (5,1), (6,null), (7, 4);
select sum(a) from t1;
select sum(a) from t1 group by b;
show profiles;
drop table t1;
End of 5.0 tests
--- New file ---
+++ mysql-test/t/profiling-master.opt 07/01/31 10:08:23
--port-open-timeout=42
--- New file ---
+++ mysql-test/t/profiling.test 07/01/31 10:08:23
# default is OFF
show session variables like 'profil%';
select @@profiling;
# setting global variable is an error
--error ER_LOCAL_VARIABLE
set global profiling = ON;
# But size is okay
set global profiling_history_size=100;
show global variables like 'profil%';
# turn on for testing
set session profiling = ON;
set session profiling_history_size=97;
# verify it is active
show session variables like 'profil%';
select @@profiling;
--disable_result_log
create table t1 (
a int,
b int
);
insert into t1 values (1,1), (2,null), (3, 4);
insert into t1 values (5,1), (6,null), (7, 4);
insert into t1 values (1,1), (2,null), (3, 4);
insert into t1 values (5,1), (6,null), (7, 4);
select max(x) from (select sum(a) as x from t1 group by b) as teeone;
insert into t1 select * from t1;
select count(*) from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
select count(*) from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
insert into t1 select * from t1;
select count(*) from t1;
select sum(a) from t1;
select sum(a) from t1 group by b;
select sum(a) + sum(b) from t1 group by b;
select max(x) from (select sum(a) as x from t1 group by b) as teeone;
--replace_column 2 #
show profiles;
--replace_column 2 # 3 # 4 #
show profile for query 15;
--replace_column 2 # 3 # 4 #
show profile cpu for query 15;
--replace_column 2 # 3 # 4 # 5 # 6 #
show profile cpu, block io for query 15;
--replace_column 2 # 3 # 4 #
show profile cpu for query 9 limit 2 offset 2;
show profile cpu for query 10 limit 0;
--error 0,ER_WRONG_ARGUMENTS
show profile cpu for query 65534;
--replace_column 2 #
show profile memory;
--replace_column 2 # 3 # 4 #
show profile block io;
--replace_column 2 # 3 # 4 #
show profile context switches;
--replace_column 2 # 3 # 4 #
show profile page faults;
--replace_column 2 # 3 # 4 #
show profile ipc;
--replace_column 2 #
show profile swaps limit 1 offset 2;
--replace_column 2 # 5 #
show profile source;
show profile all for query 0 limit 0;
--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 16 #
show profile all for query 15;
--replace_column 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 16 #
show profile all for query 29;
# Verify that turning it off does freeze it.
set session profiling = OFF;
insert into t1 values (5,1), (6,null), (7, 4);
insert into t1 values (5,1), (6,null), (7, 4);
select sum(a) from t1;
select sum(a) from t1 group by b;
--replace_column 2 #
show profiles;
drop table t1;
--enable_result_log
##
--echo End of 5.0 tests
--- 1.1/sql/sql_profile.cc 2007-01-31 10:08:30 -05:00
+++ 1.2/sql/sql_profile.cc 2007-01-31 10:08:30 -05:00
@@ -14,27 +14,29 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
#include "mysql_priv.h"
-#include "sp_rcontext.h"
+#include "my_sys.h"
+
+#ifdef ENABLED_PROFILING
#define RUSAGE_USEC(tv) ((tv).tv_sec*1000000 + (tv).tv_usec)
#define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2)))
PROFILE_ENTRY::PROFILE_ENTRY()
- :status(NULL), time(0), function(NULL), file(NULL), line(0)
+ :profile(NULL), status(NULL), time(0), function(NULL), file(NULL), line(0)
{
collect();
}
-PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg)
+PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg)
:profile(profile_arg), function(NULL), file(NULL), line(0)
{
collect();
- if (status_arg)
set_status(status_arg);
}
-PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg,
+PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg,
const char *function_arg,
const char *file_arg, unsigned int line_arg)
:profile(profile_arg)
@@ -43,64 +45,80 @@ PROFILE_ENTRY::PROFILE_ENTRY(PROFILE *pr
if (status_arg)
set_status(status_arg);
if (function_arg)
- function= strdup_root(&profile->profiling->root, function_arg);
+ function= my_strdup(function_arg, MYF(0));
if (file_arg)
- file= strdup_root(&profile->profiling->root, file_arg);
+ file= my_strdup(file_arg, MYF(0));
line= line_arg;
}
PROFILE_ENTRY::~PROFILE_ENTRY()
{
if (status)
- free(status);
+ my_free(status, MYF(0));
if (function)
- free(function);
+ my_free(function, MYF(0));
if (file)
- free(file);
+ my_free(file, MYF(0));
+ status= function= file= NULL;
}
void PROFILE_ENTRY::set_status(const char *status_arg)
{
- status= strdup_root(&profile->profiling->root, status_arg);
+ if (status_arg)
+ status= my_strdup(status_arg, 0);
+ else
+ status= NULL;
}
void PROFILE_ENTRY::collect()
{
time= my_getsystime();
+#ifdef HAVE_GETRUSAGE
getrusage(RUSAGE_SELF, &rusage);
+#endif
}
-PROFILE::PROFILE(PROFILING *profiling_arg)
- :profiling(profiling_arg)
+QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg,
+ const char *query_source_arg)
+ :profiling(profiling_arg), profiling_query_id(-1)
{
profile_end= &profile_start;
+ query_source= my_strdup(query_source_arg, MYF(0));
}
-PROFILE::~PROFILE()
+QUERY_PROFILE::~QUERY_PROFILE()
{
+ PROFILE_ENTRY *entry;
+ List_iterator<PROFILE_ENTRY> it(entries);
+ while ((entry= it++) != NULL)
+ delete entry;
entries.empty();
+
+ if (query_source != NULL)
+ my_free(query_source, MYF(0));
}
-void PROFILE::status(const char *status_arg,
+void QUERY_PROFILE::status(const char *status_arg,
const char *function_arg=NULL,
const char *file_arg=NULL, unsigned int line_arg=0)
{
- PROFILE_ENTRY *prof= NULL;
- MEM_ROOT *old_root= NULL;
THD *thd= profiling->thd;
-
- DBUG_ENTER("PROFILE::status");
+ PROFILE_ENTRY *prof;
+ MEM_ROOT *saved_mem_root;
+ DBUG_ENTER("QUERY_PROFILE::set_status");
/* Blank status. Just return, and thd->proc_info will be set blank later. */
- if (unlikely(!status_arg))
+ if (unlikely(status_arg == NULL))
DBUG_VOID_RETURN;
/* If thd->proc_info is currently set to status_arg, don't profile twice. */
- if (unlikely(thd->proc_info && !(strcmp(thd->proc_info, status_arg))))
+ if (likely((thd->proc_info != NULL) &&
+ ((thd->proc_info == status_arg) ||
+ (strcmp(thd->proc_info, status_arg) == 0))))
DBUG_VOID_RETURN;
/* Is this the same query as our profile currently contains? */
- if (unlikely(thd->query_id != query_id && !thd->spcont))
+ if (unlikely((thd->query_id != profiling_query_id) && !thd->spcont))
reset();
/*
@@ -113,50 +131,58 @@ void PROFILE::status(const char *status_
The thd->mem_root structure is freed after each query is completed,
so temporarily override it.
*/
- old_root= thd->mem_root;
- thd->mem_root= &profiling->root;
- if (function_arg && file_arg) {
- if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg, file_arg, line_arg)))
+ saved_mem_root= thd->mem_root;
+ thd->mem_root= &profiling->mem_root;
+ if (function_arg && file_arg)
+ {
+ if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg, function_arg,
+ file_arg, line_arg)))
entries.push_back(prof);
- } else {
+ }
+ else
+ {
if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg)))
entries.push_back(prof);
}
- thd->mem_root= old_root;
+ thd->mem_root= saved_mem_root;
DBUG_VOID_RETURN;
}
-void PROFILE::reset()
+void QUERY_PROFILE::reset()
{
- DBUG_ENTER("PROFILE::reset");
- if (profiling->thd->query_id != query_id)
+ DBUG_ENTER("QUERY_PROFILE::reset");
+ if (likely(profiling->thd->query_id != profiling_query_id))
{
- query_id= profiling->thd->query_id;
+ profiling_query_id= profiling->thd->query_id;
profile_start.collect();
entries.empty();
}
DBUG_VOID_RETURN;
}
-bool PROFILE::show(uint options)
+bool QUERY_PROFILE::show(uint options)
{
PROFILE_ENTRY *prof;
THD *thd= profiling->thd;
PROFILE_ENTRY *ps= &profile_start;
List<Item> field_list;
- DBUG_ENTER("PROFILE::show");
+ DBUG_ENTER("QUERY_PROFILE::show");
field_list.push_back(new Item_empty_string("Status", MYSQL_ERRMSG_SIZE));
- field_list.push_back(new Item_return_int("Time_elapsed", 20,
+ field_list.push_back(new Item_return_int("Elapsed_usec", 20,
MYSQL_TYPE_LONGLONG));
if (options & PROFILE_CPU)
{
- field_list.push_back(new Item_return_int("CPU_user", 20,
+ field_list.push_back(new Item_return_int("CPU_user_usec", 20,
MYSQL_TYPE_LONGLONG));
- field_list.push_back(new Item_return_int("CPU_system", 20,
+ field_list.push_back(new Item_return_int("CPU_system_usec", 20,
MYSQL_TYPE_LONGLONG));
+#ifndef HAVE_GETRUSAGE
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
+ "CPU usage not available on this platform");
+#endif
}
if (options & PROFILE_MEMORY)
@@ -169,6 +195,10 @@ bool PROFILE::show(uint options)
MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("Context_involuntary", 10,
MYSQL_TYPE_LONG));
+#ifndef HAVE_GETRUSAGE
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
+ "Context-switch info not available on this platform");
+#endif
}
if (options & PROFILE_BLOCK_IO)
@@ -177,6 +207,10 @@ bool PROFILE::show(uint options)
MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("Block_ops_out", 10,
MYSQL_TYPE_LONG));
+#ifndef HAVE_GETRUSAGE
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
+ "Block I/O info not available on this platform");
+#endif
}
if (options & PROFILE_IPC)
@@ -185,6 +219,10 @@ bool PROFILE::show(uint options)
MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("Messages_received", 10,
MYSQL_TYPE_LONG));
+#ifndef HAVE_GETRUSAGE
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
+ "IPC info not available on this platform");
+#endif
}
if (options & PROFILE_PAGE_FAULTS)
@@ -193,11 +231,19 @@ bool PROFILE::show(uint options)
MYSQL_TYPE_LONG));
field_list.push_back(new Item_return_int("Page_faults_minor", 10,
MYSQL_TYPE_LONG));
+#ifndef HAVE_GETRUSAGE
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
+ "Page fault info not available on this platform");
+#endif
}
if (options & PROFILE_SWAPS)
{
field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG));
+#ifndef HAVE_GETRUSAGE
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR,
+ "Swap info not available on this platform");
+#endif
}
if(options & PROFILE_SOURCE)
@@ -236,46 +282,76 @@ bool PROFILE::show(uint options)
if (options & PROFILE_CPU)
{
+#ifdef HAVE_GETRUSAGE
protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_utime,
ps->rusage.ru_utime));
protocol->store((ulonglong)RUSAGE_DIFF_USEC(prof->rusage.ru_stime,
ps->rusage.ru_stime));
+#else
+ protocol->store_null();
+ protocol->store_null();
+#endif
}
if (options & PROFILE_CONTEXT)
{
+#ifdef HAVE_GETRUSAGE
protocol->store((uint32)(prof->rusage.ru_nvcsw - ps->rusage.ru_nvcsw));
protocol->store((uint32)(prof->rusage.ru_nivcsw - ps->rusage.ru_nivcsw));
+#else
+ protocol->store_null();
+ protocol->store_null();
+#endif
}
if (options & PROFILE_BLOCK_IO)
{
+#ifdef HAVE_GETRUSAGE
protocol->store((uint32)(prof->rusage.ru_inblock-ps->rusage.ru_inblock));
protocol->store((uint32)(prof->rusage.ru_oublock-ps->rusage.ru_oublock));
+#else
+ protocol->store_null();
+ protocol->store_null();
+#endif
}
if (options & PROFILE_IPC)
{
+#ifdef HAVE_GETRUSAGE
protocol->store((uint32)(prof->rusage.ru_msgsnd - ps->rusage.ru_msgsnd));
protocol->store((uint32)(prof->rusage.ru_msgrcv - ps->rusage.ru_msgrcv));
+#else
+ protocol->store_null();
+ protocol->store_null();
+#endif
}
if (options & PROFILE_PAGE_FAULTS)
{
+#ifdef HAVE_GETRUSAGE
protocol->store((uint32)(prof->rusage.ru_majflt - ps->rusage.ru_majflt));
protocol->store((uint32)(prof->rusage.ru_minflt - ps->rusage.ru_minflt));
+#else
+ protocol->store_null();
+ protocol->store_null();
+#endif
}
if (options & PROFILE_SWAPS)
{
+#ifdef HAVE_GETRUSAGE
protocol->store((uint32)(prof->rusage.ru_nswap - ps->rusage.ru_nswap));
+#else
+ protocol->store_null();
+#endif
}
if (options & PROFILE_SOURCE)
{
if(prof->function && prof->file)
{
- protocol->store(prof->function, strlen(prof->function), system_charset_info);
+ protocol->store(prof->function, strlen(prof->function),
+ system_charset_info);
protocol->store(prof->file, strlen(prof->file), system_charset_info);
protocol->store(prof->line);
} else {
@@ -293,67 +369,90 @@ bool PROFILE::show(uint options)
DBUG_RETURN(FALSE);
}
-/* XXX: enabled should be set to the current global profiling setting */
PROFILING::PROFILING()
- :enabled(1), keeping(1), current(NULL), last(NULL)
+ :keeping(1), current(NULL), last(NULL)
{
- init_sql_alloc(&root,
+ init_sql_alloc(&mem_root,
PROFILE_ALLOC_BLOCK_SIZE,
PROFILE_ALLOC_PREALLOC_SIZE);
}
PROFILING::~PROFILING()
{
- free_root(&root, MYF(0));
+ QUERY_PROFILE *prof;
+
+ List_iterator<QUERY_PROFILE> it(history);
+ while ((prof= it++) != NULL)
+ {
+ delete prof;
}
+ history.empty();
-void PROFILING::status(const char *status_arg,
+ if (current != NULL)
+ delete current;
+
+ free_root(&mem_root, MYF(0));
+}
+
+void PROFILING::status_change(const char *status_arg,
const char *function_arg,
const char *file_arg, unsigned int line_arg)
{
DBUG_ENTER("PROFILING::status");
- if(!current)
+ if (unlikely(current == NULL))
reset();
- if(unlikely(enabled))
+ DBUG_ASSERT(current != NULL);
+
+ if (unlikely((thd->options & OPTION_PROFILING) != 0))
current->status(status_arg, function_arg, file_arg, line_arg);
thd->proc_info= status_arg;
-
DBUG_VOID_RETURN;
}
void PROFILING::store()
{
- MEM_ROOT *old_root;
+ MEM_ROOT *saved_mem_root;
DBUG_ENTER("PROFILING::store");
- if (last && current && (last->query_id == current->query_id))
+ /* Already stored */
+ if (unlikely((last != NULL) &&
+ (current != NULL) &&
+ (last->profiling_query_id == current->profiling_query_id)))
DBUG_VOID_RETURN;
- if (history.elements > 10) /* XXX: global/session var */
+ if (history.elements > thd->variables.profiling_history_size)
{
- PROFILE *tmp= history.pop();
+ QUERY_PROFILE *tmp= history.pop();
delete tmp;
}
- old_root= thd->mem_root;
- thd->mem_root= &root;
+ /* Switch out memory roots so that we're sure that we keep what we need */
+ saved_mem_root= thd->mem_root;
+ thd->mem_root= &mem_root;
- if (current)
+ if (current != NULL)
+ {
+ if (keeping && (!current->entries.is_empty()))
{
- if (keeping && (!current->entries.is_empty())) {
- last= current;
+ last= current; /* never contains something that is not in the history. */
history.push_back(current);
current= NULL;
- } else {
+ }
+ else
+ {
delete current;
+ current= NULL;
}
}
- current= new PROFILE(this);
- thd->mem_root= old_root;
+ DBUG_ASSERT(current == NULL);
+ current= new QUERY_PROFILE(this, thd->query);
+
+ /* Restore memory root */
+ thd->mem_root= saved_mem_root;
DBUG_VOID_RETURN;
}
@@ -363,9 +462,9 @@ void PROFILING::reset()
DBUG_ENTER("PROFILING::reset");
store();
+ DBUG_ASSERT(current != NULL);
current->reset();
- /*free_root(&root, MYF(0));*/
keep();
DBUG_VOID_RETURN;
@@ -373,15 +472,15 @@ void PROFILING::reset()
bool PROFILING::show_profiles()
{
- PROFILE *prof;
+ DBUG_ENTER("PROFILING::show_profiles");
+ QUERY_PROFILE *prof;
List<Item> field_list;
- DBUG_ENTER("PROFILING::list_all");
field_list.push_back(new Item_return_int("Query_ID", 10,
MYSQL_TYPE_LONG));
- field_list.push_back(new Item_return_int("Time", 20,
+ field_list.push_back(new Item_return_int("Elapsed_usec", 20,
MYSQL_TYPE_LONGLONG));
- /* TODO: Add another field that lists the query. */
+ field_list.push_back(new Item_empty_string("Query", 40));
if (thd->protocol->send_fields(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -394,8 +493,8 @@ bool PROFILING::show_profiles()
unit->set_limit(sel);
- List_iterator<PROFILE> it(history);
- while ((prof= it++))
+ List_iterator<QUERY_PROFILE> it(history);
+ while ((prof= it++) != NULL)
{
PROFILE_ENTRY *ps= &prof->profile_start;
PROFILE_ENTRY *pe= prof->profile_end;
@@ -406,8 +505,12 @@ bool PROFILING::show_profiles()
break;
protocol->prepare_for_resend();
- protocol->store((uint32)(prof->query_id));
+ protocol->store((uint32)(prof->profiling_query_id));
protocol->store((ulonglong)((pe->time - ps->time)/10));
+ if (prof->query_source != NULL)
+ protocol->store(prof->query_source, strlen(prof->query_source), system_charset_info);
+ else
+ protocol->store_null();
if (protocol->write())
DBUG_RETURN(TRUE);
@@ -416,18 +519,19 @@ bool PROFILING::show_profiles()
DBUG_RETURN(FALSE);
}
-bool PROFILING::show(uint options, uint query_id)
+bool PROFILING::show(uint options, uint profiling_query_id)
{
DBUG_ENTER("PROFILING::show");
- PROFILE *prof;
+ QUERY_PROFILE *prof;
- List_iterator<PROFILE> it(history);
- while ((prof= it++))
+ List_iterator<QUERY_PROFILE> it(history);
+ while ((prof= it++) != NULL)
{
- if(prof->query_id == query_id)
- prof->show(options);
+ if(prof->profiling_query_id == profiling_query_id)
+ DBUG_RETURN(prof->show(options));
}
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "SHOW PROFILE");
DBUG_RETURN(TRUE);
}
@@ -439,3 +543,5 @@ bool PROFILING::show_last(uint options)
}
DBUG_RETURN(TRUE);
}
+
+#endif /* ENABLED_PROFILING */
--- 1.1/sql/sql_profile.h 2007-01-31 10:08:30 -05:00
+++ 1.2/sql/sql_profile.h 2007-01-31 10:08:30 -05:00
@@ -14,41 +14,56 @@
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
+#ifndef _SQL_PROFILE_H
+#define _SQL_PROFILE_H
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#if 1
-#define THD_PROC_INFO(thd, msg) do { if(unlikely((thd)->profiling.enabled)) { (thd)->profiling.status((msg), __FUNCTION__, __FILE__, __LINE__); } else { (thd)->proc_info= (msg); } } while (0)
+#if X__STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+# define __func__ __FUNCTION__
+# else
+# define __func__ _db_func_
+extern const char *_db_func_;
+# endif
+#elif defined(_MSC_VER)
+# if _MSC_VER < 1300
+# define __func__ _db_func_
+extern const char *_db_func_;
#else
-#define THD_PROC_INFO(thd, msg) do { (thd)->proc_info= (msg); } while (0)
+# define __func__ __FUNCTION__
+# endif
+#elif defined(__BORLANDC__)
+# define __func__ __FUNC__
+#else
+# define __func__ _db_func_
+extern const char *_db_func_;
#endif
-#if 0
- struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
- long ru_maxrss; /* integral max resident set size */
- long ru_ixrss; /* integral shared text memory size */
- long ru_idrss; /* integral unshared data size */
- long ru_isrss; /* integral unshared stack size */
- long ru_minflt; /* page reclaims */
- long ru_majflt; /* page faults */
- long ru_nswap; /* swaps */
- long ru_inblock; /* block input operations */
- long ru_oublock; /* block output operations */
- long ru_msgsnd; /* messages sent */
- long ru_msgrcv; /* messages received */
- long ru_nsignals; /* signals received */
- long ru_nvcsw; /* voluntary context switches */
- long ru_nivcsw; /* involuntary context switches */
- };
+#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
+
#define PROFILE_NONE 0
#define PROFILE_CPU 1
#define PROFILE_MEMORY 2
@@ -61,52 +76,62 @@
#define PROFILE_ALL 32767
class PROFILE_ENTRY;
-class PROFILE;
+class QUERY_PROFILE;
class PROFILING;
-/*
+
+/**
A single entry in a single profile.
*/
-
class PROFILE_ENTRY: public Sql_alloc
{
-public:
- PROFILE *profile;
+private:
+ friend class QUERY_PROFILE;
+ friend class PROFILING;
+
+ QUERY_PROFILE *profile;
char *status;
ulonglong time;
+#ifdef HAVE_GETRUSAGE
struct rusage rusage;
+#endif
char *function;
char *file;
unsigned int line;
+ void set_status(const char *status_arg);
+ void clean_up();
+
PROFILE_ENTRY();
- PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg);
- PROFILE_ENTRY(PROFILE *profile_arg, const char *status_arg,
+ 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 set_status(const char *status_arg);
void collect();
};
-/*
- The full profile for a single query. Includes multiple PROFILE_ENTRY
+
+/**
+ The full profile for a single query, and includes multiple PROFILE_ENTRY
objects.
*/
-
-class PROFILE: public Sql_alloc
+class QUERY_PROFILE: public Sql_alloc
{
-public:
- PROFILING *profiling;
- query_id_t query_id;
+private:
+ friend class PROFILING;
+
+ query_id_t profiling_query_id;
+ char *query_source;
PROFILE_ENTRY profile_start;
PROFILE_ENTRY *profile_end;
List<PROFILE_ENTRY> entries;
- PROFILE(PROFILING *profiling_arg);
- ~PROFILE();
+ PROFILING *profiling;
+
+ QUERY_PROFILE(PROFILING *profiling_arg, const char *query_source_ptr);
+ ~QUERY_PROFILE();
/* Add a profile status change to the current profile. */
void status(const char *status_arg,
@@ -120,68 +145,72 @@ public:
bool show(uint options);
};
-/*
- Profiling state for a single THD. Contains multiple PROFILE objects.
-*/
+/**
+ Profiling state for a single THD; contains multiple QUERY_PROFILE objects.
+*/
class PROFILING: public Sql_alloc
{
-public:
- MEM_ROOT root;
+private:
+ friend class PROFILE_ENTRY;
+ friend class QUERY_PROFILE;
+
+ MEM_ROOT mem_root;
THD *thd;
- bool enabled;
bool keeping;
- PROFILE *current;
- PROFILE *last;
- List<PROFILE> history;
+ QUERY_PROFILE *current;
+ QUERY_PROFILE *last;
+ List<QUERY_PROFILE> history;
+public:
PROFILING();
~PROFILING();
- inline void set_thd(THD *thd_arg) { thd= thd_arg; };
-
- /*
- Should we try to collect profiling information at all?
-
- If we disable profiling, we cannot later decide to turn it back
- on for the same query.
- */
- inline void enable() { enabled= 1; };
- inline void disable() { enabled= 0; };
+ /** 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.
+ 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= 1; };
- inline void discard() { keeping= 0; };
- void status(const char *status_arg,
- const char *function_arg,
- const char *file_arg, unsigned int line_arg);
+ /**
+ Do we intend to keep the currently collected profile?
+ @see keep()
+ */
+ inline void discard() { keeping= 0; };
- /* Stash this profile in the profile history. */
+ /** Stash this profile in the profile history. */
void store();
- /* Reset the current profile and state of profiling for the next query. */
- void reset();
+ /**
+ 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);
/* SHOW PROFILES */
bool show_profiles();
/* SHOW PROFILE FOR QUERY query_id */
- bool show(uint options, uint query_id);
+ bool show(uint options, uint profiling_query_id);
/* SHOW PROFILE */
bool show_last(uint options);
+
+ inline void set_thd(THD *thd_arg) { thd= thd_arg; };
};
-#endif /* SQL_PROFILE_H */
+# endif /* HAVE_PROFILING */
+#endif /* _SQL_PROFILE_H */
--- 1.175/sql/set_var.cc 2007-01-31 10:08:30 -05:00
+++ 1.176/sql/set_var.cc 2007-01-31 10:08:30 -05:00
@@ -545,6 +545,12 @@ static sys_var_thd_bit sys_unique_checks
set_option_bit,
OPTION_RELAXED_UNIQUE_CHECKS,
1);
+#ifdef ENABLED_PROFILING
+static sys_var_thd_bit sys_profiling("profiling", NULL, set_option_bit,
+ ulonglong(OPTION_PROFILING));
+sys_var_thd_ulong sys_profiling_history_size("profiling_history_size",
+ &SV::profiling_history_size);
+#endif
/* Local state variables */
@@ -696,6 +702,10 @@ sys_var *sys_variables[]=
&sys_optimizer_prune_level,
&sys_optimizer_search_depth,
&sys_preload_buff_size,
+#ifdef ENABLED_PROFILING
+ &sys_profiling,
+ &sys_profiling_history_size,
+#endif
&sys_pseudo_thread_id,
&sys_query_alloc_block_size,
&sys_query_cache_size,
@@ -1003,6 +1013,10 @@ struct show_var_st init_vars[]= {
{"pid_file", (char*) pidfile_name, SHOW_CHAR},
{"port", (char*) &mysqld_port, SHOW_INT},
{sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
+#ifdef ENABLED_PROFILING
+ {sys_profiling.name, (char*) &sys_profiling, SHOW_SYS},
+ {sys_profiling_history_size.name, (char*) &sys_profiling_history_size, SHOW_SYS},
+#endif
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size,
SHOW_SYS},
--- 1.80/sql/set_var.h 2007-01-31 10:08:30 -05:00
+++ 1.81/sql/set_var.h 2007-01-31 10:08:30 -05:00
@@ -457,11 +457,11 @@ class sys_var_thd_bit :public sys_var_th
sys_check_func check_func;
sys_update_func update_func;
public:
- ulong bit_flag;
+ ulonglong bit_flag;
bool reverse;
sys_var_thd_bit(const char *name_arg,
sys_check_func c_func, sys_update_func u_func,
- ulong bit, bool reverse_arg=0)
+ ulonglong bit, bool reverse_arg=0)
:sys_var_thd(name_arg), check_func(c_func), update_func(u_func),
bit_flag(bit), reverse(reverse_arg)
{}
| Thread |
|---|
| • bk commit into 5.0 tree (cmiller:1.2384) BUG#24795 | Chad MILLER | 31 Jan |