Profiler class, suggestions and comments welcome

J

James Kanze

- Shall I start adding "throw()" to all functions - and ensure
that none of them actually throws by wrapping the code into
try / catch blocks?

Only if it's an important part of their contract that they don't
throw. (Note that a function which guarantees that it doesn't
throw can't use any of the standard containers, including
std::string.)
- Does it make any difference to use clock_t against
std::clock_t (and the alike, using C functions incorporated
into the std namespace)?

Formally, if you include <ctime>, it's std::clock_t, and if you
include <time.h>, it's clock_t (or ::clock_t). I generally
prefer the latter---it's a C interface, and should look like
one. (Also, I work a lot on Posix based systems, where the C
headers are somewhat modified anyway.)
 
F

Francesco

On 20 Ago, 10:49, James Kanze <[email protected]> wrote:

    [...]
Sorry but I don't understand this, what do you mean exactly?
Do you mean typo-free (about the escaping) or something else
related to streams and flushing them with endl?

Unless you're a really, really good programmer (a lot better
than me), you're code will crash from time to time.  If you're
flushing after each line, you'll see everything through the last
line output on standard out; this can be a very big help in
understanding where and why you're crashing.

Using std::endl does have significant performance implications.
With experience, you'll get a more or less intuitive feel about
when it's appropriate, and when to prefer '\n'.  But until then,
std::endl will cause you a lot less problems.

Thank you for the explanation, now I got it right - this couples with
your suggestion about making the report function to work on a passed
stream instead that on a local stream. I'll replace all newline chars
with endl as suggested.

Of course, there is a long, long way to go before I become a really,
really good programmer - assuming I'll ever get there ;-)

Francesco
 
F

Francesco

Exactly.  Or more to the point, whether you knew that it would
make a significant difference.

Of course I didn't knew, I had to try it to get a grip.
I used my profiler onto the two ctor versions using this code:
-------
#include "profiler_utils.h" // 3rd version as posted before
using namespace profiler_utils;
using namespace std;
struct inline_ctor {
  string s;
  clock_t t;
  inline_ctor(const string& rs = "") : s(rs), t(clock()) {}
};
struct separate_ctor {
  string s;
  clock_t t;
  separate_ctor(const string& = "");
};
const size_t arr_max = 10000;
template<class T> void test(const string& s) {
  Profiler p(s);
  T* ptr = new T[arr_max];
  for(size_t i = 0; i < arr_max; ++i) {
    ptr = T("text");
  }
  delete[] ptr;
}


Note that for such a small array, the allocation could easily
take up a significant amount of time, and affect your
measurements.  


Good to know. The next time I'll use a larger one.
And that your new T[ arr_max ] also calls the
default constructor.

I considered this - after having run the test, to be honest - and I've
tried to work around it by dividing the timing difference by 20K
instead of 10K.
And that your loop includes an assignment
operator as well.  Also, a good compiler will note that elements
in the array are never accessed after the assign, and end up
suppressing the entire loop.

Now that you make me think about it, the whole loop+assign part was
superfluous. If I got it right about your second sentence here above,
maybe my compiler has actually suppressed the loop and I unwillingly
compensated the array allocation (and the delete[] part) with the 10K -
20K replacement. For my very own curiosity, I'll improve this test
and I'll run it again.
Benchmarking is a tricky art---you want the compiler to apply
all relevant optimizations, but not to optimize away what you're
actually trying to measure.  My BenchHarness class uses a
virtual function to encapsulate what I'm trying to measure; in
the base class, this function is empty, and in the derived
classes, I put the code I'm trying to measure.  When I set the
iteration count (via a static member function in BenchHarness),
I run the test on the base class, and save the results (which
correspond to the time necessary to call the empty function).
When I run benchmarks with the derived classes, I subtract this
saved value from the total, so that (hopefully), I end up with
only the time taken for what I'm trying to measure.  And at
least with the compilers I generally use, calling through a
virtual function seems to stump the optimizer, so my loops don't
get optimized out.  I also run each test once immediately before
starting the measurements, so that I'm not measuring cache
misses the first time through.

Thanks for the further details. I'll definitely take advantage of
reading and fiddling with your code. Compiler optimizations - and
ensuring they do _only_ what I want them to - are still way ahead of
me. I'll try to fill the gap.
Given that this definition is in the same file, a lot (most?)
compilers will generate it inline anyway.  (There are some
compilers which will generate it inline even if the definition
is in a different file, but they aren't legion.)

Since my tests proved that there is actually a difference in the two
template instantiations, I believe that my compiler didn't do such
inlining.

I thought I were ensuring it by defining the ctor after the point
where it is used and by omitting the inline keyword in the definition.
I guess I can't rely on this assumption - and of course, such a thing
could be meaningful only in cases like this one, where you want the
compiler _not to do_ such optimizations.
That's about 24 nanoseconds.  That sounds about right for the
cost of a function call on a modern machine.  On the other hand,
the difference in the measurements is about 3%.  I'm not sure
your harness provides that sort of precision.

Seems' I've been lucky ;-) Never mind, precision and "sure knowledge"
will come with experience.

Thanks a lot,
Franecsco
 
F

Francesco

Only if it's an important part of their contract that they don't
throw.  (Note that a function which guarantees that it doesn't
throw can't use any of the standard containers, including
std::string.)

Exactly the info I was looking for. Now I understand that declaring
these functions of mine as "throw()" and ensure it by using try/catch
wouldn't be a smart move at all.
Formally, if you include <ctime>, it's std::clock_t, and if you
include <time.h>, it's clock_t (or ::clock_t).  I generally
prefer the latter---it's a C interface, and should look like
one.  (Also, I work a lot on Posix based systems, where the C
headers are somewhat modified anyway.)

So that makes no practical difference, matter of tastes and coherence,
if I got it right. Nice to read these details, thanks.

Best regards,
Francesco
 
F

Francesco

start_time(std::clock()) {} // start_time must be initialized last

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
std::clock_t start_time; // start_time must be declared last
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The first comment is superfluous - and ignorant - while the second
doesn't explain the reason - although the reason is obvious even for a
|\|008 like me. Heck, you owe me a beer for all the laughs I'm giving
you all for free...
- Why do I get strange warnings about uninitialized variables about
the instantiation of the STL containers? Is my code faulty or it is
due to some gcc oddity?

One warning for all:
-------
C:/Programmi/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../
include/c++/3.4.5/bits/stl_vector.h: In member function
`std::vector<_Tp, _Alloc>& std::vector<_Tp, _Alloc>::eek:perator=(const
std::vector<_Tp, _Alloc>&) [with _Tp = profiler_utils::TimingRec,
_Alloc = std::allocator<profiler_utils::TimingRec>]':
C:/Programmi/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../
include/c++/3.4.5/bits/stl_vector.h:715: warning: '__result' might be
used uninitialized in this function
-------

Any idea or pointer here?

Well, I suppose I could simply ignore these warnings, after all they
don't point to _my_ code ;-)

But honestly, since uninitialized variables aren't nice, I'd like to
understand what's going on.

[ for anybody reading this post alone out of context, these warnings
are raised by the third version of the profiler as it appears in the
post I'm replying to ]

Thank you for your attention,
Francesco
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,145
Latest member
web3PRAgeency
Top