profiler_container_size.h

00001 // -*- C++ -*-
00002 //
00003 // Copyright (C) 2009, 2010 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the terms
00007 // of the GNU General Public License as published by the Free Software
00008 // Foundation; either version 2, or (at your option) any later
00009 // version.
00010 
00011 // This library is distributed in the hope that it will be useful, but
00012 // WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // General Public License for more details.
00015 
00016 // You should have received a copy of the GNU General Public License
00017 // along with this library; see the file COPYING.  If not, write to
00018 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
00019 // MA 02111-1307, USA.
00020 
00021 // As a special exception, you may use this file as part of a free
00022 // software library without restriction.  Specifically, if other files
00023 // instantiate templates or use macros or inline functions from this
00024 // file, or you compile this file and link it with other files to
00025 // produce an executable, this file does not by itself cause the
00026 // resulting executable to be covered by the GNU General Public
00027 // License.  This exception does not however invalidate any other
00028 // reasons why the executable file might be covered by the GNU General
00029 // Public License.
00030 
00031 /** @file profile/impl/profiler_trace.h
00032  *  @brief Diagnostics for container sizes.
00033  */
00034 
00035 // Written by Lixia Liu and Silvius Rus.
00036 
00037 #ifndef _GLIBCXX_PROFILE_PROFILER_CONTAINER_SIZE_H
00038 #define _GLIBCXX_PROFILE_PROFILER_CONTAINER_SIZE_H 1
00039 
00040 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00041 #include <cstdlib>
00042 #include <cstdio>
00043 #include <cstring>
00044 #else
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #include <string.h>
00048 #endif
00049 
00050 #include <sstream>
00051 
00052 #include "profile/impl/profiler.h"
00053 #include "profile/impl/profiler_node.h"
00054 #include "profile/impl/profiler_trace.h"
00055 
00056 namespace __gnu_profile
00057 {
00058 
00059 /** @brief A container size instrumentation line in the object table.  */
00060 class __container_size_info: public __object_info_base 
00061 {
00062  public:
00063   __container_size_info();
00064   __container_size_info(const __container_size_info& __o);
00065   __container_size_info(__stack_t __stack, size_t __num);
00066   virtual ~__container_size_info() {}
00067 
00068   void __write(FILE* f) const;
00069   float __magnitude() const { return static_cast<float>(_M_cost); }
00070   const char* __advice() const;
00071 
00072   void __merge(const __container_size_info& __o);
00073   // Call if a container is destructed or cleaned.
00074   void __destruct(size_t __num, size_t __inum);
00075   // Estimate the cost of resize/rehash. 
00076   float __resize_cost(size_t __from, size_t __to) { return __from; }
00077   // Call if container is resized.
00078   void __resize(size_t __from, size_t __to);
00079 
00080  private:
00081   size_t _M_init;
00082   size_t _M_max;  // range of # buckets
00083   size_t _M_min;
00084   size_t _M_total;
00085   size_t _M_item_min;  // range of # items
00086   size_t _M_item_max;
00087   size_t _M_item_total;
00088   size_t _M_count;
00089   size_t _M_resize;
00090   size_t _M_cost;
00091 };
00092 
00093 inline const char* __container_size_info::__advice() const
00094 {
00095   std::stringstream __message;
00096   if (_M_init < _M_item_max)
00097     __message << "change initial container size from " << _M_init
00098               << " to " << _M_item_max;
00099 
00100   return strdup(__message.str().c_str());
00101 }
00102 
00103 inline void __container_size_info::__destruct(size_t __num, size_t __inum) 
00104 {
00105   _M_max = std::max(_M_max, __num);
00106   _M_item_max = std::max(_M_item_max, __inum);
00107   if (_M_min == 0) {
00108     _M_min = __num; 
00109     _M_item_min = __inum;
00110   } else {
00111     _M_min = std::min(_M_min, __num);
00112     _M_item_min = std::min(_M_item_min, __inum);
00113   }
00114   _M_total += __num;
00115   _M_item_total += __inum;
00116   _M_count += 1;
00117 }
00118 
00119 inline void __container_size_info::__resize(size_t __from, size_t __to) 
00120 {
00121   _M_cost += this->__resize_cost(__from, __to);
00122   _M_resize += 1;
00123   _M_max = std::max(_M_max, __to);
00124 }
00125 
00126 inline __container_size_info::__container_size_info(__stack_t __stack, 
00127                                                     size_t __num)
00128     : __object_info_base(__stack), _M_init(0), _M_max(0), _M_item_max(0), 
00129       _M_min(0), _M_item_min(0), _M_total(0), _M_item_total(0), _M_cost(0), 
00130       _M_count(0), _M_resize(0)
00131 {
00132   _M_init = _M_max = __num;
00133   _M_item_min = _M_item_max = _M_item_total = _M_total = 0;
00134   _M_min = 0;
00135   _M_count = 0;
00136   _M_resize = 0;
00137 }
00138 
00139 inline void __container_size_info::__merge(const __container_size_info& __o)
00140 {
00141   _M_init        = std::max(_M_init, __o._M_init);
00142   _M_max         = std::max(_M_max, __o._M_max);
00143   _M_item_max    = std::max(_M_item_max, __o._M_item_max);
00144   _M_min         = std::min(_M_min, __o._M_min);
00145   _M_item_min    = std::min(_M_item_min, __o._M_item_min);
00146   _M_total      += __o._M_total;
00147   _M_item_total += __o._M_item_total;
00148   _M_count      += __o._M_count;
00149   _M_cost       += __o._M_cost;
00150   _M_resize     += __o._M_resize;
00151 }
00152 
00153 inline __container_size_info::__container_size_info()
00154     : _M_init(0), _M_max(0), _M_item_max(0), _M_min(0), _M_item_min(0),
00155       _M_total(0), _M_item_total(0), _M_cost(0), _M_count(0), _M_resize(0)
00156 {
00157 }
00158 
00159 inline __container_size_info::__container_size_info(
00160     const __container_size_info& __o)
00161     : __object_info_base(__o)
00162 {
00163   _M_init        = __o._M_init;
00164   _M_max         = __o._M_max;
00165   _M_item_max    = __o._M_item_max;
00166   _M_min         = __o._M_min;
00167   _M_item_min    = __o._M_item_min;
00168   _M_total       = __o._M_total;
00169   _M_item_total  = __o._M_item_total;
00170   _M_cost        = __o._M_cost;
00171   _M_count       = __o._M_count;
00172   _M_resize      = __o._M_resize;
00173 }
00174 
00175 /** @brief A container size instrumentation line in the stack table.  */
00176 class __container_size_stack_info: public __container_size_info
00177 {
00178  public:
00179   __container_size_stack_info(const __container_size_info& __o)
00180       : __container_size_info(__o) {}
00181 };
00182 
00183 /** @brief Container size instrumentation trace producer.  */
00184 class __trace_container_size
00185     : public __trace_base<__container_size_info, __container_size_stack_info> 
00186 {
00187  public:
00188   ~__trace_container_size() {}
00189   __trace_container_size()
00190       : __trace_base<__container_size_info, __container_size_stack_info>() {};
00191 
00192   // Insert a new node at construct with object, callstack and initial size. 
00193   void __insert(const __object_t __obj, __stack_t __stack, size_t __num);
00194   // Call at destruction/clean to set container final size.
00195   void __destruct(const void* __obj, size_t __num, size_t __inum);
00196   void __construct(const void* __obj, size_t __inum);
00197   // Call at resize to set resize/cost information.
00198   void __resize(const void* __obj, int __from, int __to);
00199 };
00200 
00201 inline void __trace_container_size::__insert(const __object_t __obj,
00202                                              __stack_t __stack, size_t __num)
00203 {
00204   __add_object(__obj, __container_size_info(__stack, __num));
00205 }
00206 
00207 inline void __container_size_info::__write(FILE* __f) const
00208 {
00209   fprintf(__f, "%Zu %Zu %Zu %Zu %Zu %Zu %Zu %Zu %Zu %Zu\n", 
00210           _M_init, _M_count, _M_cost, _M_resize, _M_min, _M_max, _M_total,
00211           _M_item_min, _M_item_max, _M_item_total);
00212 }
00213 
00214 inline void __trace_container_size::__destruct(const void* __obj, 
00215                                                size_t __num, size_t __inum)
00216 {
00217   if (!__is_on()) return;
00218 
00219   __object_t __obj_handle = static_cast<__object_t>(__obj);
00220 
00221   __container_size_info* __object_info = __get_object_info(__obj_handle);
00222   if (!__object_info)
00223     return;
00224 
00225   __object_info->__destruct(__num, __inum);
00226   __retire_object(__obj_handle);
00227 }
00228 
00229 inline void __trace_container_size::__resize(const void* __obj, int __from, 
00230                                              int __to)
00231 {
00232   if (!__is_on()) return;
00233 
00234   __container_size_info* __object_info = __get_object_info(__obj);
00235   if (!__object_info)
00236     return;
00237 
00238   __object_info->__resize(__from, __to);
00239 }
00240 
00241 } // namespace __gnu_profile
00242 #endif /* _GLIBCXX_PROFILE_PROFILER_CONTAINER_SIZE_H */