prof.cc

Go to the documentation of this file.
00001 
00003 
00004 //
00005 // Copyright (c) 1999-2004 California Institute of Technology
00006 // Copyright (c) 2004-2007 University of Southern California
00007 // Rob Peters <rjpeters at klab dot caltech dot edu>
00008 //
00009 // created: Thu Jun 30 14:47:13 2005
00010 // commit: $Id: prof.cc 10065 2007-04-12 05:54:56Z rjpeters $
00011 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/src/rutz/prof.cc $
00012 //
00013 // --------------------------------------------------------------------
00014 //
00015 // This file is part of GroovX.
00016 //   [http://www.klab.caltech.edu/rjpeters/groovx/]
00017 //
00018 // GroovX is free software; you can redistribute it and/or modify it
00019 // under the terms of the GNU General Public License as published by
00020 // the Free Software Foundation; either version 2 of the License, or
00021 // (at your option) any later version.
00022 //
00023 // GroovX is distributed in the hope that it will be useful, but
00024 // WITHOUT ANY WARRANTY; without even the implied warranty of
00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 // General Public License for more details.
00027 //
00028 // You should have received a copy of the GNU General Public License
00029 // along with GroovX; if not, write to the Free Software Foundation,
00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00031 //
00033 
00034 #ifndef GROOVX_RUTZ_PROF_CC_UTC20050630214713_DEFINED
00035 #define GROOVX_RUTZ_PROF_CC_UTC20050630214713_DEFINED
00036 
00037 #include "rutz/prof.h"
00038 
00039 #include "rutz/abort.h"
00040 #include "rutz/mutex.h"
00041 #include "rutz/staticstack.h"
00042 
00043 #include <algorithm> // for std::stable_sort()
00044 #include <cstdio>
00045 #include <functional>
00046 #include <iomanip>
00047 #include <new> // for std::nothrow
00048 #include <ostream>
00049 #include <pthread.h>
00050 #include <string>
00051 
00052 namespace
00053 {
00054   //
00055   // data and thread info for the profile output file
00056   //
00057 
00058   bool            g_pdata_print_at_exit = false;
00059   std::string     g_pdata_fname = "prof.out";
00060   FILE*           g_pdata_file = 0;
00061   pthread_once_t  g_pdata_file_once = PTHREAD_ONCE_INIT;
00062   pthread_mutex_t g_pdata_mutex = PTHREAD_MUTEX_INITIALIZER;
00063 
00064   void open_pdata_file()
00065   {
00066     if (g_pdata_fname.length() > 0)
00067       g_pdata_file = fopen(g_pdata_fname.c_str(), "w");
00068 
00069     if (g_pdata_file == 0)
00070       {
00071         fprintf(stderr,
00072                 "couldn't open profile file '%s' for writing\n",
00073                 g_pdata_fname.c_str());
00074       }
00075   }
00076 
00077   //
00078   // data and thread info for a global list of all rutz::prof objects
00079   //
00080 
00081   typedef rutz::static_stack<rutz::prof*, 2048> prof_list;
00082 
00083   prof_list*      g_prof_list = 0;
00084   pthread_once_t  g_prof_list_once = PTHREAD_ONCE_INIT;
00085   pthread_mutex_t g_prof_list_mutex = PTHREAD_MUTEX_INITIALIZER;
00086 
00087   void initialize_prof_list()
00088   {
00089     // Q: Why do a dynamic allocation here instead of just having a
00090     // static object?
00091 
00092     // A: With a static object, we could potentially run in to trouble
00093     // during program exit, if somebody's destructor called
00094     // backtrace::current() after the local static object's destructor
00095     // (i.e., ~backtrace()) had itself already been run. On the other
00096     // hand, with a dynamically-allocated object, we can just let the
00097     // memory dangle (it's not really a memory "leak" since the amount
00098     // of memory is finite and bounded), so the object will never
00099     // become invalid, even during program shutdown.
00100 
00101     g_prof_list = new (std::nothrow) prof_list;
00102 
00103     if (g_prof_list == 0)
00104       GVX_ABORT("memory allocation failed");
00105   }
00106 
00107   prof_list& all_profs() throw()
00108   {
00109     pthread_once(&g_prof_list_once, &initialize_prof_list);
00110 
00111     return *g_prof_list;
00112   }
00113 
00114   //
00115   // data and thread info for a global start time
00116   //
00117 
00118   rutz::time     g_start;
00119   pthread_once_t g_start_once = PTHREAD_ONCE_INIT;
00120 
00121   void initialize_start_time()
00122   {
00123     g_start = rutz::prof::get_now_time(rutz::prof::get_timing_mode());
00124   }
00125 }
00126 
00128 //
00129 // rutz::prof member definitions
00130 //
00132 
00133 rutz::prof::timing_mode rutz::prof::s_timing_mode = rutz::prof::RUSAGE;
00134 
00135 rutz::prof::prof(const char* s, const char* fname, int lineno)  throw():
00136   m_context_name(s),
00137   m_src_file_name(fname),
00138   m_src_line_no(lineno)
00139 {
00140   reset();
00141 
00142   {
00143     GVX_MUTEX_LOCK(&g_prof_list_mutex);
00144     all_profs().push(this);
00145   }
00146 
00147   pthread_once(&g_start_once, &initialize_start_time);
00148 }
00149 
00150 rutz::prof::~prof() throw()
00151 {
00152   if (g_pdata_print_at_exit)
00153     {
00154       pthread_once(&g_pdata_file_once, &open_pdata_file);
00155 
00156       GVX_MUTEX_LOCK(&g_pdata_mutex);
00157 
00158       if (g_pdata_file != 0)
00159         {
00160           print_prof_data(g_pdata_file);
00161         }
00162     }
00163 }
00164 
00165 void rutz::prof::reset() throw()
00166 {
00167   m_call_count = 0;
00168   m_total_time.reset();
00169   m_children_time.reset();
00170 }
00171 
00172 unsigned int rutz::prof::count() const throw()
00173 {
00174   return m_call_count;
00175 }
00176 
00177 void rutz::prof::add_time(const rutz::time& t) throw()
00178 {
00179   m_total_time += t;
00180   ++m_call_count;
00181 }
00182 
00183 void rutz::prof::add_child_time(const rutz::time& t) throw()
00184 {
00185   m_children_time += t;
00186 }
00187 
00188 const char* rutz::prof::context_name() const throw()
00189 {
00190   return m_context_name;
00191 }
00192 
00193 const char* rutz::prof::src_file_name() const throw()
00194 {
00195   return m_src_file_name;
00196 }
00197 
00198 int rutz::prof::src_line_no() const throw()
00199 {
00200   return m_src_line_no;
00201 }
00202 
00203 double rutz::prof::total_time() const throw()
00204 {
00205   return (m_call_count > 0)
00206     ? m_total_time.usec()
00207     : 0.0;
00208 }
00209 
00210 double rutz::prof::self_time() const throw()
00211 {
00212   return (m_call_count > 0)
00213     ? m_total_time.usec() - m_children_time.usec()
00214     : 0.0;
00215 }
00216 
00217 double rutz::prof::avg_self_time() const throw()
00218 {
00219   return m_call_count > 0 ? (total_time() / m_call_count) : 0.0;
00220 }
00221 
00222 void rutz::prof::print_prof_data(FILE* file) const throw()
00223 {
00224   if (file == 0)
00225     GVX_ABORT("FILE* was null");
00226 
00227   const double total_elapsed_usec =
00228     (rutz::prof::get_now_time(s_timing_mode) - g_start).usec();
00229 
00230   // Don't try to convert the double values to long or int, because
00231   // we're likely to overflow and potentially cause a floating-point
00232   // exception.
00233   fprintf(file, "%10.0f %6u %10.0f %4.1f%% %10.0f %4.1f%% %s\n",
00234           avg_self_time(), count(),
00235           self_time(), (100.0 * self_time()) / total_elapsed_usec,
00236           total_time(), (100.0 * total_time()) / total_elapsed_usec,
00237           m_context_name);
00238 }
00239 
00240 void rutz::prof::print_prof_data(std::ostream& os) const throw()
00241 {
00242   os.exceptions(std::ios::goodbit);
00243 
00244   const double total_elapsed_usec =
00245     (rutz::prof::get_now_time(s_timing_mode) - g_start).usec();
00246 
00247   // Don't try to convert the double values to long or int, because
00248   // we're likely to overflow and potentially cause a floating-point
00249   // exception.
00250   os << std::fixed
00251      << std::setw(10) << std::setprecision(0) << avg_self_time() << ' '
00252      << std::setw(6) << count() << ' '
00253      << std::setw(10) << std::setprecision(0) << self_time() << ' '
00254      << std::setw(4) << std::setprecision(1)
00255      << (100.0 * self_time()) / total_elapsed_usec << "% "
00256      << std::setw(10) << std::setprecision(0) << total_time() << ' '
00257      << std::setw(4) << std::setprecision(1)
00258      << (100.0 * total_time()) / total_elapsed_usec << "% "
00259      << m_context_name << '\n';
00260 }
00261 
00262 void rutz::prof::print_at_exit(bool yes_or_no) throw()
00263 {
00264   g_pdata_print_at_exit = yes_or_no;
00265 }
00266 
00267 void rutz::prof::prof_summary_file_name(const char* fname)
00268 {
00269   GVX_MUTEX_LOCK(&g_pdata_mutex);
00270 
00271   if (fname == 0)
00272     fname = "";
00273 
00274   g_pdata_fname = fname;
00275 }
00276 
00277 void rutz::prof::reset_all_prof_data() throw()
00278 {
00279   GVX_MUTEX_LOCK(&g_prof_list_mutex);
00280   std::for_each(all_profs().begin(), all_profs().end(),
00281                 std::mem_fun(&rutz::prof::reset));
00282 }
00283 
00284 namespace
00285 {
00286   // comparison function for use with std::stable_sort()
00287   bool compare_total_time(rutz::prof* p1, rutz::prof* p2) throw()
00288   {
00289     return p1->total_time() < p2->total_time();
00290   }
00291 }
00292 
00293 void rutz::prof::print_all_prof_data(FILE* file) throw()
00294 {
00295   GVX_MUTEX_LOCK(&g_prof_list_mutex);
00296   std::stable_sort(all_profs().begin(), all_profs().end(),
00297                    compare_total_time);
00298 
00299   for (unsigned int i = 0; i < all_profs().size(); ++i)
00300     {
00301       if (all_profs()[i]->count() > 0)
00302         all_profs()[i]->print_prof_data(file);
00303     }
00304 }
00305 
00306 void rutz::prof::print_all_prof_data(std::ostream& os) throw()
00307 {
00308   GVX_MUTEX_LOCK(&g_prof_list_mutex);
00309   std::stable_sort(all_profs().begin(), all_profs().end(),
00310                    compare_total_time);
00311 
00312   for (unsigned int i = 0; i < all_profs().size(); ++i)
00313     {
00314       if (all_profs()[i]->count() > 0)
00315         all_profs()[i]->print_prof_data(os);
00316     }
00317 }
00318 
00319 static const char __attribute__((used)) vcid_groovx_rutz_prof_cc_utc20050630214713[] = "$Id: prof.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00320 #endif // !GROOVX_RUTZ_PROF_CC_UTC20050630214713DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:40 2008 by Doxygen version 1.5.5.