# 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 */