Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Programming ➜ STL ➜ Function tracer

Function tracer

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Sat 10 Jul 2004 05:51 AM (UTC)

Amended on Sat 10 Jul 2004 06:07 AM (UTC) by Nick Gammon

Message
The code below is for a simple function tracer. The idea is to output debugging information to somewhere (eg. standard output) to show when a function has been called. The constructor supplies the function name and echoes "begin name" to the output stream. The destruction echoes "--end name" when the function terminates.

It also uses a map of function names so that it can count how many times a function was called. You could use this for some simple profiling.

To use it, just include the class in your project, and then put something like:


trace x ("func_name");


at the start of your functions. This will then echo "begin func_name" when that line is reached.

It is important to give the class variable a name (like "x" in the example). Without it, like this:


trace ("func_name"); // don't do this!


the compiler will construct a temporary object which will immediately be destroyed, thus showing the "--end func_name" message at the wrong time.

You can use any standard ostream as the recipient of the trace messages (eg. cout, cerr). For no tracing (eg. in production) use 0 as the output stream.

You can turn tracing on and off with the "reset" member function. eg.


trace::reset (0); // turn tracing off
trace::reset (&cout); // turn tracing on, output to cout


To show the summaries of counts just call:


trace::show_counts ();





#ifdef WIN32
  #pragma warning( disable : 4786)
#endif

#include <iostream>

#include <map>
#include <string>

using namespace std;

class trace
  {
  const string name;
  const int which;

  static ostream * os;
  static map<string, int> invoc_count;

  public:

    // constructor shows beginning of function
    trace (const string & s)
      : name (s), which (++invoc_count [s])
      {
      if (os)
        *os << "begin " << name << " #" << which << endl;
      }

    // destructor shows end of function
     ~trace ()
      {
      if (os)
        *os << "--end " << name << " #" << which << endl;
      }

     // change output stream to something else (eg. &cout, or 0)
     static void reset (ostream * o) 
       {
       os = o;
       }

     // show counts of how many times every function called
     static void show_counts ()
       {
       if (os)
         for (map<string, int>::const_iterator i = invoc_count.begin ();
              i != invoc_count.end ();
              i++)
            *os << i->second << " " << i->first << endl;          
       }

     // reset all counts
     static void reset_counts ()
       {
       invoc_count.clear ();
       }

  };  // end of trace

// initialise static variables
ostream * trace::os = &cout;
map<string, int> trace::invoc_count;


void g ()
  {
  trace t ("g");
  }

void f ()
  {
  trace t ("f");
  g ();
  g ();
  }

int main (void)
  {
  trace t ("main");
  f ();
  f ();
  f ();


  trace::reset (0);

  {
  trace t ("foo");
  }

  trace::reset (&cout);

  {
  trace t ("bah");
  }

  trace::show_counts ();

  return 0;
  }



Output


begin main #1
begin f #1
begin g #1
--end g #1
begin g #2
--end g #2
--end f #1
begin f #2
begin g #3
--end g #3
begin g #4
--end g #4
--end f #2
begin f #3
begin g #5
--end g #5
begin g #6
--end g #6
--end f #3
begin bah #1
--end bah #1
1 bah
3 f
1 foo
6 g
1 main
--end main #1


The output shows the call sequence (eg. main calls f which calls g).

The summary at the end shows the count of each function call.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Reply #1 on Sat 10 Jul 2004 06:26 AM (UTC)
Message
A neat variation is to output to a stringstream, this could then be sent somewhere else (eg. written to a file, sent on the Internet, eaten by wild goats).

Here is an example, modifying the "main" function above:




#include <sstream>

int main (void)
  {
  ostringstream to;  // trace output

  trace::reset (&to);  // direct to our string stream

  trace t ("main");
  f ();
  f ();
  f ();
 
  trace::show_counts ();  // output function counts

  // show results (string in 'to')

  cout << "trace output = " << endl << to.str ();

  return 0;
  }



Output

trace output =
begin main #1
begin f #1
begin g #1
--end g #1
begin g #2
--end g #2
--end f #1
begin f #2
begin g #3
--end g #3
begin g #4
--end g #4
--end f #2
begin f #3
begin g #5
--end g #5
begin g #6
--end g #6
--end f #3
3 f
6 g
1 main



- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


10,320 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.