diff options
Diffstat (limited to 'sql/sql_profile.cc')
-rw-r--r-- | sql/sql_profile.cc | 804 |
1 files changed, 804 insertions, 0 deletions
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc new file mode 100644 index 00000000000..77dea4f9954 --- /dev/null +++ b/sql/sql_profile.cc @@ -0,0 +1,804 @@ +/* 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 */ + + +#include "mysql_priv.h" +#include "my_sys.h" + +#define TIME_FLOAT_DIGITS 9 +#define MAX_QUERY_LENGTH 300 + +bool schema_table_store_record(THD *thd, TABLE *table); + +/* Reserved for systems that can't record the function name in source. */ +const char * const _unknown_func_ = "<unknown>"; + +/** + Connects Information_Schema and Profiling. +*/ +int fill_query_profile_statistics_info(THD *thd, struct st_table_list *tables, + Item *cond) +{ +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + return(thd->profiling.fill_statistics_info(thd, tables, cond)); +#else + return(1); +#endif +} + +ST_FIELD_INFO query_profile_statistics_info[]= +{ + /* name, length, type, value, maybe_null, old_name */ + {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, NULL}, + {"STATE", 30, MYSQL_TYPE_STRING, 0, false, NULL}, + {"DURATION", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, false, NULL}, + {"CPU_USER", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CPU_SYSTEM", TIME_FLOAT_DIGITS, MYSQL_TYPE_DOUBLE, 0, true, NULL}, + {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, NULL}, + {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, NULL}, + {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, NULL}, + {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL} +}; + +#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) + +#define RUSAGE_USEC(tv) ((tv).tv_sec*1000*1000 + (tv).tv_usec) +#define RUSAGE_DIFF_USEC(tv1, tv2) (RUSAGE_USEC((tv1))-RUSAGE_USEC((tv2))) + +PROFILE_ENTRY::PROFILE_ENTRY() + :profile(NULL), status(NULL), function(NULL), file(NULL), line(0), + time_usecs(0.0), allocated_status_memory(NULL) +{ + collect(); + + /* The beginning of the query, before any state is set. */ + set_status("(initialization)", NULL, NULL, 0); +} + +PROFILE_ENTRY::PROFILE_ENTRY(QUERY_PROFILE *profile_arg, const char *status_arg) + :profile(profile_arg) +{ + collect(); + set_status(status_arg, NULL, NULL, 0); +} + +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) +{ + collect(); + set_status(status_arg, function_arg, file_arg, line_arg); +} + +PROFILE_ENTRY::~PROFILE_ENTRY() +{ + if (allocated_status_memory != NULL) + my_free(allocated_status_memory, MYF(0)); + status= function= file= NULL; +} + +void PROFILE_ENTRY::set_status(const char *status_arg, const char *function_arg, const char *file_arg, unsigned int line_arg) +{ + size_t sizes[3]; /* 3 == status+function+file */ + char *cursor; + + /* + Compute all the space we'll need to allocate one block for everything + we'll need, instead of N mallocs. + */ + sizes[0]= (status_arg == NULL) ? 0 : strlen(status_arg) + 1; + sizes[1]= (function_arg == NULL) ? 0 : strlen(function_arg) + 1; + sizes[2]= (file_arg == NULL) ? 0 : strlen(file_arg) + 1; + + allocated_status_memory= (char *) my_malloc(sizes[0] + sizes[1] + sizes[2], MYF(0)); + DBUG_ASSERT(allocated_status_memory != NULL); + + cursor= allocated_status_memory; + + if (status_arg != NULL) + { + strcpy(cursor, status_arg); + status= cursor; + cursor+= sizes[0]; + } + else + status= NULL; + + if (function_arg != NULL) + { + strcpy(cursor, function_arg); + function= cursor; + cursor+= sizes[1]; + } + else + function= NULL; + + if (file_arg != NULL) + { + strcpy(cursor, file_arg); + file= cursor; + cursor+= sizes[2]; + } + else + file= NULL; + + line= line_arg; +} + +void PROFILE_ENTRY::collect() +{ + time_usecs= (double) my_getsystime() / 10.0; /* 1 sec was 1e7, now is 1e6 */ +#ifdef HAVE_GETRUSAGE + getrusage(RUSAGE_SELF, &rusage); +#endif +} + +QUERY_PROFILE::QUERY_PROFILE(PROFILING *profiling_arg, char *query_source_arg, + uint query_length_arg) + :profiling(profiling_arg), server_query_id(0), profiling_query_id(0), + query_source(NULL) +{ + profile_end= &profile_start; + set_query_source(query_source_arg, query_length_arg); +} + +void QUERY_PROFILE::set_query_source(char *query_source_arg, + uint query_length_arg) +{ + if (! profiling->enabled) + return; + + /* Truncate to avoid DoS attacks. */ + uint length= min(MAX_QUERY_LENGTH, query_length_arg); + /* TODO?: Provide a way to include the full text, as in SHOW PROCESSLIST. */ + + DBUG_ASSERT(query_source == NULL); + if (query_source_arg != NULL) + query_source= my_strdup_with_length(query_source_arg, length, MYF(0)); +} + +QUERY_PROFILE::~QUERY_PROFILE() +{ + while (! entries.is_empty()) + delete entries.pop(); + + if (query_source != NULL) + my_free(query_source, MYF(0)); +} + +void QUERY_PROFILE::status(const char *status_arg, + const char *function_arg= NULL, + const char *file_arg= NULL, unsigned int line_arg= 0) +{ + THD *thd= profiling->thd; + PROFILE_ENTRY *prof; + DBUG_ENTER("QUERY_PROFILE::status"); + + /* Blank status. Just return, and thd->proc_info will be set blank later. */ + if (unlikely(status_arg == NULL)) + DBUG_VOID_RETURN; + + /* If thd->proc_info is currently set to status_arg, don't profile twice. */ + 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 != server_query_id) && !thd->spcont)) + reset(); + + 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 + { + if ((profile_end= prof= new PROFILE_ENTRY(this, status_arg))) + entries.push_back(prof); + } + + DBUG_VOID_RETURN; +} + +void QUERY_PROFILE::reset() +{ + DBUG_ENTER("QUERY_PROFILE::reset"); + if (likely(profiling->thd->query_id != server_query_id)) + { + server_query_id= profiling->thd->query_id; /* despite name, is global */ + profile_start.collect(); + + while (! entries.is_empty()) + delete entries.pop(); + } + DBUG_VOID_RETURN; +} + +bool QUERY_PROFILE::show(uint options) +{ + THD *thd= profiling->thd; + List<Item> field_list; + 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("Duration", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); + + if (options & PROFILE_CPU) + { + field_list.push_back(new Item_return_int("CPU_user", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); + field_list.push_back(new Item_return_int("CPU_system", TIME_FLOAT_DIGITS, + MYSQL_TYPE_DOUBLE)); + } + + if (options & PROFILE_MEMORY) + { + } + + if (options & PROFILE_CONTEXT) + { + field_list.push_back(new Item_return_int("Context_voluntary", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Context_involuntary", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_BLOCK_IO) + { + field_list.push_back(new Item_return_int("Block_ops_in", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Block_ops_out", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_IPC) + { + field_list.push_back(new Item_return_int("Messages_sent", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Messages_received", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_PAGE_FAULTS) + { + field_list.push_back(new Item_return_int("Page_faults_major", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Page_faults_minor", 10, + MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_SWAPS) + { + field_list.push_back(new Item_return_int("Swaps", 10, MYSQL_TYPE_LONG)); + } + + if (options & PROFILE_SOURCE) + { + field_list.push_back(new Item_empty_string("Source_function", + MYSQL_ERRMSG_SIZE)); + field_list.push_back(new Item_empty_string("Source_file", + MYSQL_ERRMSG_SIZE)); + field_list.push_back(new Item_return_int("Source_line", 10, + MYSQL_TYPE_LONG)); + } + + if (thd->protocol->send_fields(&field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + DBUG_RETURN(TRUE); + + Protocol *protocol= thd->protocol; + SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX_UNIT *unit= &thd->lex->unit; + ha_rows idx= 0; + unit->set_limit(sel); + PROFILE_ENTRY *previous= &profile_start; + + PROFILE_ENTRY *entry; + void *iterator; + for (iterator= entries.new_iterator(); + iterator != NULL; + iterator= entries.iterator_next(iterator)) + { + entry= entries.iterator_value(iterator); + +#ifdef HAVE_GETRUSAGE + struct rusage *rusage= &(entry->rusage); +#endif + String elapsed; + + if (++idx <= unit->offset_limit_cnt) + continue; + if (idx > unit->select_limit_cnt) + break; + + protocol->prepare_for_resend(); + + /* + This entry, n, has a point in time, T(n), and a status phrase, S(n). The + status phrase S(n) describes the period of time that begins at T(n). The + previous status phrase S(n-1) describes the period of time that starts at + T(n-1) and ends at T(n). Since we want to describe the time that a status + phrase took T(n)-T(n-1), this line must describe the previous status. + */ + protocol->store(previous->status, strlen(previous->status), + system_charset_info); + protocol->store((double)(entry->time_usecs - + previous->time_usecs)/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + + if (options & PROFILE_CPU) + { +#ifdef HAVE_GETRUSAGE + String cpu_utime, cpu_stime; + protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_utime, + previous->rusage.ru_utime))/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &cpu_utime); + protocol->store((double)(RUSAGE_DIFF_USEC(rusage->ru_stime, + previous->rusage.ru_stime))/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &cpu_stime); +#else + protocol->store_null(); + protocol->store_null(); +#endif + } + + if (options & PROFILE_CONTEXT) + { +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_nvcsw - previous->rusage.ru_nvcsw)); + protocol->store((uint32)(rusage->ru_nivcsw - previous->rusage.ru_nivcsw)); +#else + protocol->store_null(); + protocol->store_null(); +#endif + } + + if (options & PROFILE_BLOCK_IO) + { +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_inblock - previous->rusage.ru_inblock)); + protocol->store((uint32)(rusage->ru_oublock - previous->rusage.ru_oublock)); +#else + protocol->store_null(); + protocol->store_null(); +#endif + } + + if (options & PROFILE_IPC) + { +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_msgsnd - previous->rusage.ru_msgsnd)); + protocol->store((uint32)(rusage->ru_msgrcv - previous->rusage.ru_msgrcv)); +#else + protocol->store_null(); + protocol->store_null(); +#endif + } + + if (options & PROFILE_PAGE_FAULTS) + { +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_majflt - previous->rusage.ru_majflt)); + protocol->store((uint32)(rusage->ru_minflt - previous->rusage.ru_minflt)); +#else + protocol->store_null(); + protocol->store_null(); +#endif + } + + if (options & PROFILE_SWAPS) + { +#ifdef HAVE_GETRUSAGE + protocol->store((uint32)(rusage->ru_nswap - previous->rusage.ru_nswap)); +#else + protocol->store_null(); +#endif + } + + if (options & PROFILE_SOURCE) + { + if ((entry->function != NULL) && (entry->file != NULL)) + { + protocol->store(entry->function, strlen(entry->function), + system_charset_info); + protocol->store(entry->file, strlen(entry->file), system_charset_info); + protocol->store((uint32) entry->line); + } else { + protocol->store_null(); + protocol->store_null(); + protocol->store_null(); + } + } + + if (protocol->write()) + DBUG_RETURN(TRUE); + + previous= entry; + } + send_eof(thd); + DBUG_RETURN(FALSE); +} + +PROFILING::PROFILING() + :profile_id_counter(1), keeping(TRUE), enabled(FALSE), current(NULL), last(NULL) +{ +} + +PROFILING::~PROFILING() +{ + while (! history.is_empty()) + delete history.pop(); + + if (current != NULL) + delete current; +} + +void PROFILING::status_change(const char *status_arg, + const char *function_arg, + const char *file_arg, unsigned int line_arg) +{ + DBUG_ENTER("PROFILING::status_change"); + + if (unlikely(enabled)) + { + if (unlikely(current == NULL)) + reset(); + + DBUG_ASSERT(current != NULL); + + current->status(status_arg, function_arg, file_arg, line_arg); + } + + thd->proc_info= status_arg; + DBUG_VOID_RETURN; +} + +void PROFILING::store() +{ + DBUG_ENTER("PROFILING::store"); + + /* Already stored */ + if (unlikely((last != NULL) && + (current != NULL) && + (last->server_query_id == current->server_query_id))) + { + DBUG_VOID_RETURN; + } + + while (history.elements > thd->variables.profiling_history_size) + delete history.pop(); + + if (likely(((thd)->options & OPTION_PROFILING) == 0)) + DBUG_VOID_RETURN; + + if (current != NULL) + { + if (keeping && + (enabled) && /* ON at start? */ + (((thd)->options & OPTION_PROFILING) != 0) && /* and ON at end? */ + (current->query_source != NULL) && + (current->query_source[0] != '\0') && + (!current->entries.is_empty())) + { + current->profiling_query_id= next_profile_id(); /* assign an id */ + + last= current; /* never contains something that is not in the history. */ + history.push_back(current); + current= NULL; + } + else + { + delete current; + current= NULL; + } + } + + DBUG_ASSERT(current == NULL); + if (enabled) + current= new QUERY_PROFILE(this, thd->query, thd->query_length); + + DBUG_VOID_RETURN; +} + +/** + Store and clean up the old information and get ready to hold info about this + new query. This is called very often so it must be very lightweight if + profiling is not active. +*/ +void PROFILING::reset() +{ + DBUG_ENTER("PROFILING::reset"); + + store(); + + if (likely(((thd)->options & OPTION_PROFILING) == 0)) + { + enabled= FALSE; + DBUG_VOID_RETURN; + } + else + enabled= TRUE; + + if (current != NULL) + current->reset(); + keep(); + + DBUG_VOID_RETURN; +} + +bool PROFILING::show_profiles() +{ + DBUG_ENTER("PROFILING::show_profiles"); + QUERY_PROFILE *prof; + List<Item> field_list; + + field_list.push_back(new Item_return_int("Query_ID", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Duration", TIME_FLOAT_DIGITS-1, + MYSQL_TYPE_DOUBLE)); + field_list.push_back(new Item_empty_string("Query", 40)); + + if (thd->protocol->send_fields(&field_list, + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) + DBUG_RETURN(TRUE); + + SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX_UNIT *unit= &thd->lex->unit; + ha_rows idx= 0; + Protocol *protocol= thd->protocol; + + unit->set_limit(sel); + + void *iterator; + for (iterator= history.new_iterator(); + iterator != NULL; + iterator= history.iterator_next(iterator)) + { + prof= history.iterator_value(iterator); + + String elapsed; + + PROFILE_ENTRY *ps= &prof->profile_start; + PROFILE_ENTRY *pe= prof->profile_end; + + if (++idx <= unit->offset_limit_cnt) + continue; + if (idx > unit->select_limit_cnt) + break; + + protocol->prepare_for_resend(); + protocol->store((uint32)(prof->profiling_query_id)); + protocol->store((double)(pe->time_usecs - ps->time_usecs)/(1000.0*1000), + (uint32) TIME_FLOAT_DIGITS-1, &elapsed); + 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); + } + send_eof(thd); + DBUG_RETURN(FALSE); +} + +/* + This is an awful hack to let prepared statements tell us the query + that they're executing. +*/ +void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) +{ + DBUG_ENTER("PROFILING::set_query_source"); + + /* We can't get this query source through normal means. */ + DBUG_ASSERT((thd->query == NULL) || (thd->query_length == 0)); + + if (current != NULL) + current->set_query_source(query_source_arg, query_length_arg); + else + DBUG_PRINT("info", ("no current profile to send query source to")); + DBUG_VOID_RETURN; +} + +bool PROFILING::show(uint options, uint profiling_query_id) +{ + DBUG_ENTER("PROFILING::show"); + QUERY_PROFILE *prof; + + void *iterator; + for (iterator= history.new_iterator(); + iterator != NULL; + iterator= history.iterator_next(iterator)) + { + prof= history.iterator_value(iterator); + + 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); +} + +bool PROFILING::show_last(uint options) +{ + DBUG_ENTER("PROFILING::show_last"); + if (!history.is_empty()) { + DBUG_RETURN(last->show(options)); + } + DBUG_RETURN(TRUE); +} + + +/** + Fill the information schema table, "query_profile", as defined in show.cc . +*/ +int PROFILING::fill_statistics_info(THD *thd, struct st_table_list *tables, Item *cond) +{ + DBUG_ENTER("PROFILING::fill_statistics_info"); + TABLE *table= tables->table; + ulonglong row_number= 0; + + QUERY_PROFILE *query; + /* Go through each query in this thread's stored history... */ + void *history_iterator; + for (history_iterator= history.new_iterator(); + history_iterator != NULL; + history_iterator= history.iterator_next(history_iterator)) + { + query= history.iterator_value(history_iterator); + PROFILE_ENTRY *previous= &(query->profile_start); + + /* + Because we put all profiling info into a table that may be reordered, let + us also include a numbering of each state per query. The query_id and + the "seq" together are unique. + */ + ulonglong seq; + + void *entry_iterator; + PROFILE_ENTRY *entry; + /* ...and for each query, go through all its state-change steps. */ + for (seq= 0, entry_iterator= query->entries.new_iterator(); + entry_iterator != NULL; + entry_iterator= query->entries.iterator_next(entry_iterator), + seq++, previous=entry, row_number++) + { + entry= query->entries.iterator_value(entry_iterator); + + /* Set default values for this row. */ + restore_record(table, s->default_values); + + /* + The order of these fields is set by the query_profile_statistics_info + array. + */ + table->field[0]->store((ulonglong) query->profiling_query_id); + table->field[1]->store((ulonglong) seq); /* the step in the sequence */ + /* + This entry, n, has a point in time, T(n), and a status phrase, S(n). + The status phrase S(n) describes the period of time that begins at + T(n). The previous status phrase S(n-1) describes the period of time + that starts at T(n-1) and ends at T(n). Since we want to describe the + time that a status phrase took T(n)-T(n-1), this line must describe the + previous status. + */ + table->field[2]->store(previous->status, strlen(previous->status), + system_charset_info); + table->field[3]->store((double)(entry->time_usecs - + previous->time_usecs)/(1000*1000)); + +#ifdef HAVE_GETRUSAGE + table->field[4]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_utime, + previous->rusage.ru_utime)/(1000.0*1000)); + table->field[4]->set_notnull(); + table->field[5]->store((double)RUSAGE_DIFF_USEC(entry->rusage.ru_stime, + previous->rusage.ru_stime)/(1000.0*1000)); + + table->field[5]->set_notnull(); +#else + /* TODO: Add CPU-usage info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[6]->store((uint32)(entry->rusage.ru_nvcsw - + previous->rusage.ru_nvcsw)); + table->field[6]->set_notnull(); + table->field[7]->store((uint32)(entry->rusage.ru_nivcsw - + previous->rusage.ru_nivcsw)); + table->field[7]->set_notnull(); +#else + /* TODO: Add context switch info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[8]->store((uint32)(entry->rusage.ru_inblock - + previous->rusage.ru_inblock)); + table->field[8]->set_notnull(); + table->field[9]->store((uint32)(entry->rusage.ru_oublock - + previous->rusage.ru_oublock)); + table->field[9]->set_notnull(); +#else + /* TODO: Add block IO info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[10]->store((uint32)(entry->rusage.ru_msgsnd - + previous->rusage.ru_msgsnd), true); + table->field[10]->set_notnull(); + table->field[11]->store((uint32)(entry->rusage.ru_msgrcv - + previous->rusage.ru_msgrcv), true); + table->field[11]->set_notnull(); +#else + /* TODO: Add message info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[12]->store((uint32)(entry->rusage.ru_majflt - + previous->rusage.ru_majflt), true); + table->field[12]->set_notnull(); + table->field[13]->store((uint32)(entry->rusage.ru_minflt - + previous->rusage.ru_minflt), true); + table->field[13]->set_notnull(); +#else + /* TODO: Add page fault info for non-BSD systems */ +#endif + +#ifdef HAVE_GETRUSAGE + table->field[14]->store((uint32)(entry->rusage.ru_nswap - + previous->rusage.ru_nswap), true); + table->field[14]->set_notnull(); +#else + /* TODO: Add swap info for non-BSD systems */ +#endif + + if ((entry->function != NULL) && (entry->file != NULL)) + { + table->field[15]->store(entry->function, strlen(entry->function), + system_charset_info); + table->field[15]->set_notnull(); + table->field[16]->store(entry->file, strlen(entry->file), system_charset_info); + table->field[16]->set_notnull(); + table->field[17]->store(entry->line, true); + table->field[17]->set_notnull(); + } + + if (schema_table_store_record(thd, table)) + DBUG_RETURN(1); + + } + } + + DBUG_RETURN(0); +} +#endif /* ENABLED_PROFILING */ |