1 // -*- C++ -*-
2 //
3 // Copyright (C) 2009-2018 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License along
21 // with this library; see the file COPYING3.  If not see
22 // <http://www.gnu.org/licenses/>.
23 
24 /** @file profile/impl/profiler_container_size.h
25  *  @brief Diagnostics for container sizes.
26  */
27 
28 // Written by Lixia Liu and Silvius Rus.
29 
30 #ifndef _GLIBCXX_PROFILE_PROFILER_CONTAINER_SIZE_H
31 #define _GLIBCXX_PROFILE_PROFILER_CONTAINER_SIZE_H 1
32 
33 #include <sstream>
34 
35 #include "profile/impl/profiler.h"
36 #include "profile/impl/profiler_node.h"
37 #include "profile/impl/profiler_trace.h"
38 
39 namespace __gnu_profile
40 {
41   /** @brief A container size instrumentation line in the object table.  */
42   class __container_size_info
43   : public __object_info_base
44   {
45   public:
46     __container_size_info(__stack_t __stack)
47     : __object_info_base(__stack), _M_init(0), _M_max(0),
48       _M_min(0), _M_total(0), _M_item_min(0), _M_item_max(0),
49       _M_item_total(0), _M_count(0), _M_resize(0), _M_cost(0)
50     { }
51 
52     void
53     __write(FILE* __f) const
54     {
55       std::fprintf(__f, "%Zu %Zu %Zu %Zu %Zu %Zu %Zu %Zu %Zu %Zu\n",
56 		   _M_init, _M_count, _M_cost, _M_resize, _M_min, _M_max,
57 		   _M_total, _M_item_min, _M_item_max, _M_item_total);
58     }
59 
60     float
61     __magnitude() const
62     { return static_cast<float>(_M_cost); }
63 
64     std::string
65     __advice() const
66     {
67       std::stringstream __message;
68       if (_M_init < _M_item_max)
69 	__message << "change initial container size from " << _M_init
70 		  << " to " << _M_item_max;
71       return __message.str();
72     }
73 
74     void
75     __init(std::size_t __num)
76     {
77       _M_init = __num;
78       _M_max = __num;
79     }
80 
81     void
82     __merge(const __container_size_info& __o)
83     {
84       __object_info_base::__merge(__o);
85       _M_init        = std::max(_M_init, __o._M_init);
86       _M_max         = std::max(_M_max, __o._M_max);
87       _M_item_max    = std::max(_M_item_max, __o._M_item_max);
88       _M_min         = std::min(_M_min, __o._M_min);
89       _M_item_min    = std::min(_M_item_min, __o._M_item_min);
90       _M_total      += __o._M_total;
91       _M_item_total += __o._M_item_total;
92       _M_count      += __o._M_count;
93       _M_cost       += __o._M_cost;
94       _M_resize     += __o._M_resize;
95     }
96 
97     // Call if a container is destructed or cleaned.
98     void
99     __destruct(std::size_t __num, std::size_t __inum)
100     {
101       _M_max = std::max(_M_max, __num);
102       _M_item_max = std::max(_M_item_max, __inum);
103       if (_M_min == 0)
104 	{
105 	  _M_min = __num;
106 	  _M_item_min = __inum;
107 	}
108       else
109 	{
110 	  _M_min = std::min(_M_min, __num);
111 	  _M_item_min = std::min(_M_item_min, __inum);
112 	}
113 
114       _M_total += __num;
115       _M_item_total += __inum;
116       _M_count += 1;
117     }
118 
119     // Estimate the cost of resize/rehash.
120     float
121     __resize_cost(std::size_t __from, std::size_t)
122     { return __from; }
123 
124     // Call if container is resized.
125     void
126     __resize(std::size_t __from, std::size_t __to)
127     {
128       _M_cost += this->__resize_cost(__from, __to);
129       _M_resize += 1;
130       _M_max = std::max(_M_max, __to);
131     }
132 
133   private:
134     std::size_t _M_init;
135     std::size_t _M_max;  // range of # buckets
136     std::size_t _M_min;
137     std::size_t _M_total;
138     std::size_t _M_item_min;  // range of # items
139     std::size_t _M_item_max;
140     std::size_t _M_item_total;
141     std::size_t _M_count;
142     std::size_t _M_resize;
143     std::size_t _M_cost;
144   };
145 
146   /** @brief A container size instrumentation line in the stack table.  */
147   class __container_size_stack_info
148   : public __container_size_info
149   {
150   public:
151     __container_size_stack_info(const __container_size_info& __o)
152     : __container_size_info(__o) { }
153   };
154 
155   /** @brief Container size instrumentation trace producer.  */
156   class __trace_container_size
157   : public __trace_base<__container_size_info, __container_size_stack_info>
158   {
159   public:
160     ~__trace_container_size() { }
161 
162     __trace_container_size()
163     : __trace_base<__container_size_info, __container_size_stack_info>() { };
164 
165     // Insert a new node at construct with object, callstack and initial size.
166     __container_size_info*
167     __insert(__stack_t __stack, std::size_t __num)
168     {
169       __container_size_info* __ret =  __add_object(__stack);
170       if (__ret)
171 	__ret->__init(__num);
172       return __ret;
173     }
174 
175     // Call at destruction/clean to set container final size.
176     void
177     __destruct(__container_size_info* __obj_info,
178 	       std::size_t __num, std::size_t __inum)
179     {
180       __obj_info->__destruct(__num, __inum);
181       __retire_object(__obj_info);
182     }
183   };
184 
185 } // namespace __gnu_profile
186 #endif /* _GLIBCXX_PROFILE_PROFILER_CONTAINER_SIZE_H */
187