Merge lp:~prafulla-t/drizzle/drz-fast-timer-and-time-profile-refactoring into lp:~drizzle-trunk/drizzle/development

Proposed by PrafullaT
Status: Rejected
Rejected by: Lee Bieber
Proposed branch: lp:~prafulla-t/drizzle/drz-fast-timer-and-time-profile-refactoring
Merge into: lp:~drizzle-trunk/drizzle/development
Diff against target: 1013 lines (+693/-16)
9 files modified
drizzled/drizzled.cc (+0/-1)
drizzled/filesort.cc (+35/-8)
drizzled/include.am (+1/-0)
drizzled/optimizer/range.cc (+2/-0)
drizzled/session.cc (+7/-2)
drizzled/session.h (+21/-2)
drizzled/sql_parse.cc (+13/-1)
drizzled/sql_select.cc (+0/-2)
drizzled/time_profile.h (+614/-0)
To merge this branch: bzr merge lp:~prafulla-t/drizzle/drz-fast-timer-and-time-profile-refactoring
Reviewer Review Type Date Requested Status
Stewart Smith (community) Disapprove
Monty Taylor Pending
Brian Aker Pending
Review via email: mp+32887@code.launchpad.net

Description of the change

Hi
This is first attempt to have timer classes and easy macros
for doing time-related profiling of drizzle code.

We have three choice for timer classes.
rtdtc based timer
clock_gettime based timer
gettimeofday based timer.

As an example of how macros can be used, I have added few timer(uSec precision) profile related macros around filesort code.

Here what is dumped in error stream once query/command execution is done.

--------------------Profile Output------------------
Command : create table t(c1 int)
query
{
mysql_parse, acc= 71303 microsec, occ=1
}

---------------------------x------------------------
--------------------Profile Output------------------
Command : select * from t
query
{
mysql_parse, acc= 630 microsec, occ=1
}

---------------------------x------------------------
--------------------Profile Output------------------
Command : select * from t order by 1
query
{
mysql_parse, acc= 365 microsec, occ=1
}

filesort
{
estimateRowsUpperBound, acc= 4 microsec, occ=1
filesort, acc= 95 microsec, occ=1
find_all_keys, acc= 49 microsec, occ=1
innodb::releaselatches, acc= 3 microsec, occ=1
raw_read, acc= 28 microsec, occ=1
register_used_fields, acc= 2 microsec, occ=1
save_index, acc= 2 microsec, occ=1
}

---------------------------x------------------------

acc = accumulated time
occ = number of timers timer code was invoked.

In order to enable time profiling, we need to turn on TIME_PROFILE
macro in time_profile.h

I hope this would be helpful in profiling various part of drizzle code.
Could you please go over the code and suggest improvement if any ?

To post a comment you must log in.
Revision history for this message
PrafullaT (prafulla-t) wrote :

Hi
This branch has code from my other branches too.

Could you please look at the following files ?
drizzled/filesort.cc drizzled/session.cc
drizzled/session.h
drizzled/sql_parse.cc drizzled/time_profile.h
drizzled/optimizer/range.cc

Once it is reviewed, I will create separate branch with only
profiling related code. or hopefully by then my other changes
should already be in trunk.

Revision history for this message
Monty Taylor (mordred) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/17/2010 08:18 AM, Prafulla Tekawade wrote:
> Prafulla Tekawade has proposed merging lp:~prafulla-tekawade/drizzle/drz-fast-timer-and-time-profile-refactoring into lp:drizzle.
>
> Requested reviews:
> Drizzle Merge Team (drizzle-merge)
>
>
> Hi
> This is first attempt to have timer classes and easy macros
> for doing time-related profiling of drizzle code.

This looks very potentially useful.

> We have three choice for timer classes.
> rtdtc based timer
> clock_gettime based timer
> gettimeofday based timer.

Could you also investigate Boost::DateTime and see if it's a useful
choice for timer class implementation? I'm looking at using it for some
other things as well and I'd love it if we could have one set of
time-related code.

However, if it's not suitable, that's fine.

> As an example of how macros can be used, I have added few timer(uSec precision) profile related macros around filesort code.
>
> Here what is dumped in error stream once query/command execution is done.
>
> -------------Profile Output----------
> query
> {
> mysql_parse, acc= 366639 microsec, occ=1
> }
>
> filesort
> {
> estimateRowsUpperBound, acc= 5 microsec, occ=1
> filesort, acc= 262365 microsec, occ=1
> find_all_keys, acc= 227612 microsec, occ=1
> innodb::releaselatches, acc= 3 microsec, occ=1
> make_char_array, acc= 18 microsec, occ=1
> optimizer::SqlSelect::skip_record, acc= 18647 microsec, occ=12010
> raw_read, acc= 68733 microsec, occ=12011
> write_keys, acc= 46767 microsec, occ=12010
> }
>
> acc = accumulated time
> occ = number of timers timer code was invoked.
>
> In order to enable time profiling, we need to turn on TIME_PROFILE
> macro in time_profile.h
>
> I hope this would be helpful in profiling various part of drizzle code.
> Could you please go over the code and suggest improvement if any ?
>

A few quick notes...

Please do not include config.h in drizzled/time_profile.h ... it will be
included by any .cc files that use it.

For the output - would you see if it's possible to hook in to the error
message infrastructure? (errmsg_printf and friends) - that way it's
conceivable that someone could use profiling in an infrastructure where
server messages are reported to a centralized server. Like
boost::datetime, it's possible this won't work well yet - I've been
meaning to add a stream-like interface to that system and just haven't
gotten there yet.

Other than that it looks reasonable (I haven't walked through the actual
timer impl code fully yet.)

Monty
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkxqq2AACgkQ2Jv7/VK1RgEAngCguk02ETTC9xj7ruBbalvLr/B7
n7IAoO7Yr/Py6y3bu6P8RFzQNfzQ1nY0
=UPvq
-----END PGP SIGNATURE-----

1701. By PrafullaT

Time profiling related macros were misplaced due to
wrong patch in filesort.cc
Putting them at right place now.

1702. By PrafullaT

Merge from mainline branch.

1703. By PrafullaT

o. Adding some printf which prints command along with profile data
   This would help associating profiling data with input command
   easily
o. Removing some unnecessary printfs in mysql_parse method
o. Replaced fprintf with errmsg_printf as suggested by Monty in review
o. Adding license information
o. Adding guards around use clock_gettime method as it may not
   available on some platform.

1704. By PrafullaT

Fixing some formatting issues.

1705. By PrafullaT

Some more formatting issues.

Revision history for this message
Brian Aker (brianaker) wrote :

Hi!

A couple of things:

1) We want to avoid using pthread_key_t because it ties sessions to threads, and we want sessions to float between threads.

2) At the beginning of each query we call gettimeofday() in Session. You can base any calls you need off of that initially.

3) The style in the code is off from our coding style.

How can we provide this data to a user? Have you thought about providing a table function to display it for the last query?

Cheers,
   -Brian

(BTW I will be offline for an extended period of time starting this weekend, so I will be slow to respond for the next two weeks).

Revision history for this message
PrafullaT (prafulla-t) wrote :

Hi,
Thanks for review Brian.

> Hi!
>
> A couple of things:
>
> 1) We want to avoid using pthread_key_t because it ties sessions to threads,
> and we want sessions to float between threads.

I see , I wanted profile code to be done for a single thread to avoid having
thread related complexity(mutex etc) in profiling code.
Do you suggest creating independent pthread_key_t for ThreadProfile ?
That was my original plan but then I saw sessions are created per thread so I hung
threadprofile object pointer off that class.

> 2) At the beginning of each query we call gettimeofday() in Session. You can
> base any calls you need off of that initially.
>
> 3) The style in the code is off from our coding style.

I will work on the style.

>
> How can we provide this data to a user? Have you thought about providing a
> table function to display it for the last query?

User ?
I thought this would be useful for developer working on drizzle code as profiling
related code will most probably have names of internal function etc.
But yes, the data can be made available to use through some user variable.
I'll think about this.

--
Thanks
Prafulla

1706. By PrafullaT

Merge from trunk

Revision history for this message
Brian Aker (brianaker) wrote :

hi!

Please ask monty (or Lee) to set you up with hudson param build to see how this patch does with performance regression on the benchmarks.

Cheers,
   -Brian

Revision history for this message
Monty Taylor (mordred) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/20/2010 09:30 PM, Brian Aker wrote:
> hi!
>
> Please ask monty (or Lee) to set you up with hudson param build to see how this patch does with performance regression on the benchmarks.

Make yourself a user account on http://hudson.drizzle.org and then tell
me what it is.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkxvWDAACgkQ2Jv7/VK1RgGWUwCaAi0vS/FHhIKqV0dOTrL/6ChV
PWcAoOJcCCt95CiCzHerS+k5UVu7iaNk
=pk3X
-----END PGP SIGNATURE-----

1707. By PrafullaT

Fixing build failure on x86 machines
Also adding time_profile.h to include.am

1708. By PrafullaT

Chaning profiling to default off

1709. By PrafullaT

Merge from trunk

Revision history for this message
PrafullaT (prafulla-t) wrote :

Hi,

> Please ask monty (or Lee) to set you up with hudson param build to see how
> this patch does with performance regression on the benchmarks.

I ran few sysbench related test to see how it performs with this patch
Here are results.

With time profiling default on
https://lists.launchpad.net/drizzle-benchmark/msg03728.html

Without time profiling default off
https://lists.launchpad.net/drizzle-benchmark/msg03729.html

Performance becomes pretty bad with this time profiling default on.
This should be due to err_msgprintf which is used to print profile
output along with input command string.

I wrote this patch as an aid to developer working on performance
intensive project, to see which part of code is taking what time
etc. I do not think, this should be default on. We can however make user
timer to get timing information. Developer working
on performance related projects, should turn it on themselves. (Maybe
./configure can be modified to take extra param for this).

Let me know what you think

--
Thanks
Prafulla

1710. By PrafullaT

Making some changes to match up to drizzled coding standard

1711. By PrafullaT

Some more changes for coding standard

Revision history for this message
Brian Aker (brianaker) wrote :

(I am on vacation for the next two weeks, so my resonces will be slow).

If we don't print but only collect timing information, how does it effect performance ?

Revision history for this message
PrafullaT (prafulla-t) wrote :

> If we don't print but only collect timing information, how does it effect
> performance ?

If we have TIME_PROFILE_ON define'ed, it collects timing information as well as
prints it at the end of query execution using errmsg_printf,
This printing is what should be causing performance degradation.
In current branch TIME_PROFILE_ON is off by default, and hence performance
is pretty much within norm.

--
Thanks
Prauflla

1712. By PrafullaT

Disabling just printing of profiling code, to see
impact of priniting on performance.

1713. By PrafullaT

Fixing build failure

Revision history for this message
PrafullaT (prafulla-t) wrote :

> > If we don't print but only collect timing information, how does it effect
> > performance ?

I just ran tests without printing code and TIME_PROFILE_ON defin'ed

https://lists.launchpad.net/drizzle-benchmark/msg03772.html
https://lists.launchpad.net/drizzle-benchmark/msg03771.html

Performance is worse with this settings too.
I need to check root cause of these regression.

--
Thanks
Prafulla

Revision history for this message
Stewart Smith (stewart) wrote :

The regression is because any call getting a timer is relatively expensive. Also, when you have inline asm somewhere, it does limit what the compiler can do to optimise (think about instruction re-ordering around the getting of the timer).

I'd much prefer to see something based on the Linux perf-events infrastructure instead - it could be easily used to get a much better profile of what's going on instead of just what we think would ever be a bottleneck.

I guess you could hook into dtrace on OSX/Solaris but I don't think anybody really cares :)

review: Disapprove
Revision history for this message
Stewart Smith (stewart) wrote :

(that being said, for an implementation of this type of timers, this look relatively okay... I just disagree with the approach)

Unmerged revisions

1713. By PrafullaT

Fixing build failure

1712. By PrafullaT

Disabling just printing of profiling code, to see
impact of priniting on performance.

1711. By PrafullaT

Some more changes for coding standard

1710. By PrafullaT

Making some changes to match up to drizzled coding standard

1709. By PrafullaT

Merge from trunk

1708. By PrafullaT

Chaning profiling to default off

1707. By PrafullaT

Fixing build failure on x86 machines
Also adding time_profile.h to include.am

1706. By PrafullaT

Merge from trunk

1705. By PrafullaT

Some more formatting issues.

1704. By PrafullaT

Fixing some formatting issues.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'drizzled/drizzled.cc'
--- drizzled/drizzled.cc 2010-08-24 01:36:17 +0000
+++ drizzled/drizzled.cc 2010-08-26 04:32:43 +0000
@@ -338,7 +338,6 @@
338boost::mutex LOCK_open;338boost::mutex LOCK_open;
339boost::mutex LOCK_global_system_variables;339boost::mutex LOCK_global_system_variables;
340boost::mutex LOCK_thread_count;340boost::mutex LOCK_thread_count;
341
342boost::condition_variable COND_refresh;341boost::condition_variable COND_refresh;
343boost::condition_variable COND_thread_count;342boost::condition_variable COND_thread_count;
344pthread_t signal_thread;343pthread_t signal_thread;
345344
=== modified file 'drizzled/filesort.cc'
--- drizzled/filesort.cc 2010-08-17 01:34:55 +0000
+++ drizzled/filesort.cc 2010-08-26 04:32:43 +0000
@@ -41,6 +41,8 @@
41#include "drizzled/internal/my_sys.h"41#include "drizzled/internal/my_sys.h"
42#include "plugin/myisam/myisam.h"42#include "plugin/myisam/myisam.h"
43#include "drizzled/plugin/transactional_storage_engine.h"43#include "drizzled/plugin/transactional_storage_engine.h"
44#include "drizzled/time_profile.h"
45
4446
45using namespace std;47using namespace std;
4648
@@ -135,6 +137,8 @@
135 optimizer::SqlSelect *select, ha_rows max_rows,137 optimizer::SqlSelect *select, ha_rows max_rows,
136 bool sort_positions, ha_rows *examined_rows)138 bool sort_positions, ha_rows *examined_rows)
137{139{
140 START_PROFILING_PHASE("filesort", "microsec");
141 BLOCK_MICRO_SEC_TIMER("filesort");
138 int error;142 int error;
139 uint32_t memavl, min_sort_memory;143 uint32_t memavl, min_sort_memory;
140 uint32_t maxbuffer;144 uint32_t maxbuffer;
@@ -151,11 +155,14 @@
151155
152 DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());156 DRIZZLE_FILESORT_START(table->getShare()->getSchemaName(), table->getShare()->getTableName());
153157
154 /*158 {
155 Release InnoDB's adaptive hash index latch (if holding) before159 BLOCK_MICRO_SEC_TIMER("innodb::releaselatches");
156 running a sort.160 /*
157 */161 Release InnoDB's adaptive hash index latch (if holding) before
158 plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);162 running a sort.
163 */
164 plugin::TransactionalStorageEngine::releaseTemporaryLatches(session);
165 }
159166
160 /*167 /*
161 Don't use table->sort in filesort as it is also used by168 Don't use table->sort in filesort as it is also used by
@@ -226,6 +233,7 @@
226 else233 else
227#endif234#endif
228 {235 {
236 BLOCK_MICRO_SEC_TIMER("estimateRowsUpperBound");
229 records= table->cursor->estimate_rows_upper_bound();237 records= table->cursor->estimate_rows_upper_bound();
230 /*238 /*
231 If number of records is not known, use as much of sort buffer239 If number of records is not known, use as much of sort buffer
@@ -268,10 +276,12 @@
268 param.keys--; /* TODO: check why we do this */276 param.keys--; /* TODO: check why we do this */
269 param.sort_form= table;277 param.sort_form= table;
270 param.end=(param.local_sortorder=sortorder)+s_length;278 param.end=(param.local_sortorder=sortorder)+s_length;
279
271 if ((records=find_all_keys(session, &param,select,sort_keys, &buffpek_pointers,280 if ((records=find_all_keys(session, &param,select,sort_keys, &buffpek_pointers,
272 &tempfile, selected_records_file)) ==281 &tempfile, selected_records_file)) == HA_POS_ERROR)
273 HA_POS_ERROR)
274 goto err;282 goto err;
283
284
275 maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));285 maxbuffer= (uint32_t) (my_b_tell(&buffpek_pointers)/sizeof(*buffpek));
276286
277 if (maxbuffer == 0) // The whole set is in memory287 if (maxbuffer == 0) // The whole set is in memory
@@ -363,7 +373,7 @@
363 DRIZZLE_FILESORT_DONE(error, records);373 DRIZZLE_FILESORT_DONE(error, records);
364 return (error ? HA_POS_ERROR : records);374 return (error ? HA_POS_ERROR : records);
365} /* filesort */375} /* filesort */
366376
367377
368void Table::filesort_free_buffers(bool full)378void Table::filesort_free_buffers(bool full)
369{379{
@@ -421,6 +431,8 @@
421static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffpek_pointers, uint32_t count,431static unsigned char *read_buffpek_from_file(internal::IO_CACHE *buffpek_pointers, uint32_t count,
422 unsigned char *buf)432 unsigned char *buf)
423{433{
434
435 BLOCK_MICRO_SEC_TIMER("read_buffpek_from_file");
424 uint32_t length= sizeof(buffpek_st)*count;436 uint32_t length= sizeof(buffpek_st)*count;
425 unsigned char *tmp= buf;437 unsigned char *tmp= buf;
426 if (count > UINT_MAX/sizeof(buffpek_st))438 if (count > UINT_MAX/sizeof(buffpek_st))
@@ -484,6 +496,7 @@
484 internal::IO_CACHE *buffpek_pointers,496 internal::IO_CACHE *buffpek_pointers,
485 internal::IO_CACHE *tempfile, internal::IO_CACHE *indexfile)497 internal::IO_CACHE *tempfile, internal::IO_CACHE *indexfile)
486{498{
499 BLOCK_MICRO_SEC_TIMER("find_all_keys");
487 int error,flag,quick_select;500 int error,flag,quick_select;
488 uint32_t idx,indexpos,ref_length;501 uint32_t idx,indexpos,ref_length;
489 unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];502 unsigned char *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
@@ -540,6 +553,7 @@
540 {553 {
541 if (quick_select)554 if (quick_select)
542 {555 {
556 BLOCK_MICRO_SEC_TIMER("quick_select_read");
543 if ((error= read_record_info.read_record(&read_record_info)))557 if ((error= read_record_info.read_record(&read_record_info)))
544 {558 {
545 error= HA_ERR_END_OF_FILE;559 error= HA_ERR_END_OF_FILE;
@@ -551,6 +565,7 @@
551 {565 {
552 if (indexfile)566 if (indexfile)
553 {567 {
568 BLOCK_MICRO_SEC_TIMER("index_file_read");
554 if (my_b_read(indexfile,(unsigned char*) ref_pos,ref_length))569 if (my_b_read(indexfile,(unsigned char*) ref_pos,ref_length))
555 {570 {
556 error= errno ? errno : -1; /* Abort */571 error= errno ? errno : -1; /* Abort */
@@ -560,6 +575,7 @@
560 }575 }
561 else576 else
562 {577 {
578 BLOCK_MICRO_SEC_TIMER("raw_read");
563 error=file->rnd_next(sort_form->getInsertRecord());579 error=file->rnd_next(sort_form->getInsertRecord());
564580
565 if (!flag)581 if (!flag)
@@ -663,6 +679,7 @@
663write_keys(SORTPARAM *param, register unsigned char **sort_keys, uint32_t count,679write_keys(SORTPARAM *param, register unsigned char **sort_keys, uint32_t count,
664 internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)680 internal::IO_CACHE *buffpek_pointers, internal::IO_CACHE *tempfile)
665{681{
682 BLOCK_MICRO_SEC_TIMER("write_keys");
666 size_t sort_length, rec_length;683 size_t sort_length, rec_length;
667 unsigned char **end;684 unsigned char **end;
668 buffpek_st buffpek;685 buffpek_st buffpek;
@@ -699,6 +716,7 @@
699716
700static inline void store_length(unsigned char *to, uint32_t length, uint32_t pack_length)717static inline void store_length(unsigned char *to, uint32_t length, uint32_t pack_length)
701{718{
719 BLOCK_MICRO_SEC_TIMER("store_length");
702 switch (pack_length) {720 switch (pack_length) {
703 case 1:721 case 1:
704 *to= (unsigned char) length;722 *to= (unsigned char) length;
@@ -721,6 +739,7 @@
721static void make_sortkey(register SORTPARAM *param,739static void make_sortkey(register SORTPARAM *param,
722 register unsigned char *to, unsigned char *ref_pos)740 register unsigned char *to, unsigned char *ref_pos)
723{741{
742 BLOCK_MICRO_SEC_TIMER("make_sortkey");
724 Field *field;743 Field *field;
725 SortField *sort_field;744 SortField *sort_field;
726 size_t length;745 size_t length;
@@ -954,6 +973,7 @@
954973
955static void register_used_fields(SORTPARAM *param)974static void register_used_fields(SORTPARAM *param)
956{975{
976 BLOCK_MICRO_SEC_TIMER("register_used_fields");
957 SortField *sort_field;977 SortField *sort_field;
958 Table *table=param->sort_form;978 Table *table=param->sort_form;
959979
@@ -992,6 +1012,7 @@
992static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,1012static bool save_index(SORTPARAM *param, unsigned char **sort_keys, uint32_t count,
993 filesort_info_st *table_sort)1013 filesort_info_st *table_sort)
994{1014{
1015 BLOCK_MICRO_SEC_TIMER("save_index");
995 uint32_t offset,res_length;1016 uint32_t offset,res_length;
996 unsigned char *to;1017 unsigned char *to;
9971018
@@ -1017,6 +1038,7 @@
1017int merge_many_buff(SORTPARAM *param, unsigned char *sort_buffer,1038int merge_many_buff(SORTPARAM *param, unsigned char *sort_buffer,
1018 buffpek_st *buffpek, uint32_t *maxbuffer, internal::IO_CACHE *t_file)1039 buffpek_st *buffpek, uint32_t *maxbuffer, internal::IO_CACHE *t_file)
1019{1040{
1041 BLOCK_MICRO_SEC_TIMER("merge_many_buf");
1020 register uint32_t i;1042 register uint32_t i;
1021 internal::IO_CACHE t_file2,*from_file,*to_file,*temp;1043 internal::IO_CACHE t_file2,*from_file,*to_file,*temp;
1022 buffpek_st *lastbuff;1044 buffpek_st *lastbuff;
@@ -1074,6 +1096,7 @@
1074uint32_t read_to_buffer(internal::IO_CACHE *fromfile, buffpek_st *buffpek,1096uint32_t read_to_buffer(internal::IO_CACHE *fromfile, buffpek_st *buffpek,
1075 uint32_t rec_length)1097 uint32_t rec_length)
1076{1098{
1099 BLOCK_MICRO_SEC_TIMER("read_to_buffer");
1077 register uint32_t count;1100 register uint32_t count;
1078 uint32_t length;1101 uint32_t length;
10791102
@@ -1130,6 +1153,7 @@
1130 buffpek_st *lastbuff, buffpek_st *Fb, buffpek_st *Tb,1153 buffpek_st *lastbuff, buffpek_st *Fb, buffpek_st *Tb,
1131 int flag)1154 int flag)
1132{1155{
1156 BLOCK_MICRO_SEC_TIMER("merge_buffers");
1133 int error;1157 int error;
1134 uint32_t rec_length,res_length,offset;1158 uint32_t rec_length,res_length,offset;
1135 size_t sort_length;1159 size_t sort_length;
@@ -1336,6 +1360,7 @@
1336 buffpek_st *buffpek, uint32_t maxbuffer,1360 buffpek_st *buffpek, uint32_t maxbuffer,
1337 internal::IO_CACHE *tempfile, internal::IO_CACHE *outfile)1361 internal::IO_CACHE *tempfile, internal::IO_CACHE *outfile)
1338{1362{
1363 BLOCK_MICRO_SEC_TIMER("merge_index");
1339 if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,1364 if (merge_buffers(param,tempfile,outfile,sort_buffer,buffpek,buffpek,
1340 buffpek+maxbuffer,1))1365 buffpek+maxbuffer,1))
1341 return(1);1366 return(1);
@@ -1570,6 +1595,7 @@
1570static void1595static void
1571unpack_addon_fields(struct sort_addon_field_st *addon_field, unsigned char *buff)1596unpack_addon_fields(struct sort_addon_field_st *addon_field, unsigned char *buff)
1572{1597{
1598 BLOCK_MICRO_SEC_TIMER("unpack_addon_fields");
1573 Field *field;1599 Field *field;
1574 sort_addon_field_st *addonf= addon_field;1600 sort_addon_field_st *addonf= addon_field;
15751601
@@ -1594,6 +1620,7 @@
15941620
1595void change_double_for_sort(double nr,unsigned char *to)1621void change_double_for_sort(double nr,unsigned char *to)
1596{1622{
1623 BLOCK_MICRO_SEC_TIMER("change_double_for_sort");
1597 unsigned char *tmp=(unsigned char*) to;1624 unsigned char *tmp=(unsigned char*) to;
1598 if (nr == 0.0)1625 if (nr == 0.0)
1599 { /* Change to zero string */1626 { /* Change to zero string */
16001627
=== modified file 'drizzled/include.am'
--- drizzled/include.am 2010-08-20 18:39:24 +0000
+++ drizzled/include.am 2010-08-26 04:32:43 +0000
@@ -428,6 +428,7 @@
428 drizzled/temporal_interval.h \428 drizzled/temporal_interval.h \
429 drizzled/thr_lock.h \429 drizzled/thr_lock.h \
430 drizzled/time_functions.h \430 drizzled/time_functions.h \
431 drizzled/time_profile.h \
431 drizzled/tmp_table_param.h \432 drizzled/tmp_table_param.h \
432 drizzled/transaction_context.h \433 drizzled/transaction_context.h \
433 drizzled/transaction_services.h \434 drizzled/transaction_services.h \
434435
=== modified file 'drizzled/optimizer/range.cc'
--- drizzled/optimizer/range.cc 2010-08-06 11:21:12 +0000
+++ drizzled/optimizer/range.cc 2010-08-26 04:32:43 +0000
@@ -132,6 +132,7 @@
132#include "drizzled/records.h"132#include "drizzled/records.h"
133#include "drizzled/internal/my_sys.h"133#include "drizzled/internal/my_sys.h"
134#include "drizzled/internal/iocache.h"134#include "drizzled/internal/iocache.h"
135#include "drizzled/time_profile.h"
135136
136#include "drizzled/temporal.h" /* Needed in get_mm_leaf() for timestamp -> datetime comparisons */137#include "drizzled/temporal.h" /* Needed in get_mm_leaf() for timestamp -> datetime comparisons */
137138
@@ -420,6 +421,7 @@
420421
421bool optimizer::SqlSelect::skip_record()422bool optimizer::SqlSelect::skip_record()
422{423{
424 BLOCK_MICRO_SEC_TIMER("optimizer::SqlSelect::skip_record");
423 return (cond ? cond->val_int() == 0 : 0);425 return (cond ? cond->val_int() == 0 : 0);
424}426}
425427
426428
=== modified file 'drizzled/session.cc'
--- drizzled/session.cc 2010-08-24 16:45:09 +0000
+++ drizzled/session.cc 2010-08-26 04:32:43 +0000
@@ -47,6 +47,7 @@
47#include "drizzled/pthread_globals.h"47#include "drizzled/pthread_globals.h"
48#include "drizzled/transaction_services.h"48#include "drizzled/transaction_services.h"
49#include "drizzled/drizzled.h"49#include "drizzled/drizzled.h"
50#include "drizzled/time_profile.h"
5051
51#include "drizzled/table_share_instance.h"52#include "drizzled/table_share_instance.h"
5253
@@ -160,6 +161,7 @@
160 scheduler(NULL),161 scheduler(NULL),
161 scheduler_arg(NULL),162 scheduler_arg(NULL),
162 lock_id(&main_lock_id),163 lock_id(&main_lock_id),
164 pThreadProfile(NULL),
163 user_time(0),165 user_time(0),
164 ha_data(plugin::num_trx_monitored_objects),166 ha_data(plugin::num_trx_monitored_objects),
165 arg_of_last_insert_id_function(false),167 arg_of_last_insert_id_function(false),
@@ -254,7 +256,7 @@
254 thr_lock_owner_init(&main_lock_id, &lock_info);256 thr_lock_owner_init(&main_lock_id, &lock_info);
255257
256 m_internal_handler= NULL;258 m_internal_handler= NULL;
257 259 pThreadProfile = new drizzled::timer::ThreadProfile();
258 plugin::EventObserver::registerSessionEvents(*this); 260 plugin::EventObserver::registerSessionEvents(*this);
259}261}
260262
@@ -391,7 +393,10 @@
391 pthread_setspecific(THR_Session, 0);393 pthread_setspecific(THR_Session, 0);
392394
393 plugin::Logging::postEndDo(this);395 plugin::Logging::postEndDo(this);
394 plugin::EventObserver::deregisterSessionEvents(*this); 396 plugin::EventObserver::deregisterSessionEvents(*this);
397
398 delete pThreadProfile;
399 pThreadProfile = NULL;
395400
396 /* Ensure that no one is using Session */401 /* Ensure that no one is using Session */
397 LOCK_delete.unlock();402 LOCK_delete.unlock();
398403
=== modified file 'drizzled/session.h'
--- drizzled/session.h 2010-08-24 16:45:09 +0000
+++ drizzled/session.h 2010-08-26 04:32:43 +0000
@@ -80,6 +80,11 @@
80struct st_my_thread_var;80struct st_my_thread_var;
81}81}
8282
83namespace timer
84{
85class ThreadProfile;
86}
87
83class Lex_input_stream;88class Lex_input_stream;
84class user_var_entry;89class user_var_entry;
85class CopyField;90class CopyField;
@@ -418,7 +423,18 @@
418 struct system_status_var status_var; /**< Session-local status counters */423 struct system_status_var status_var; /**< Session-local status counters */
419 THR_LOCK_INFO lock_info; /**< Locking information for this session */424 THR_LOCK_INFO lock_info; /**< Locking information for this session */
420 THR_LOCK_OWNER main_lock_id; /**< To use for conventional queries */425 THR_LOCK_OWNER main_lock_id; /**< To use for conventional queries */
421 THR_LOCK_OWNER *lock_id; /**< If not main_lock_id, points to the lock_id of a cursor. */426 THR_LOCK_OWNER *lock_id; /**< If not main_lock_id, points to the lock_id of a
427 *cursor. */
428
429 /**
430 ThreadProfile class has been created to handle time-profiling related
431 information for individual threads.(so as to reduce complexity of mutex etc
432 in writing profiling classes) This is currenly hung off session object
433 assuming it would be there per connection. Other alternative is to create
434 pthread_key_t specifically for profiling and put object of threadProfile
435 class there.
436 */
437 timer::ThreadProfile* pThreadProfile; /**< Data structure required for time profiling*/
422private:438private:
423 boost::mutex LOCK_delete; /**< Locked before session is deleted */439 boost::mutex LOCK_delete; /**< Locked before session is deleted */
424public:440public:
@@ -432,7 +448,10 @@
432 {448 {
433 LOCK_delete.unlock();449 LOCK_delete.unlock();
434 }450 }
435451 timer::ThreadProfile& getThreadProfile() const {
452 return *pThreadProfile;
453 }
454
436 /**455 /**
437 * A peek into the query string for the session. This is a best effort456 * A peek into the query string for the session. This is a best effort
438 * delivery, there is no guarantee whether the content is meaningful.457 * delivery, there is no guarantee whether the content is meaningful.
439458
=== modified file 'drizzled/sql_parse.cc'
--- drizzled/sql_parse.cc 2010-08-24 16:45:09 +0000
+++ drizzled/sql_parse.cc 2010-08-26 04:32:43 +0000
@@ -41,6 +41,7 @@
41#include "drizzled/probes.h"41#include "drizzled/probes.h"
42#include "drizzled/session_list.h"42#include "drizzled/session_list.h"
43#include "drizzled/global_charset_info.h"43#include "drizzled/global_charset_info.h"
44#include "drizzled/time_profile.h"
4445
45#include "drizzled/plugin/logging.h"46#include "drizzled/plugin/logging.h"
46#include "drizzled/plugin/query_rewrite.h"47#include "drizzled/plugin/query_rewrite.h"
@@ -214,6 +215,7 @@
214 }215 }
215 case COM_QUERY:216 case COM_QUERY:
216 {217 {
218 START_PROFILING_PHASE("query", "microsec");
217 if (! session->readAndStoreQuery(packet, packet_length))219 if (! session->readAndStoreQuery(packet, packet_length))
218 break; // fatal error is set220 break; // fatal error is set
219 DRIZZLE_QUERY_START(session->query.c_str(),221 DRIZZLE_QUERY_START(session->query.c_str(),
@@ -222,7 +224,16 @@
222224
223 plugin::QueryRewriter::rewriteQuery(session->db, session->query);225 plugin::QueryRewriter::rewriteQuery(session->db, session->query);
224 mysql_parse(session, session->query.c_str(), session->query.length());226 mysql_parse(session, session->query.c_str(), session->query.length());
225227#if 0
228 stringstream ss;
229 GET_ALL_PROFILING_RESULT(ss);
230 errmsg_printf(ERRMSG_LVL_DBUG,
231 "--------------------Profile Output------------------\n");
232 errmsg_printf(ERRMSG_LVL_DBUG,"Command : %s\n", session->query.c_str());
233 errmsg_printf(ERRMSG_LVL_DBUG,ss.str().c_str());
234 errmsg_printf(ERRMSG_LVL_DBUG,
235 "---------------------------x------------------------\n");
236#endif
226 break;237 break;
227 }238 }
228 case COM_QUIT:239 case COM_QUIT:
@@ -716,6 +727,7 @@
716727
717void mysql_parse(Session *session, const char *inBuf, uint32_t length)728void mysql_parse(Session *session, const char *inBuf, uint32_t length)
718{729{
730 drizzled::timer::FastTimerMicroSecPrec autoObj("mysql_parse");
719 uint64_t start_time= my_getsystime();731 uint64_t start_time= my_getsystime();
720 lex_start(session);732 lex_start(session);
721 session->reset_for_next_command();733 session->reset_for_next_command();
722734
=== modified file 'drizzled/sql_select.cc'
--- drizzled/sql_select.cc 2010-08-21 04:05:07 +0000
+++ drizzled/sql_select.cc 2010-08-26 04:32:43 +0000
@@ -6594,8 +6594,6 @@
6594 /* QQ: session may not be set for sub queries, but this should be fixed */6594 /* QQ: session may not be set for sub queries, but this should be fixed */
6595 if(not session)6595 if(not session)
6596 session= current_session;6596 session= current_session;
6597
6598
6599 str->append(STRING_WITH_LEN("select "));6597 str->append(STRING_WITH_LEN("select "));
66006598
6601 /* First add options */6599 /* First add options */
66026600
=== added file 'drizzled/time_profile.h'
--- drizzled/time_profile.h 1970-01-01 00:00:00 +0000
+++ drizzled/time_profile.h 2010-08-26 04:32:43 +0000
@@ -0,0 +1,614 @@
1/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 *
4 * Copyright (C) 2010 Prafulla Tekawade
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef DRIZZLED_TIME_PROFILE_H
21#define DRIZZLED_TIME_PROFILE_H
22
23#include "drizzled/drizzle_time.h"
24#if TIME_WITH_SYS_TIME
25#include <sys/time.h>
26#include <time.h>
27#else
28#if HAVE_SYS_TIME_H
29#include <sys/time.h>
30#else
31#include <time.h>
32#endif
33
34#endif
35
36#include <iostream>
37#include <stdint.h>
38#include <math.h>
39#include <stdio.h>
40#include <cassert>
41#include <map>
42#include <stack>
43#include <sstream>
44#include <iostream>
45#include "drizzled/session.h"
46#include "drizzled/errmsg_print.h"
47
48#define ONE_BILLION 1000000000ULL
49#define ONE_MILLION 1000000
50#define ONE_THOUSAND 1000
51
52
53#if 0
54#define ENABLE_RTDC_BASED_TIMER
55#endif
56
57
58//Set this to 1, if you want to profile the code.
59#if 1
60#define TIME_PROFILE_ON 1
61#endif
62
63#define _CONCAT(a,b) a ## b
64#define CONCAT(a,b) _CONCAT(a, b)
65
66namespace drizzled {
67namespace timer {
68
69inline uint64_t getSecTime();
70inline uint64_t getMicroSecTime();
71inline uint64_t getNanoSecTime();
72inline uint64_t getMilliSecTime();
73
74inline ThreadProfile& thp();
75inline void th_pushProfilePhase(const char* sPhaseName,
76 const char* sScale);
77inline void th_popProfilePhase();
78inline bool useRtdcImpl();
79inline bool useClockGetTimeImpl();
80inline const char* getTimePrecToStr(int ePrecRange);
81
82
83enum
84{
85 eRtdcImpl = 0,
86 eClockTimeImpl,
87 eGetToDImpl
88};
89
90enum
91{
92 eSecPrec = 0,
93 eMilliSecPrec,
94 eMicroSecPrec,
95 eNanoSecPrec
96};
97
98#ifdef TIME_PROFILE_ON
99
100#define BLOCK_NANO_SEC_TIMER(sBlockName) drizzled::timer::FastTimerNanoSecPrec CONCAT(autoObj, __LINE__ )(sBlockName);
101#define BLOCK_MICRO_SEC_TIMER(sBlockName) drizzled::timer::FastTimerMicroSecPrec CONCAT(autoObj, __LINE__ )(sBlockName);
102#define BLOCK_MILLI_SEC_TIMER(sBlockName) drizzled::timer::FastTimerMilliSecPrec CONCAT(autoObj, __LINE__ )(sBlockName);
103#define BLOCK_SEC_TIMER(sBlockName) drizzled::timer::FastTimerSecPrec CONCAT(autoObj, __LINE__ )(sBlockName);
104
105#define START_PROFILING_PHASE(name, scale) \
106 drizzled::timer::th_pushProfilePhase(name, scale); \
107 drizzled::timer::AutoProfPhase autoPhase;
108
109
110#define GET_ALL_PROFILING_RESULT(outputStream) drizzled::timer::thp().printAllOpTime(outputStream);
111
112#else
113
114#define START_PROFILING_PHASE(name, scale)
115#define END_PROFILING_AND_COLLECT_RESULT(outputStream)
116#define BLOCK_NANO_SEC_TIMER(sBlockName)
117#define BLOCK_MICRO_SEC_TIMER(sBlockName)
118#define BLOCK_MILLI_SEC_TIMER(sBlockName)
119#define BLOCK_SEC_TIMER(sBlockName)
120#define GET_ALL_PROFILING_RESULT(outputStream)
121
122
123#endif
124
125class TimeProfile
126{
127private:
128 typedef std::pair<uint64_t, uint64_t> AccOccTimePair;
129 typedef std::map<std::string, AccOccTimePair> OpTimeMap;
130public:
131
132 TimeProfile():prof_name("{NoProfileName}"),
133 scale("NoScale")
134 { }
135 TimeProfile(const char* _prof_name,
136 const char* _scale) : prof_name(_prof_name),
137 scale(_scale)
138 { }
139
140 void addOpTime(const char* name, uint64_t time)
141 {
142 std::pair<OpTimeMap::iterator, bool> ins_res_pair =
143 opTimeMap.insert(std::make_pair(name, std::make_pair(time,1)));
144
145 if( !ins_res_pair.second ) { //If opName already exists, accumulate numTime
146 //and increament occ counter.
147 (ins_res_pair.first)->second.first += time;
148 (ins_res_pair.first)->second.second++;
149 }
150 }
151
152 void printOpTime(std::ostream& oss)
153 {
154 OpTimeMap::iterator itr = opTimeMap.begin();
155 oss << prof_name << std::endl;
156 oss << "{" << std::endl;
157 while( itr != opTimeMap.end() )
158 {
159 oss << itr->first;
160 oss << ", acc= " << itr->second.first << " " << scale;
161 oss << ", occ=" << itr->second.second << std::endl;
162 itr++;
163 }
164 oss << "}" << std::endl;
165 }
166
167private:
168 OpTimeMap opTimeMap;
169 const char* prof_name;
170 const char* scale;
171};
172
173
174class ThreadProfile
175{
176public:
177
178 ThreadProfile():time_profile_stack(),
179 profile_data() { }
180 ~ThreadProfile() { }
181
182 TimeProfile* cur()
183 {
184 if( time_profile_stack.empty() )
185 return NULL;
186 return &(time_profile_stack.top());
187 }
188 void pushProfilePhase(const char* sPhaseName, const char* sScale)
189 {
190 time_profile_stack.push(TimeProfile(sPhaseName, sScale));
191 }
192
193 void popProfilePhase()
194 {
195 if( time_profile_stack.empty() )
196 return;
197 time_profile_stack.pop();
198 }
199
200 void printAllOpTime(std::ostream& oss)
201 {
202 while( !time_profile_stack.empty() )
203 {
204 time_profile_stack.top().printOpTime(oss);
205 oss << std::endl;
206 time_profile_stack.pop();
207 }
208 std::vector<std::string>::const_iterator it = profile_data.begin();
209 while(it != profile_data.end())
210 {
211 oss << *it;
212 oss << std::endl;
213 it++;
214 }
215 profile_data.clear();
216 }
217
218 void saveProfileData(const char* pData)
219 {
220 std::string sStr(pData);
221 if( sStr.length() )
222 profile_data.push_back(sStr);
223 }
224private:
225 std::stack<TimeProfile> time_profile_stack;
226 std::vector<std::string> profile_data;
227};
228
229
230inline ThreadProfile& thp()
231{
232 return current_session->getThreadProfile();
233}
234
235inline TimeProfile* th_getProf()
236{
237 return thp().cur();
238}
239
240inline void th_pushProfilePhase(const char* sPhaseName,
241 const char* sScale)
242{
243 thp().pushProfilePhase(sPhaseName, sScale);
244}
245
246inline void th_popProfilePhase()
247{
248 thp().popProfilePhase();
249}
250
251
252class AutoProfPhase
253{
254public:
255 explicit AutoProfPhase()
256 { }
257 void popAndSaveProfileData() const
258 {
259 std::stringstream ss;
260 if( th_getProf() )
261 th_getProf()->printOpTime(ss);
262 th_popProfilePhase();
263 thp().saveProfileData(ss.str().c_str());
264 }
265
266 ~AutoProfPhase() {
267 popAndSaveProfileData();
268 }
269};
270
271
272namespace rtdcimpl {
273
274 inline uint64_t getTimeInNanoSec();
275 inline uint64_t getTimeInMicroSec();
276 inline uint64_t getTimeInMilliSec();
277 inline uint64_t getTimeInSec();
278 inline uint64_t getProcTimestampCounter();
279 inline double getProcTimerstampScale();
280
281 inline uint64_t getProcTimestampCounter()
282 {
283 uint64_t cur_time_cntr;
284#if defined(__GNUC__) && defined(__i386__)
285 asm volatile("rdtsc":"=A"(cur_time_cntr));
286#elif defined(__GNUC__) && defined(__x86_64__)
287 uint64_t hi, lo;
288 asm volatile("rdtc":"=a"(hi), "=d"(lo));
289 cur_time_cntr = (((uint64_t)hi << 32) || lo);
290#else
291 cur_time_cntr = 0;
292 assert(!"Aborted: rdtsc unimplemented for this configuration.");
293#endif
294 return cur_time_cntr;;
295 }
296
297 //Calculating how many seconds are spent in a tick
298 //so that we can use this information to get nano/milli/micro secs
299 inline double getProcTimerstampScale()
300 {
301 int seconds_to_test = 2;
302 uint64_t delta_time = 0, retry_num = 3;
303 do
304 {
305 uint64_t beforeTime = getProcTimestampCounter();
306 sleep(seconds_to_test);
307 delta_time = getProcTimestampCounter() - beforeTime;
308 } while(retry_num-- && delta_time > 0);
309 if (delta_time <= 0 )
310 return 0;
311 double scale = (double)seconds_to_test/delta_time;
312 return scale;
313 }
314#ifdef ENABLE_RTDC_BASED_TIMER
315 static double processort_counter_scale = getProcTimerstampScale();
316#else
317 static double processort_counter_scale = 0;
318#endif
319 inline uint64_t getTimeInSec()
320 {
321 uint64_t proc_counter_value = getProcTimestampCounter();
322 return proc_counter_value * processort_counter_scale;
323 }
324
325 inline uint64_t getTimeInMilliSec()
326 {
327 uint64_t proc_counter_value = getProcTimestampCounter();
328 return proc_counter_value * ONE_THOUSAND * processort_counter_scale;
329 }
330
331 inline uint64_t getTimeInMicroSec()
332 {
333 uint64_t proc_counter_value = getProcTimestampCounter();
334 return proc_counter_value * ONE_MILLION * processort_counter_scale;
335 }
336
337 inline uint64_t getTimeInNanoSec()
338 {
339 uint64_t proc_counter_value = getProcTimestampCounter();
340 return proc_counter_value * ONE_BILLION * processort_counter_scale;
341 }
342}
343
344namespace todimpl {
345 inline uint64_t getTimeInNanoSec();
346 inline uint64_t getTimeInMicroSec();
347 inline uint64_t getTimeInMilliSec();
348 inline uint64_t getTimeInSec();
349
350 inline uint64_t getTimeInMilliSec()
351 {
352 struct timeval cur_time;
353 gettimeofday(&cur_time, NULL);
354 return cur_time.tv_sec*ONE_THOUSAND + cur_time.tv_usec/ONE_THOUSAND;
355 }
356
357 inline uint64_t getTimeInMicroSec()
358 {
359 struct timeval cur_time;
360 gettimeofday(&cur_time, NULL);
361 return cur_time.tv_sec*ONE_MILLION + cur_time.tv_usec;
362 }
363
364 inline uint64_t getTimeInNanoSec()
365 {
366 struct timeval cur_time;
367 gettimeofday(&cur_time, NULL);
368 return cur_time.tv_sec*ONE_BILLION + cur_time.tv_usec*ONE_THOUSAND;
369 }
370
371 inline uint64_t getTimeInSec()
372 {
373 struct timeval cur_time;
374 gettimeofday(&cur_time, NULL);
375 return cur_time.tv_sec*ONE_BILLION + cur_time.tv_usec*ONE_MILLION;
376 }
377}
378
379namespace clockimpl {
380 inline uint64_t getTimeInNanoSec();
381 inline uint64_t getTimeInMicroSec();
382 inline uint64_t getTimeInMilliSec();
383 inline uint64_t getTimeInSec();
384 inline void getClockTime(struct timespec& tp);
385
386 inline uint64_t getTimeInNanoSec()
387 {
388 struct timespec tp;
389 clock_gettime(CLOCK_REALTIME, &tp);
390 return tp.tv_sec*ONE_BILLION + tp.tv_nsec;
391 }
392
393 inline uint64_t getTimeInMicroSec()
394 {
395 struct timespec tp;
396 clock_gettime(CLOCK_REALTIME, &tp);
397 return (uint64_t)tp.tv_sec*ONE_MILLION + (uint64_t)tp.tv_nsec/ONE_THOUSAND;
398 }
399
400 inline uint64_t getTimeInMilliSec()
401 {
402 struct timespec tp;
403 clock_gettime(CLOCK_REALTIME, &tp);
404 return (uint64_t)tp.tv_sec*ONE_THOUSAND + (uint64_t)tp.tv_nsec/ONE_MILLION;
405 }
406
407 inline uint64_t getTimeInSec()
408 {
409 struct timespec tp;
410 return (uint64_t)tp.tv_sec + (uint64_t)tp.tv_nsec/ONE_BILLION;
411 }
412
413 inline void getClockTime(struct timespec& tp)
414 {
415#if defined(HAVE_CLOCK_GETTIME)
416 clock_gettime(CLOCK_REALTIME, &tp);
417#else
418 tp.tv_sec = 0;
419 tp.tv_nsec = 0;
420 errmsg_printf(ERRMSG_LVL_ERROR,
421 "clock_gettime is not supported on this platform."\
422 "Please use different timer implementation");
423#endif
424 }
425}
426
427#if defined(__GNUC__) && defined(__i386__)
428#define HAVE_RTDC_IMPL
429#elif defined(__GNUC__) && defined(__x86_64__)
430#define HAVE_RTDC_IMPL
431#endif
432
433inline bool useRtdcImpl()
434{
435#ifdef HAVE_RTDC_IMPL
436 return true;
437#else
438 return false;
439#endif
440}
441
442inline bool useClockGetTimeImpl()
443{
444#ifdef HAVE_CLOCK_GETTIME
445 return true;
446#else
447 return false;
448#endif
449}
450
451
452#define GET_TIME(timerimpl, cur_time) { \
453 switch( ePrecRange ) { \
454 case eSecPrec: \
455 cur_time = timerimpl::getTimeInSec(); \
456 break; \
457 case eMilliSecPrec: \
458 cur_time = timerimpl::getTimeInMilliSec(); \
459 break; \
460 case eMicroSecPrec: \
461 cur_time = timerimpl::getTimeInMicroSec(); \
462 break; \
463 case eNanoSecPrec: \
464 cur_time = timerimpl::getTimeInNanoSec(); \
465 break; \
466 } \
467 } \
468
469
470
471inline const char* getTimePrecToStr(int ePrecRange)
472{
473 switch(ePrecRange) {
474 case eMilliSecPrec:
475 return "milli sec";
476 case eMicroSecPrec:
477 return "micro sec";
478 case eNanoSecPrec:
479 return "nano sec";
480 case eSecPrec:
481 return "sec";
482
483 }
484 return NULL;
485}
486/**
487 * Class to capture timing information for C/C++ block
488 * If opName is supplied, it adds this information to currect active Timing
489 * profile object.
490 * Following are some overhead information for this classes
491 * eImplKind = eRtdcImpl (~50 ns on 2.7 GHz intel machine), This went to
492 * average ~20 ns for large number of operations (1 million in my example)
493 * eImplKind = eClockTimeImpl (~1000 ns on 2.7 GHz intel machine)
494 * eImplKind = eGetToDImpl (~1500/2000 ns on 2.7 GHz intel machine)
495 */
496template<int eImplKind , int ePrecRange >
497class AutoOpTimer {
498public:
499 explicit AutoOpTimer(const char* sOpName):opr_name(sOpName), begin_time(0)
500 {
501 acquire();
502 }
503
504 void acquire()
505 {
506 switch( eImplKind )
507 {
508 case eGetToDImpl:
509 GET_TIME(todimpl, begin_time);
510 break;
511 case eClockTimeImpl:
512 GET_TIME(clockimpl, begin_time);
513 break;
514 case eRtdcImpl:
515 GET_TIME(rtdcimpl, begin_time);
516 break;
517 }
518 }
519
520 uint64_t getBgnTime() const
521 {
522 return begin_time;
523 }
524
525 static uint64_t getCurTime()
526 {
527 uint64_t cur_time = 0;
528 switch( eImplKind )
529 {
530 case eGetToDImpl:
531 GET_TIME(todimpl, cur_time);
532 break;
533 case eClockTimeImpl:
534 GET_TIME(clockimpl, cur_time);
535 break;
536 case eRtdcImpl:
537 GET_TIME(rtdcimpl, cur_time);
538 break;
539 }
540 return cur_time;
541 }
542
543 uint64_t getTimeElapsed() const
544 {
545 uint64_t cur_time = getCurTime();
546 uint64_t diff = (cur_time - begin_time) * (cur_time > begin_time);
547 return diff;
548 }
549
550 ~AutoOpTimer()
551 {
552 uint64_t uTimeElapsed = getTimeElapsed();
553 if( opr_name ) {
554 if( th_getProf() )
555 th_getProf()->addOpTime(opr_name, uTimeElapsed);
556 }
557 }
558private:
559 const char* opr_name;
560 uint64_t begin_time;
561};
562
563//Rtdc based timer do not give reliable timing information.
564//so by default they are off. One can use them directly if they want in
565//CPU-bound operation by using following Rtdc Timers and setting
566//ENABLE_RTDC_BASED_TIMER macro above.
567typedef AutoOpTimer<eRtdcImpl, eNanoSecPrec> RtdcTimerNanoSecPrec;
568typedef AutoOpTimer<eRtdcImpl, eMilliSecPrec> RtdcTimerMilliSecPrec;
569typedef AutoOpTimer<eRtdcImpl, eMicroSecPrec> RtdcTimerMicroSecPrec;
570typedef AutoOpTimer<eRtdcImpl, eSecPrec> RtdcTimerSecPrec;
571
572
573#if defined(HAVE_RTDC_IMPL) && defined(ENABLE_RTDC_BASED_TIMER)
574typedef AutoOpTimer<eRtdcImpl, eNanoSecPrec> FastTimerNanoSecPrec;
575typedef AutoOpTimer<eRtdcImpl, eMilliSecPrec> FastTimerMilliSecPrec;
576typedef AutoOpTimer<eRtdcImpl, eMicroSecPrec> FastTimerMicroSecPrec;
577typedef AutoOpTimer<eRtdcImpl, eSecPrec> FastTimerSecPrec;
578#elif defined(HAVE_CLOCK_GETTIME)
579typedef AutoOpTimer<eClockTimeImpl, eNanoSecPrec> FastTimerNanoSecPrec;
580typedef AutoOpTimer<eClockTimeImpl, eMilliSecPrec> FastTimerMilliSecPrec;
581typedef AutoOpTimer<eClockTimeImpl, eMicroSecPrec> FastTimerMicroSecPrec;
582typedef AutoOpTimer<eClockTimeImpl, eSecPrec> FastTimerSecPrec;
583#else
584typedef AutoOpTimer<eGetToDImpl, eNanoSecPrec> FastTimerNanoSecPrec;
585typedef AutoOpTimer<eGetToDImpl, eMilliSecPrec> FastTimerMilliSecPrec;
586typedef AutoOpTimer<eGetToDImpl, eMicroSecPrec> FastTimerMicroSecPrec;
587typedef AutoOpTimer<eGetToDImpl, eSecPrec> FastTimerSecPrec;
588#endif
589
590
591uint64_t getSecTime()
592{
593 return FastTimerSecPrec::getCurTime();
594}
595
596uint64_t getMilliSecTime()
597{
598 return FastTimerMilliSecPrec::getCurTime();
599}
600
601uint64_t getMicroSecTime()
602{
603 return FastTimerMicroSecPrec::getCurTime();
604}
605
606uint64_t getNanoSecTime()
607{
608 return FastTimerNanoSecPrec::getCurTime();
609}
610}/* namespace timer */
611}/*namespace drizzled*/
612
613
614#endif