1// -*- C++ -*-
2//
3// Copyright (C) 2009-2015 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_map_to_unordered_map.h
25 *  @brief Diagnostics for map to unordered_map.
26 */
27
28// Written by Silvius Rus.
29
30#ifndef _GLIBCXX_PROFILE_PROFILER_MAP_TO_UNORDERED_MAP_H
31#define _GLIBCXX_PROFILE_PROFILER_MAP_TO_UNORDERED_MAP_H 1
32
33#include "profile/impl/profiler.h"
34#include "profile/impl/profiler_node.h"
35#include "profile/impl/profiler_trace.h"
36
37namespace __gnu_profile
38{
39  inline int
40  __log2(std::size_t __size)
41  {
42    for (int __bit_count = sizeof(std::size_t) - 1; __bit_count >= 0;
43	 -- __bit_count)
44      if ((2 << __bit_count) & __size)
45	return __bit_count;
46    return 0;
47  }
48
49  inline float
50  __map_insert_cost(std::size_t __size)
51  { return (_GLIBCXX_PROFILE_DATA(__map_insert_cost_factor).__value
52	    * static_cast<float>(__log2(__size))); }
53
54  inline float
55  __map_erase_cost(std::size_t __size)
56  { return (_GLIBCXX_PROFILE_DATA(__map_erase_cost_factor).__value
57	    * static_cast<float>(__log2(__size))); }
58
59  inline float
60  __map_find_cost(std::size_t __size)
61  { return (_GLIBCXX_PROFILE_DATA(__map_find_cost_factor).__value
62	    * static_cast<float>(__log2(__size))); }
63
64  /** @brief A map-to-unordered_map instrumentation line in the
65      object table.  */
66  class __map2umap_info
67  : public __object_info_base
68  {
69  public:
70    __map2umap_info(__stack_t __stack)
71    : __object_info_base(__stack), _M_insert(0), _M_erase(0), _M_find(0),
72      _M_iterate(0), _M_umap_cost(0.0), _M_map_cost(0.0)
73    { }
74
75    void
76    __merge(const __map2umap_info& __o)
77    {
78      __object_info_base::__merge(__o);
79      _M_insert		+= __o._M_insert;
80      _M_erase		+= __o._M_erase;
81      _M_find		+= __o._M_find;
82      _M_iterate	+= __o._M_iterate;
83      _M_umap_cost	+= __o._M_umap_cost;
84      _M_map_cost	+= __o._M_map_cost;
85    }
86
87    void
88    __write(FILE* __f) const
89    {
90      std::fprintf(__f, "%Zu %Zu %Zu %Zu %.0f %.0f\n",
91		   _M_insert, _M_erase, _M_find, _M_iterate, _M_map_cost,
92		   _M_umap_cost);
93    }
94
95    float
96    __magnitude() const
97    { return _M_map_cost - _M_umap_cost; }
98
99    std::string
100    __advice() const
101    { return "prefer an unordered container"; }
102
103    void
104    __record_insert(std::size_t __size, std::size_t __count)
105    {
106      ++_M_insert;
107      if (__count)
108	{
109	  _M_map_cost += __count * __map_insert_cost(__size);
110	  _M_umap_cost
111	    += (__count
112		* _GLIBCXX_PROFILE_DATA(__umap_insert_cost_factor).__value);
113	}
114    }
115
116    void
117    __record_erase(std::size_t __size, std::size_t __count)
118    {
119      ++_M_erase;
120      if (__count)
121	{
122	  _M_map_cost += __count * __map_erase_cost(__size);
123	  _M_umap_cost
124	    += (__count
125		* _GLIBCXX_PROFILE_DATA(__umap_erase_cost_factor).__value);
126	}
127    }
128
129    void
130    __record_find(std::size_t __size)
131    {
132      ++_M_find;
133      _M_map_cost += __map_find_cost(__size);
134      _M_umap_cost += _GLIBCXX_PROFILE_DATA(__umap_find_cost_factor).__value;
135    }
136
137    void
138    __record_iterate(int __count)
139    { __gnu_cxx::__atomic_add(&_M_iterate, __count); }
140
141    void
142    __set_iterate_costs()
143    {
144      _M_umap_cost
145	+= (_M_iterate
146	    * _GLIBCXX_PROFILE_DATA(__umap_iterate_cost_factor).__value);
147      _M_map_cost
148	+= (_M_iterate
149	    * _GLIBCXX_PROFILE_DATA(__map_iterate_cost_factor).__value);
150    }
151
152  private:
153    std::size_t _M_insert;
154    std::size_t _M_erase;
155    std::size_t _M_find;
156    mutable _Atomic_word _M_iterate;
157    float _M_umap_cost;
158    float _M_map_cost;
159  };
160
161
162  /** @brief A map-to-unordered_map instrumentation line in the
163      stack table.  */
164  class __map2umap_stack_info
165  : public __map2umap_info
166  {
167  public:
168    __map2umap_stack_info(const __map2umap_info& __o)
169    : __map2umap_info(__o) { }
170  };
171
172  /** @brief Map-to-unordered_map instrumentation producer.  */
173  class __trace_map2umap
174  : public __trace_base<__map2umap_info, __map2umap_stack_info>
175  {
176  public:
177    __trace_map2umap()
178    : __trace_base<__map2umap_info, __map2umap_stack_info>()
179    { __id = "ordered-to-unordered"; }
180
181    // Call at destruction/clean to set container final size.
182    void
183    __destruct(__map2umap_info* __obj_info)
184    {
185      __obj_info->__set_iterate_costs();
186      __retire_object(__obj_info);
187    }
188  };
189
190  inline void
191  __trace_map_to_unordered_map_init()
192  { _GLIBCXX_PROFILE_DATA(_S_map2umap) = new __trace_map2umap(); }
193
194  inline void
195  __trace_map_to_unordered_map_free()
196  { delete _GLIBCXX_PROFILE_DATA(_S_map2umap); }
197
198  inline void
199  __trace_map_to_unordered_map_report(FILE* __f,
200				      __warning_vector_t& __warnings)
201  { __trace_report(_GLIBCXX_PROFILE_DATA(_S_map2umap), __f, __warnings); }
202
203  inline __map2umap_info*
204  __trace_map_to_unordered_map_construct()
205  {
206    if (!__profcxx_init())
207      return 0;
208
209    if (!__reentrance_guard::__get_in())
210      return 0;
211
212    __reentrance_guard __get_out;
213    return _GLIBCXX_PROFILE_DATA(_S_map2umap)->__add_object(__get_stack());
214  }
215
216  inline void
217  __trace_map_to_unordered_map_insert(__map2umap_info* __info,
218				      std::size_t __size, std::size_t __count)
219  {
220    if (!__info)
221      return;
222
223    __info->__record_insert(__size, __count);
224  }
225
226  inline void
227  __trace_map_to_unordered_map_erase(__map2umap_info* __info,
228				     std::size_t __size, std::size_t __count)
229  {
230    if (!__info)
231      return;
232
233    __info->__record_erase(__size, __count);
234  }
235
236  inline void
237  __trace_map_to_unordered_map_find(__map2umap_info* __info,
238				    std::size_t __size)
239  {
240    if (!__info)
241      return;
242
243    __info->__record_find(__size);
244  }
245
246  inline void
247  __trace_map_to_unordered_map_iterate(__map2umap_info* __info,
248				       int)
249  {
250    if (!__info)
251      return;
252
253    // We only collect if an iteration took place no matter in what side.
254    __info->__record_iterate(1);
255  }
256
257  inline void
258  __trace_map_to_unordered_map_invalidate(__map2umap_info* __info)
259  {
260    if (!__info)
261      return;
262
263    __info->__set_invalid();
264  }
265
266  inline void
267  __trace_map_to_unordered_map_destruct(__map2umap_info* __info)
268  {
269    if (!__info)
270      return;
271
272    _GLIBCXX_PROFILE_DATA(_S_map2umap)->__destruct(__info);
273  }
274} // namespace __gnu_profile
275#endif /* _GLIBCXX_PROFILE_PROFILER_MAP_TO_UNORDERED_MAP_H */
276