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_list_to_vector.h
25 *  @brief diagnostics for list to vector.
26 */
27
28// Written by Changhee Jung.
29
30#ifndef _GLIBCXX_PROFILE_PROFILER_LIST_TO_VECTOR_H
31#define _GLIBCXX_PROFILE_PROFILER_LIST_TO_VECTOR_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
39namespace __gnu_profile
40{
41  /** @brief A list-to-vector instrumentation line in the object table.  */
42  class __list2vector_info
43  : public __object_info_base
44  {
45  public:
46    __list2vector_info(__stack_t __stack)
47    : __object_info_base(__stack), _M_shift_count(0), _M_iterate(0),
48      _M_resize(0), _M_list_cost(0), _M_vector_cost(0),
49      _M_max_size(0) { }
50
51    void
52    __merge(const __list2vector_info& __o)
53    {
54      __object_info_base::__merge(__o);
55      _M_shift_count  += __o._M_shift_count;
56      _M_iterate      += __o._M_iterate;
57      _M_vector_cost  += __o._M_vector_cost;
58      _M_list_cost    += __o._M_list_cost;
59      _M_resize       += __o._M_resize;
60      _M_max_size     = std::max( _M_max_size, __o._M_max_size);
61    }
62
63    void
64    __write(FILE* __f) const
65    {
66      std::fprintf(__f, "%Zu %Zu %Zu %.0f %.0f\n", _M_shift_count,
67		   _M_resize, _M_iterate, _M_vector_cost, _M_list_cost);
68    }
69
70    float
71    __magnitude() const
72    { return _M_list_cost - _M_vector_cost; }
73
74    std::string
75    __advice() const
76    {
77      std::stringstream __sstream;
78      __sstream
79	<< "change std::list to std::vector and its initial size from 0 to "
80	<< _M_max_size;
81      return __sstream.str();
82    }
83
84    std::size_t
85    __shift_count()
86    { return _M_shift_count; }
87
88    std::size_t
89    __iterate()
90    { return _M_iterate; }
91
92    float
93    __list_cost()
94    { return _M_list_cost; }
95
96    std::size_t
97    __resize()
98    { return _M_resize; }
99
100    void
101    __set_list_cost(float __lc)
102    { _M_list_cost = __lc; }
103
104    void
105    __set_vector_cost(float __vc)
106    { _M_vector_cost = __vc; }
107
108    void
109    __opr_insert(std::size_t __shift, std::size_t __size)
110    {
111      _M_shift_count += __shift;
112      _M_max_size = std::max(_M_max_size, __size);
113    }
114
115    void
116    __opr_iterate(int __num)
117    { __gnu_cxx::__atomic_add(&_M_iterate, __num); }
118
119    void
120    __resize(std::size_t __from, std::size_t)
121    { _M_resize += __from; }
122
123  private:
124    std::size_t _M_shift_count;
125    mutable _Atomic_word _M_iterate;
126    std::size_t _M_resize;
127    float _M_list_cost;
128    float _M_vector_cost;
129    std::size_t _M_max_size;
130  };
131
132  class __list2vector_stack_info
133  : public __list2vector_info
134  {
135  public:
136    __list2vector_stack_info(const __list2vector_info& __o)
137    : __list2vector_info(__o) {}
138  };
139
140  class __trace_list_to_vector
141  : public __trace_base<__list2vector_info, __list2vector_stack_info>
142  {
143  public:
144    __trace_list_to_vector()
145    : __trace_base<__list2vector_info, __list2vector_stack_info>()
146    { __id = "list-to-vector"; }
147
148    ~__trace_list_to_vector() { }
149
150    // Call at destruction/clean to set container final size.
151    void
152    __destruct(__list2vector_info* __obj_info)
153    {
154      float __vc = __vector_cost(__obj_info->__shift_count(),
155				 __obj_info->__iterate());
156      float __lc = __list_cost(__obj_info->__shift_count(),
157			       __obj_info->__iterate());
158      __obj_info->__set_vector_cost(__vc);
159      __obj_info->__set_list_cost(__lc);
160      __retire_object(__obj_info);
161    }
162
163    // Collect cost of operations.
164    float
165    __vector_cost(std::size_t __shift, std::size_t __iterate)
166    {
167      // The resulting vector will use a 'reserve' method.
168      return (__shift
169	      * _GLIBCXX_PROFILE_DATA(__vector_shift_cost_factor).__value
170	      + __iterate
171	      * _GLIBCXX_PROFILE_DATA(__vector_iterate_cost_factor).__value);
172    }
173
174    float
175    __list_cost(std::size_t __shift, std::size_t __iterate)
176    {
177      return (__shift
178	      * _GLIBCXX_PROFILE_DATA(__list_shift_cost_factor).__value
179	      + __iterate
180	      * _GLIBCXX_PROFILE_DATA(__list_iterate_cost_factor).__value);
181    }
182  };
183
184
185  inline void
186  __trace_list_to_vector_init()
187  { _GLIBCXX_PROFILE_DATA(_S_list_to_vector) = new __trace_list_to_vector(); }
188
189  inline void
190  __trace_list_to_vector_free()
191  { delete _GLIBCXX_PROFILE_DATA(_S_list_to_vector); }
192
193  inline void
194  __trace_list_to_vector_report(FILE* __f, __warning_vector_t& __warnings)
195  { __trace_report(_GLIBCXX_PROFILE_DATA(_S_list_to_vector), __f, __warnings); }
196
197  inline __list2vector_info*
198  __trace_list_to_vector_construct()
199  {
200    if (!__profcxx_init())
201      return 0;
202
203    if (!__reentrance_guard::__get_in())
204      return 0;
205
206    __reentrance_guard __get_out;
207    return _GLIBCXX_PROFILE_DATA(_S_list_to_vector)
208      ->__add_object(__get_stack());
209  }
210
211  inline void
212  __trace_list_to_vector_insert(__list2vector_info* __obj_info,
213				std::size_t __shift, std::size_t __size)
214  {
215    if (!__obj_info)
216      return;
217
218    __obj_info->__opr_insert(__shift, __size);
219  }
220
221  inline void
222  __trace_list_to_vector_iterate(__list2vector_info* __obj_info,
223				 int)
224  {
225    if (!__obj_info)
226      return;
227
228    // We only collect if an iteration took place no matter in what side.
229    __obj_info->__opr_iterate(1);
230  }
231
232  inline void
233  __trace_list_to_vector_invalid_operator(__list2vector_info* __obj_info)
234  {
235    if (!__obj_info)
236      return;
237
238    __obj_info->__set_invalid();
239  }
240
241  inline void
242  __trace_list_to_vector_resize(__list2vector_info* __obj_info,
243				std::size_t __from, std::size_t __to)
244  {
245    if (!__obj_info)
246      return;
247
248    __obj_info->__resize(__from, __to);
249  }
250
251  inline void
252  __trace_list_to_vector_destruct(__list2vector_info* __obj_info)
253  {
254    if (!__obj_info)
255      return;
256
257    _GLIBCXX_PROFILE_DATA(_S_list_to_vector)->__destruct(__obj_info);
258  }
259
260} // namespace __gnu_profile
261#endif /* _GLIBCXX_PROFILE_PROFILER_LIST_TO_VECTOR_H__ */
262