Strict Standards: Redefining already defined constructor for class wpdb in /www/htdocs/w006f36b/wp-includes/wp-db.php on line 49

Deprecated: Assigning the return value of new by reference is deprecated in /www/htdocs/w006f36b/wp-includes/cache.php on line 35

Strict Standards: Redefining already defined constructor for class WP_Object_Cache in /www/htdocs/w006f36b/wp-includes/cache.php on line 400

Strict Standards: Declaration of Walker_Page::start_lvl() should be compatible with Walker::start_lvl($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 534

Strict Standards: Declaration of Walker_Page::end_lvl() should be compatible with Walker::end_lvl($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 534

Strict Standards: Declaration of Walker_Page::start_el() should be compatible with Walker::start_el($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 534

Strict Standards: Declaration of Walker_Page::end_el() should be compatible with Walker::end_el($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 534

Strict Standards: Declaration of Walker_PageDropdown::start_el() should be compatible with Walker::start_el($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 553

Strict Standards: Declaration of Walker_Category::start_lvl() should be compatible with Walker::start_lvl($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 649

Strict Standards: Declaration of Walker_Category::end_lvl() should be compatible with Walker::end_lvl($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 649

Strict Standards: Declaration of Walker_Category::start_el() should be compatible with Walker::start_el($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 649

Strict Standards: Declaration of Walker_Category::end_el() should be compatible with Walker::end_el($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 649

Strict Standards: Declaration of Walker_CategoryDropdown::start_el() should be compatible with Walker::start_el($output) in /www/htdocs/w006f36b/wp-includes/classes.php on line 674

Deprecated: Assigning the return value of new by reference is deprecated in /www/htdocs/w006f36b/wp-includes/query.php on line 15

Deprecated: Assigning the return value of new by reference is deprecated in /www/htdocs/w006f36b/wp-includes/theme.php on line 505
MauriceK, caught between dev and drums » What took you so long…

February 18, 2007

What took you so long…

Category: Development — kaldor @ 7:23 pm

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /www/htdocs/w006f36b/wp-includes/formatting.php on line 76

Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /www/htdocs/w006f36b/wp-includes/formatting.php on line 83

This is a question developers tend to ask their own code from time to time. Some weeks ago, I had to do some investigation on profiling applications for Windows derivatives at work. Although we decided to take an already existing project, I was interested in how one can catch what goes on with your code. That’s how this all started and today is part one of a series of entries about function call profiling.

Starting to read on the MSDN I found some interesting articles. When you compile your code with the /Gh option, the compiler automatically adds a call to a function with the prototype

extern "C" void __declspec(naked) _penter( void );

in the function prolog. The function prolog is actually the part of the function before variables get initialized or any code has been executed. For more information look at here.

The __declspec(naked) part describes that _penter() does not have a prolog and neither an epilog exists. This is very interesting, as a line like

int i=4;

simply does not work. The compiler will give up. So automatic variable assignments are done in the function prolog. Because of this, you have to write

 int i;
i=4;

The same applies for exiting a function. It is the /GH option described on this page. The function prototype is the same, so we use

extern "C" void __declspec(naked) _pexit( void );

.
By the way I would like to remark, that it is my personal taste to prefer extern “C” over _cdecl. They mean the same.

Now let us take a look at the assembler part. As I had nearly no clue about assembler (and to be honest I only now a little bit more by now), this was one of the most challenging parts. The MSDN docs linked above only show that you need to protect the profiled function by pushing the registers before you can do anything. The problem with this is, that we need one specific information stored in these registers. The value of ebp with some offsets is exactly the position, where the profiled function starts. With this position we can calculate the function name later.
Before I show the final version of the assembler part, one additional issue needs to be solved. For each variable you instantiate, you need to allocate the memory for it in the assembler code. Remember the function is naked, so nothing is done for you. Near to capitulation I found this. It describes, how you can use __LOCAL_SIZE for letting the compiler do the allocation for you.
Finally, when you are done do not forget to write your own epilog with freeing memory, and restoring the old registers.

unsigned int framePtr;
_asm {
   push     ebp
   mov      ebp, esp
   sub      esp, __LOCAL_SIZE
   mov DWORD PTR [framePtr], ebp
   push eax
   push ebx
   push ecx
   push edx
   push ebp
   push edi
   push esi
}
    // do stuff here
_asm {
   pop esi
   pop edi
   pop ebp
   pop edx
   pop ecx
   pop ebx
   pop eax
   mov      esp, ebp
   pop      ebp
   ret
}

So now that we have our functions, which get called when each profiled function enters or leave, we want to do something useful. So we continue on evaluating the function name. The resulted form will be ClassName::functionName.
The procedure is the following:

  • Get the module name
  • Access the symbol table
  • Get the function name
  • Clean up

If you like to take a look at the implementation, simply download the files attached to this article.

The profiler gets compiled as a static library, which then gets linked to your project you want to profile. Take care that you never compile the library with the /Gh nor /GH option, because then you would try to profile the profiler itself and will most likely end in an endless recursion.
Additionally I need to emphasize that you should not try this on large applications. As you all know, profiling slows your application down. But using printf inside of the profiler heavily kills the performance like every I/O call does. This will get fixed in a future version.

Also I would like to mention projects floating around on the web, which took also care about profiling. Take a look here and here. Both projects behave a little bit different. They use the _penter() function, but reset the return value of the profiled function. So when the function wants to returns, actually a _thunk() function gets called, which then calls _pexit(). Afterwards you need to reset the return value to the real one, otherwise things get invalid. This attempt seems to be a little bit overheaded for the current stuff and it only gains, that applications need to be compiled with /Gh and not the additional /GH flag.

If you want to try it out, download this zip file and have fun.

Next time I will have added some stuff on creating statistics and a small app displaying the results. I hope you liked the article and if you have questions or like to comment something, feel free to…

4 Comments »


  1. Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /www/htdocs/w006f36b/wp-includes/formatting.php on line 76

    Neat little thing you have set up here Maurice. Unfortunately I don’t have much use of this. Be told though, the library and test application work fine in Visual C++ 2005 Express Edition. ;)

    Btw, there are strcpy_s() with 1024 and 1023 byte-count parameter. Due to my ignorance, I’d say 1023 should be the case for the lower strcpy_s(), too. But this may be purely wrong ;)

    Comment by emwe — February 19, 2007 @ 7:35 pm


  2. Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /www/htdocs/w006f36b/wp-includes/formatting.php on line 76

    You’re right. It should at least be consistent :)

    Comment by kaldor — February 19, 2007 @ 8:08 pm


  3. Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /www/htdocs/w006f36b/wp-includes/formatting.php on line 76

    Thanks a lot, very useful tool

    Comment by backkom — December 27, 2007 @ 12:45 am


  4. Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /www/htdocs/w006f36b/wp-includes/formatting.php on line 76

    […] More… […]

    Pingback by Method Call Interception (MCI) in C++ | Random Stuff Organized — October 25, 2014 @ 1:18 pm

RSS feed for comments on this post. | TrackBack URI

Leave a comment

XHTML ( You can use these tags):
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong> .