From d8426b744473952ce1f88f10d97de01632e3b559 Mon Sep 17 00:00:00 2001 From: Przemek Skibinski Date: Fri, 2 Nov 2018 16:24:16 +0100 Subject: [PATCH] PS-4790: Improve user statistics accuracy Currently userstat measures times for mysql_parse, mysqld_stmt_reset, mysqld_stmt_fetch, mysqld_stmt_prepare, mysqld_stmt_execute. MariaDB measures times only for `mysql_parse` and `dispatch_command` which call above functions. Moreover MariaDB adds measurements for COM_INIT_DB, COM_REGISTER_SLAVE, COM_RESET_CONNECTION, and other in `dispatch_command`. It makes measurements of BUSY_TIME and CPU_TIME more accurate. This patch implements a similar solution that measures times only for `dispatch_command` and `mysql_parse` using newly created `sql/userstat.cc` and `sql/userstat.h`. --- libmysqld/CMakeLists.txt | 3 +- mysql-test/r/percona_userstat.result | 8 +- sql/CMakeLists.txt | 2 +- sql/log_event.cc | 3 +- sql/sql_parse.cc | 110 +++------ sql/sql_parse.h | 2 +- sql/sql_prepare.cc | 320 --------------------------- sql/userstat.cc | 98 ++++++++ sql/userstat.h | 25 +++ 9 files changed, 167 insertions(+), 404 deletions(-) create mode 100644 sql/userstat.cc create mode 100644 sql/userstat.h diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index fd7b2552c34c..36314df0cb46 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -79,7 +79,8 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/sql_trigger.cc ../sql/sql_udf.cc ../sql/sql_union.cc ../sql/sql_update.cc ../sql/sql_view.cc ../sql/sql_profile.cc ../sql/strfunc.cc ../sql/table.cc ../sql/thr_malloc.cc - ../sql/sql_time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc + ../sql/sql_time.cc ../sql/tztime.cc ../sql/userstat.cc + ../sql/uniques.cc ../sql/unireg.cc ../sql/partition_info.cc ../sql/sql_connect.cc ../sql/scheduler.cc ../sql/sql_audit.cc ../sql/sql_alter.cc ../sql/sql_partition_admin.cc diff --git a/mysql-test/r/percona_userstat.result b/mysql-test/r/percona_userstat.result index 660e55fce058..3bba1bcf1338 100644 --- a/mysql-test/r/percona_userstat.result +++ b/mysql-test/r/percona_userstat.result @@ -41,7 +41,7 @@ SET @thread_statistics_old= @@thread_statistics; SET GLOBAL thread_statistics=ON; SELECT * FROM INFORMATION_SCHEMA.CLIENT_STATISTICS; CLIENT TOTAL_CONNECTIONS CONCURRENT_CONNECTIONS CONNECTED_TIME BUSY_TIME CPU_TIME BYTES_RECEIVED BYTES_SENT BINLOG_BYTES_WRITTEN ROWS_FETCHED ROWS_UPDATED TABLE_ROWS_READ SELECT_COMMANDS UPDATE_COMMANDS OTHER_COMMANDS COMMIT_TRANSACTIONS ROLLBACK_TRANSACTIONS DENIED_CONNECTIONS LOST_CONNECTIONS ACCESS_DENIED EMPTY_QUERIES TOTAL_SSL_CONNECTIONS -localhost 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 88 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 +localhost 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 36 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 SELECT * FROM INFORMATION_SCHEMA.INDEX_STATISTICS; TABLE_SCHEMA TABLE_NAME INDEX_NAME ROWS_READ SELECT * FROM INFORMATION_SCHEMA.TABLE_STATISTICS; @@ -51,10 +51,10 @@ THREAD_ID TOTAL_CONNECTIONS CONCURRENT_CONNECTIONS CONNECTED_TIME BUSY_TIME CPU_ THREAD_ID 1 0 CONNECTED_TIME BUSY_TIME CPU_TIME 163 0 0 1 0 0 3 0 0 0 0 0 0 0 2 0 SELECT * FROM INFORMATION_SCHEMA.USER_STATISTICS; USER TOTAL_CONNECTIONS CONCURRENT_CONNECTIONS CONNECTED_TIME BUSY_TIME CPU_TIME BYTES_RECEIVED BYTES_SENT BINLOG_BYTES_WRITTEN ROWS_FETCHED ROWS_UPDATED TABLE_ROWS_READ SELECT_COMMANDS UPDATE_COMMANDS OTHER_COMMANDS COMMIT_TRANSACTIONS ROLLBACK_TRANSACTIONS DENIED_CONNECTIONS LOST_CONNECTIONS ACCESS_DENIED EMPTY_QUERIES TOTAL_SSL_CONNECTIONS -root 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 306 0 0 2 0 0 4 0 2 0 0 0 0 0 2 0 +root 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 254 0 0 2 0 0 4 0 1 0 0 0 0 0 2 0 SHOW CLIENT_STATISTICS; Client Total_connections Concurrent_connections Connected_time Busy_time Cpu_time Bytes_received Bytes_sent Binlog_bytes_written Rows_fetched Rows_updated Table_rows_read Select_commands Update_commands Other_commands Commit_transactions Rollback_transactions Denied_connections Lost_connections Access_denied Empty_queries Total_ssl_connections -localhost 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 359 0 0 3 0 0 5 0 2 0 0 0 0 0 2 0 +localhost 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 307 0 0 3 0 0 5 0 1 0 0 0 0 0 2 0 SHOW INDEX_STATISTICS; Table_schema Table_name Index_name Rows_read SHOW TABLE_STATISTICS; @@ -64,7 +64,7 @@ Thread_id Total_connections Concurrent_connections Connected_time Busy_time Cpu_ THREAD_ID 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 350 0 0 4 0 0 8 0 0 0 0 0 0 0 4 0 SHOW USER_STATISTICS; User Total_connections Concurrent_connections Connected_time Busy_time Cpu_time Bytes_received Bytes_sent Binlog_bytes_written Rows_fetched Rows_updated Table_rows_read Select_commands Update_commands Other_commands Commit_transactions Rollback_transactions Denied_connections Lost_connections Access_denied Empty_queries Total_ssl_connections -root 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 465 0 0 5 0 0 9 0 2 0 0 0 0 0 4 0 +root 1 CONNECTED_TIME BUSY_TIME CPU_TIME 0 413 0 0 5 0 0 9 0 1 0 0 0 0 0 4 0 SET GLOBAL thread_statistics= @thread_statistics_old; CREATE TABLE t1 (id int(10), PRIMARY KEY (id)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 33becb58b2a9..23406b79d72a 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -68,7 +68,7 @@ SET (SQL_SOURCE sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc - sql_time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc + sql_time.cc tztime.cc userstat.cc uniques.cc unireg.cc item_xmlfunc.cc rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc event_queue.cc event_db_repository.cc sql_tablespace.cc events.cc ../sql-common/my_user.c diff --git a/sql/log_event.cc b/sql/log_event.cc index 3cada3048fd2..9b822530c34a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3572,7 +3572,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, Parser_state parser_state; if (!parser_state.init(thd, thd->query(), thd->query_length())) { - mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + mysql_parse(thd, thd->query(), thd->query_length(), + &parser_state, true); /* Finalize server status flags after executing a statement. */ thd->update_server_status(); log_slow_statement(thd); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3447a0256525..35743c424248 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -98,6 +98,7 @@ #include "debug_sync.h" #include "probes_mysql.h" #include "set_var.h" +#include "userstat.h" #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -570,7 +571,7 @@ static void handle_bootstrap_impl(THD *thd) break; } - mysql_parse(thd, thd->query(), length, &parser_state); + mysql_parse(thd, thd->query(), length, &parser_state, true); bootstrap_error= thd->is_error(); thd->protocol->end_statement(); @@ -965,6 +966,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (!(server_command_flags[command] & CF_SKIP_QUESTIONS)) statistic_increment(thd->status_var.questions, &LOCK_status); + /* Declare userstat variables and start timer */ + double start_busy_usecs = 0.0; + double start_cpu_nsecs = 0.0; + if (unlikely(opt_userstat)) + userstat_start_timer(&start_busy_usecs, &start_cpu_nsecs); + /** Clear the set of flags that are expected to be cleared at the beginning of each command. @@ -1109,7 +1116,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (parser_state.init(thd, thd->query(), thd->query_length())) break; - mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); + mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, false); while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && ! thd->is_error()) @@ -1164,7 +1171,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->set_time(); /* Reset the query start time. */ parser_state.reset(beginning_of_next_stmt, length); /* TODO: set thd->lex->sql_command to SQLCOM_END here */ - mysql_parse(thd, beginning_of_next_stmt, length, &parser_state); + mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, false); } DBUG_PRINT("info",("query ready")); @@ -1495,6 +1502,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (thd->open_tables == NULL || (thd->locked_tables_mode == LTM_LOCK_TABLES))); + /* Update user statistics only if at least one timer was initialized */ + if (unlikely(start_busy_usecs > 0.0 || start_cpu_nsecs > 0.0)) + { + userstat_finish_timer(start_busy_usecs, start_cpu_nsecs, &thd->busy_time, + &thd->cpu_time); + /* Updates THD stats and the global user stats. */ + thd->update_stats(true); +#ifndef EMBEDDED_LIBRARY + update_global_user_stats(thd, true, time(NULL)); +#endif + } + /* Finalize server status flags after executing a command. */ thd->update_server_status(); thd->protocol->end_statement(); @@ -6010,7 +6029,7 @@ void mysql_init_multi_delete(LEX *lex) */ void mysql_parse(THD *thd, char *rawbuf, uint length, - Parser_state *parser_state) + Parser_state *parser_state, bool update_userstat) { int error __attribute__((unused)); DBUG_ENTER("mysql_parse"); @@ -6036,33 +6055,11 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, lex_start(thd); mysql_reset_thd_for_next_command(thd); - int start_time_error= 0; - int end_time_error= 0; - struct timeval start_time, end_time; - double start_usecs= 0; - double end_usecs= 0; - /* cpu time */ - int cputime_error= 0; -#ifdef HAVE_CLOCK_GETTIME - struct timespec tp; -#endif - double start_cpu_nsecs= 0; - double end_cpu_nsecs= 0; - - if (opt_userstat) - { -#ifdef HAVE_CLOCK_GETTIME - /* get start cputime */ - if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - - // Gets the start time, in order to measure how long this command takes. - if (!(start_time_error = gettimeofday(&start_time, NULL))) - { - start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; - } - } + /* Declare userstat variables and start timer */ + double start_busy_usecs = 0.0; + double start_cpu_nsecs = 0.0; + if (unlikely(opt_userstat && update_userstat)) + userstat_start_timer(&start_busy_usecs, &start_cpu_nsecs); if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) { @@ -6134,52 +6131,13 @@ void mysql_parse(THD *thd, char *rawbuf, uint length, DBUG_ASSERT(thd->change_list.is_empty()); } - if (opt_userstat) - { - // Gets the end time. - if (!(end_time_error= gettimeofday(&end_time, NULL))) - { - end_usecs= end_time.tv_sec * 1000000.0 + end_time.tv_usec; - } - - // Calculates the difference between the end and start times. - if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) - { - thd->busy_time= (end_usecs - start_usecs) / 1000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->busy_time > 2629743) - { - thd->busy_time= 0; - } - } - else - { - // end time went back in time, or gettimeofday() failed. - thd->busy_time= 0; - } - -#ifdef HAVE_CLOCK_GETTIME - /* get end cputime */ - if (!cputime_error && - !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - if (start_cpu_nsecs && !cputime_error) - { - thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->cpu_time > 2629743) - { - thd->cpu_time = 0; - } - } - else - thd->cpu_time = 0; - } - - // Updates THD stats and the global user stats. - if (unlikely(opt_userstat)) + /* Update user statistics only if at least one timer was initialized */ + if (unlikely(update_userstat && + (start_busy_usecs > 0.0 || start_cpu_nsecs > 0.0))) { + userstat_finish_timer(start_busy_usecs, start_cpu_nsecs, &thd->busy_time, + &thd->cpu_time); + /* Updates THD stats and the global user stats. */ thd->update_stats(true); #ifndef EMBEDDED_LIBRARY update_global_user_stats(thd, true, time(NULL)); diff --git a/sql/sql_parse.h b/sql/sql_parse.h index f7b4d5305439..1245f660c934 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -87,7 +87,7 @@ bool is_log_table_write_query(enum enum_sql_command command); bool alloc_query(THD *thd, const char *packet, uint packet_length); void mysql_init_select(LEX *lex); void mysql_parse(THD *thd, char *rawbuf, uint length, - Parser_state *parser_state); + Parser_state *parser_state, bool update_userstat); void mysql_reset_thd_for_next_command(THD *thd); bool mysql_new_select(LEX *lex, bool move_down); void create_select_for_variable(const char *var_name); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a05f6a041970..8165be007c11 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2188,34 +2188,6 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - int start_time_error= 0; - int end_time_error= 0; - struct timeval start_time, end_time; - double start_usecs= 0; - double end_usecs= 0; - /* cpu time */ - int cputime_error= 0; -#ifdef HAVE_CLOCK_GETTIME - struct timespec tp; -#endif - double start_cpu_nsecs= 0; - double end_cpu_nsecs= 0; - - if (unlikely(opt_userstat)) - { -#ifdef HAVE_CLOCK_GETTIME - /* get start cputime */ - if (!(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - start_cpu_nsecs= tp.tv_sec * 1000000000.0 + tp.tv_nsec; -#endif - - // Gets the start time, in order to measure how long this command takes. - if (!(start_time_error= gettimeofday(&start_time, NULL))) - { - start_usecs= start_time.tv_sec * 1000000.0 + start_time.tv_usec; - } - } - if (! (stmt= new Prepared_statement(thd))) goto end; /* out of memory: error is set in Sql_alloc */ @@ -2241,60 +2213,7 @@ void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length) sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); - /* check_prepared_statemnt sends the metadata packet in case of success */ end: - if (unlikely(opt_userstat)) - { - // Gets the end time. - if (!(end_time_error= gettimeofday(&end_time, NULL))) - { - end_usecs= end_time.tv_sec * 1000000.0 + end_time.tv_usec; - } - - // Calculates the difference between the end and start times. - if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) - { - thd->busy_time= (end_usecs - start_usecs) / 1000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->busy_time > 2629743) - { - thd->busy_time= 0; - } - } - else - { - // end time went back in time, or gettimeofday() failed. - thd->busy_time= 0; - } - -#ifdef HAVE_CLOCK_GETTIME - /* get end cputime */ - if (!cputime_error && - !(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - end_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - if (start_cpu_nsecs && !cputime_error) - { - thd->cpu_time= (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->cpu_time > 2629743) - { - thd->cpu_time= 0; - } - } - else - thd->cpu_time = 0; - } - - // Updates THD stats and the global user stats. - if (unlikely(opt_userstat)) - { - thd->update_stats(true); -#ifndef EMBEDDED_LIBRARY - update_global_user_stats(thd, true, time(NULL)); -#endif - } - DBUG_VOID_RETURN; } @@ -2647,34 +2566,6 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - int start_time_error= 0; - int end_time_error= 0; - struct timeval start_time, end_time; - double start_usecs= 0; - double end_usecs= 0; - /* cpu time */ - int cputime_error= 0; -#ifdef HAVE_CLOCK_GETTIME - struct timespec tp; -#endif - double start_cpu_nsecs= 0; - double end_cpu_nsecs= 0; - - if (opt_userstat) - { -#ifdef HAVE_CLOCK_GETTIME - /* get start cputime */ - if (!(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - start_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - - // Gets the start time, in order to measure how long this command takes. - if (!(start_time_error = gettimeofday(&start_time, NULL))) - { - start_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; - } - } - if (!(stmt= find_prepared_statement(thd, stmt_id))) { char llbuf[22]; @@ -2702,58 +2593,6 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio);); end: - if (opt_userstat) - { - // Gets the end time. - if (!(end_time_error= gettimeofday(&end_time, NULL))) - { - end_usecs= end_time.tv_sec * 1000000.0 + end_time.tv_usec; - } - - // Calculates the difference between the end and start times. - if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) - { - thd->busy_time= (end_usecs - start_usecs) / 1000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->busy_time > 2629743) - { - thd->busy_time= 0; - } - } - else - { - // end time went back in time, or gettimeofday() failed. - thd->busy_time= 0; - } - -#ifdef HAVE_CLOCK_GETTIME - /* get end cputime */ - if (!cputime_error && - !(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - end_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - if (start_cpu_nsecs && !cputime_error) - { - thd->cpu_time= (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->cpu_time > 2629743) - { - thd->cpu_time= 0; - } - } - else - thd->cpu_time = 0; - } - - // Updates THD stats and the global user stats. - if (unlikely(opt_userstat)) - { - thd->update_stats(true); -#ifndef EMBEDDED_LIBRARY - update_global_user_stats(thd, true, time(NULL)); -#endif - } - DBUG_VOID_RETURN; } @@ -2827,34 +2666,6 @@ void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - int start_time_error= 0; - int end_time_error= 0; - struct timeval start_time, end_time; - double start_usecs= 0; - double end_usecs= 0; - /* cpu time */ - int cputime_error= 0; -#ifdef HAVE_CLOCK_GETTIME - struct timespec tp; -#endif - double start_cpu_nsecs= 0; - double end_cpu_nsecs= 0; - - if (opt_userstat) - { -#ifdef HAVE_CLOCK_GETTIME - /* get start cputime */ - if (!(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - start_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - - // Gets the start time, in order to measure how long this command takes. - if (!(start_time_error= gettimeofday(&start_time, NULL))) - { - start_usecs= start_time.tv_sec * 1000000.0 + start_time.tv_usec; - } - } - status_var_increment(thd->status_var.com_stmt_fetch); if (!(stmt= find_prepared_statement(thd, stmt_id))) { @@ -2886,57 +2697,6 @@ void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length) thd->stmt_arena= thd; end: - if (opt_userstat) - { - // Gets the end time. - if (!(end_time_error = gettimeofday(&end_time, NULL))) - { - end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; - } - - // Calculates the difference between the end and start times. - if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) - { - thd->busy_time= (end_usecs - start_usecs) / 1000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->busy_time > 2629743) - { - thd->busy_time= 0; - } - } - else - { - // end time went back in time, or gettimeofday() failed. - thd->busy_time= 0; - } - -#ifdef HAVE_CLOCK_GETTIME - /* get end cputime */ - if (!cputime_error && - !(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - end_cpu_nsecs= tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - if (start_cpu_nsecs && !cputime_error) - { - thd->cpu_time= (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->cpu_time > 2629743) - { - thd->cpu_time= 0; - } - } else - thd->cpu_time= 0; - } - - // Updates THD stats and the global user stats. - if (unlikely(opt_userstat)) - { - thd->update_stats(true); -#ifndef EMBEDDED_LIBRARY - update_global_user_stats(thd, true, time(NULL)); -#endif - } - DBUG_VOID_RETURN; } @@ -2967,34 +2727,6 @@ void mysqld_stmt_reset(THD *thd, char *packet) /* First of all clear possible warnings from the previous command */ mysql_reset_thd_for_next_command(thd); - int start_time_error= 0; - int end_time_error= 0; - struct timeval start_time, end_time; - double start_usecs= 0; - double end_usecs= 0; - /* cpu time */ - int cputime_error= 0; -#ifdef HAVE_CLOCK_GETTIME - struct timespec tp; -#endif - double start_cpu_nsecs= 0; - double end_cpu_nsecs= 0; - - if (opt_userstat) - { -#ifdef HAVE_CLOCK_GETTIME - /* get start cputime */ - if (!(cputime_error= clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - start_cpu_nsecs= tp.tv_sec * 1000000000.0+tp.tv_nsec; -#endif - - // Gets the start time, in order to measure how long this command takes. - if (!(start_time_error= gettimeofday(&start_time, NULL))) - { - start_usecs= start_time.tv_sec * 1000000.0 + start_time.tv_usec; - } - } - status_var_increment(thd->status_var.com_stmt_reset); if (!(stmt= find_prepared_statement(thd, stmt_id))) { @@ -3019,58 +2751,6 @@ void mysqld_stmt_reset(THD *thd, char *packet) my_ok(thd); end: - if (opt_userstat) - { - // Gets the end time. - if (!(end_time_error = gettimeofday(&end_time, NULL))) - { - end_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; - } - - // Calculates the difference between the end and start times. - if (start_usecs && end_usecs >= start_usecs && !start_time_error && !end_time_error) - { - thd->busy_time= (end_usecs - start_usecs) / 1000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->busy_time > 2629743) - { - thd->busy_time= 0; - } - } - else - { - // end time went back in time, or gettimeofday() failed. - thd->busy_time= 0; - } - -#ifdef HAVE_CLOCK_GETTIME - /* get end cputime */ - if (!cputime_error && - !(cputime_error = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp))) - end_cpu_nsecs = tp.tv_sec*1000000000.0+tp.tv_nsec; -#endif - if (start_cpu_nsecs && !cputime_error) - { - thd->cpu_time = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000; - // In case there are bad values, 2629743 is the #seconds in a month. - if (thd->cpu_time > 2629743) - { - thd->cpu_time= 0; - } - } - else - thd->cpu_time= 0; - } - - // Updates THD stats and the global user stats. - if (unlikely(opt_userstat)) - { - thd->update_stats(true); -#ifndef EMBEDDED_LIBRARY - update_global_user_stats(thd, true, time(NULL)); -#endif - } - DBUG_VOID_RETURN; } diff --git a/sql/userstat.cc b/sql/userstat.cc new file mode 100644 index 000000000000..8d1cff87502e --- /dev/null +++ b/sql/userstat.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2018 Percona LLC and/or its affiliates. All rights reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "my_config.h" + +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include "my_global.h" // unlikely +#include "userstat.h" + +/** + Get start timers for cpu_time and busy_time. + + @return start_busy_usecs Start value of busy_time or 0.0 in case of error + @return start_cpu_nsecs Start value of cpu_time or 0.0 in case of error +*/ +void userstat_start_timer(double *start_busy_usecs, + double *start_cpu_nsecs) +{ + *start_busy_usecs = 0.0; + *start_cpu_nsecs = 0.0; + +#ifdef HAVE_CLOCK_GETTIME + /* Get start cputime */ + struct timespec tp; + if (!clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)) + *start_cpu_nsecs = tp.tv_sec * 1000000000.0 + tp.tv_nsec; +#endif + + /* Gets the start time, in order to measure how long this command takes. */ + struct timeval start_time; + if (!gettimeofday(&start_time, NULL)) + *start_busy_usecs = start_time.tv_sec * 1000000.0 + start_time.tv_usec; +} + +/** + Get interval time for cpu_time and busy_time between calls to + userstat_start_timer() and this function. + + @param start_busy_usecs Start value of busy_time or 0.0 in case of error + @param start_cpu_nsecs Start value of cpu_time or 0.0 in case of error + @return busy_sec Interval time for busy_time in seconds or 0.0 in + case of error + @return cpu_sec Interval time for cpu_time in seconds or 0.0 in case + of error +*/ +void userstat_finish_timer(double start_busy_usecs, double start_cpu_nsecs, + double *busy_sec, double *cpu_sec) +{ + *busy_sec = 0.0; + *cpu_sec = 0.0; + + /* Gets the end time. */ + struct timeval end_time; + double end_busy_usecs = 0.0; + if (start_busy_usecs > 0.0 && !gettimeofday(&end_time, NULL)) + end_busy_usecs = end_time.tv_sec * 1000000.0 + end_time.tv_usec; + + /* Calculates the difference between the end and start times. */ + if (end_busy_usecs > start_busy_usecs) { + *busy_sec = (end_busy_usecs - start_busy_usecs) / 1000000.0; + /* In case there are bad values, 2629743 is the #seconds in a month. */ + if (unlikely(*busy_sec > 2629743.0)) { + *busy_sec = 0.0; + } + } + +#ifdef HAVE_CLOCK_GETTIME + /* Get end cputime */ + struct timespec tp; + double end_cpu_nsecs = 0.0; + if (start_cpu_nsecs > 0.0 && !clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)) + end_cpu_nsecs = tp.tv_sec * 1000000000.0 + tp.tv_nsec; +#endif + + if (end_cpu_nsecs > start_cpu_nsecs) { + *cpu_sec = (end_cpu_nsecs - start_cpu_nsecs) / 1000000000.0; + /* In case there are bad values, 2629743 is the #seconds in a month. */ + if (unlikely(*cpu_sec > 2629743.0)) { + *cpu_sec = 0.0; + } + } +} diff --git a/sql/userstat.h b/sql/userstat.h new file mode 100644 index 000000000000..4319860cc4ef --- /dev/null +++ b/sql/userstat.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2018 Percona LLC and/or its affiliates. All rights reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef USERSTAT_INCLUDED +#define USERSTAT_INCLUDED + +void userstat_start_timer(double *start_busy_usecs, + double *start_cpu_nsecs); +void userstat_finish_timer(double start_busy_usecs, double start_cpu_nsecs, + double *busy_sec, double *cpu_sec); + +#endif