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_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 
39 namespace __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