OSDN Git Service

PR tree-optimize/40556
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / testsuite / util / testsuite_performance.h
1 // -*- C++ -*-
2 // Testing performance utilities for the C++ library testsuite.
3 //
4 // Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009
5 // Free Software Foundation, Inc.
6 //
7 // This file is part of the GNU ISO C++ Library.  This library is free
8 // software; you can redistribute it and/or modify it under the
9 // terms of the GNU General Public License as published by the
10 // Free Software Foundation; either version 3, or (at your option)
11 // any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License along
19 // with this library; see the file COPYING3.  If not see
20 // <http://www.gnu.org/licenses/>.
21 //
22
23 #ifndef _GLIBCXX_PERFORMANCE_H
24 #define _GLIBCXX_PERFORMANCE_H
25
26 #include <sys/times.h>
27 #include <sys/resource.h>
28 #include <cstdlib>
29 #include <cstring>
30 #include <string>
31 #include <fstream>
32 #include <iomanip>
33 #include <typeinfo>
34 #include <stdexcept>
35 #include <sstream>
36 #include <cxxabi.h>
37 #include <testsuite_common_types.h>
38
39 #ifdef __linux__
40 #include <malloc.h>
41 #elif defined (__FreeBSD__)
42 extern "C"
43 {
44   struct mallinfo
45   {
46     int uordblks;
47     int hblkhd;
48   };
49
50   struct mallinfo
51   mallinfo(void)
52   {
53     struct mallinfo m = { (((size_t) sbrk (0) + 1023) / 1024), 0 };
54     return m;
55   }
56 }
57 #elif !defined (__hpux__)
58 extern "C"
59 {
60   struct mallinfo
61   {
62     int uordblks;
63     int hblkhd;
64   };
65
66   struct mallinfo empty = { 0, 0 };
67
68   struct mallinfo
69   mallinfo(void)
70   { return empty; }
71 }
72 #endif
73
74 namespace __gnu_test
75 {
76   class time_counter
77   {
78   private:
79     clock_t     elapsed_begin;
80     clock_t     elapsed_end;
81     tms         tms_begin;
82     tms         tms_end;
83
84   public:
85     explicit
86     time_counter() : elapsed_begin(), elapsed_end(), tms_begin(), tms_end()
87     { }
88
89     void 
90     clear() throw()
91     {
92       elapsed_begin = clock_t();
93       elapsed_end = clock_t();
94       tms_begin = tms();
95       tms_end = tms();
96     }
97
98     void
99     start()
100     { 
101       this->clear();
102       elapsed_begin = times(&tms_begin); 
103       const clock_t err = clock_t(-1);
104       if (elapsed_begin == err)
105         std::__throw_runtime_error("time_counter::start");
106     }
107     
108     void
109     stop()
110     { 
111       elapsed_end = times(&tms_end); 
112       const clock_t err = clock_t(-1);
113       if (elapsed_end == err)
114         std::__throw_runtime_error("time_counter::stop");
115     }
116
117     size_t
118     real_time() const
119     { return elapsed_end - elapsed_begin; }
120
121     size_t
122     user_time() const
123     { return tms_end.tms_utime - tms_begin.tms_utime; }
124
125     size_t
126     system_time() const
127     { return tms_end.tms_stime - tms_begin.tms_stime; }
128   };
129
130   class resource_counter
131   {
132     int                 who;
133     rusage              rusage_begin;
134     rusage              rusage_end;
135     struct mallinfo     allocation_begin;
136     struct mallinfo     allocation_end;
137
138   public:
139     resource_counter(int i = RUSAGE_SELF) : who(i)
140     { this->clear(); }
141     
142     void 
143     clear() throw()
144     { 
145       memset(&rusage_begin, 0, sizeof(rusage_begin)); 
146       memset(&rusage_end, 0, sizeof(rusage_end)); 
147       memset(&allocation_begin, 0, sizeof(allocation_begin)); 
148       memset(&allocation_end, 0, sizeof(allocation_end)); 
149     }
150
151     void
152     start()
153     { 
154       if (getrusage(who, &rusage_begin) != 0 )
155         memset(&rusage_begin, 0, sizeof(rusage_begin));
156       malloc(0); // Needed for some implementations.
157       allocation_begin = mallinfo();
158     }
159     
160     void
161     stop()
162     { 
163       if (getrusage(who, &rusage_end) != 0 )
164         memset(&rusage_end, 0, sizeof(rusage_end));
165       allocation_end = mallinfo();
166     }
167
168     int
169     allocated_memory() const
170     { return ((allocation_end.uordblks - allocation_begin.uordblks)
171               + (allocation_end.hblkhd - allocation_begin.hblkhd)); }
172     
173     long 
174     hard_page_fault() const
175     { return rusage_end.ru_majflt - rusage_begin.ru_majflt; }
176
177     long 
178     swapped() const
179     { return rusage_end.ru_nswap - rusage_begin.ru_nswap; }
180   };
181
182   inline void
183   start_counters(time_counter& t, resource_counter& r)
184   {
185     t.start();
186     r.start();
187   }
188
189   inline void
190   stop_counters(time_counter& t, resource_counter& r)
191   {
192     t.stop();
193     r.stop();
194   }
195
196   inline void
197   clear_counters(time_counter& t, resource_counter& r)
198   {
199     t.clear();
200     r.clear();
201   }
202
203   void
204   report_performance(const std::string file, const std::string comment, 
205                      const time_counter& t, const resource_counter& r)
206   {
207     const char space = ' ';
208     const char tab = '\t';
209     const char* name = "libstdc++-performance.sum";
210     std::string::const_iterator i = file.begin() + file.find_last_of('/') + 1;
211     std::string testname(i, file.end());
212
213     std::ofstream out(name, std::ios_base::app);
214
215 #ifdef __GTHREADS
216     if (__gthread_active_p())
217       testname.append("-thread");
218 #endif
219
220     out.setf(std::ios_base::left);
221     out << std::setw(25) << testname << tab;
222     out << std::setw(25) << comment << tab;
223
224     out.setf(std::ios_base::right);
225     out << std::setw(4) << t.real_time() << "r" << space;
226     out << std::setw(4) << t.user_time() << "u" << space;
227     out << std::setw(4) << t.system_time() << "s" << space;
228     out << std::setw(8) << r.allocated_memory() << "mem" << space;
229     out << std::setw(4) << r.hard_page_fault() << "pf" << space;
230     
231     out << std::endl;
232     out.close();
233   }
234
235   void
236   report_header(const std::string file, const std::string header)
237   {
238     const char space = ' ';
239     const char tab = '\t';
240     const char* name = "libstdc++-performance.sum";
241     std::string::const_iterator i = file.begin() + file.find_last_of('/') + 1;
242     std::string testname(i, file.end());
243
244     std::ofstream out(name, std::ios_base::app);
245
246 #ifdef __GTHREADS
247     if (__gthread_active_p ())
248       testname.append("-thread");
249 #endif
250
251     out.setf(std::ios_base::left);
252     out << std::setw(25) << testname << tab;
253     out << std::setw(40) << header << tab;
254
255     out << std::endl;
256     out.close();
257   }
258 } // namespace __gnu_test
259
260
261 // Ah, we wish it wasn't so...
262 bool first_container = false;
263 extern const char* filename;
264
265 typedef std::string::size_type (*callback_type) (std::string&);
266
267 template<typename Container, int Iter, bool Thread>
268   void
269   write_viz_container(callback_type find_container, const char* filename)
270   {
271     typedef std::string string;
272
273     // Create title.
274     {
275       const char ws(' ');
276       std::ostringstream title;
277         
278       std::string titlename(filename);
279       std::string::size_type n = titlename.find('.');
280       if (n != string::npos)
281         titlename = std::string(titlename.begin(), titlename.begin() + n);
282
283       title << titlename;
284       title << ws;
285       title << Iter;
286       title << ws;
287 #if 0
288       title << "thread<";
289       std::boolalpha(title);
290       title << Thread;
291       title << '>';
292 #endif
293       
294       titlename += ".title";
295       std::ofstream titlefile(titlename.c_str());
296       if (!titlefile.good())
297         throw std::runtime_error("write_viz_data cannot open titlename");
298       titlefile << title.str() << std::endl;
299     }
300
301     // Create compressed type name.
302     Container obj;
303     int status;
304     std::string type(abi::__cxa_demangle(typeid(obj).name(), 0, 0, &status));
305     
306     // Extract fully-qualified typename.
307     // Assumes "set" or "map" are uniquely determinate.
308     string::iterator beg = type.begin();
309     string::iterator end;
310     string::size_type n = (*find_container)(type);
311
312     // Find start of fully-qualified name.
313     // Assume map, find end.
314     string::size_type nend = type.find('<', n);
315     if (nend != string::npos)
316       end = type.begin() + nend;
317     
318     string compressed_type;
319     compressed_type += '"';
320     compressed_type += string(beg, end);
321     compressed_type += '<';
322 #if 0
323     typename Container::key_type v;
324     compressed_type += typeid(v).name();
325 #else
326     compressed_type += "int";
327 #endif
328     compressed_type += ", A>";
329
330     // XXX
331     if (Thread == true)
332       compressed_type += " thread";
333     compressed_type += '"';
334
335     std::ofstream file(filename, std::ios_base::app);
336     if (!file.good())
337       throw std::runtime_error("write_viz_data cannot open filename");
338     
339     file << compressed_type;
340     first_container = false;
341   }
342
343
344 void
345 write_viz_data(__gnu_test::time_counter& time, const char* filename)
346 {
347   std::ofstream file(filename, std::ios_base::app);  
348   if (!file.good())
349     throw std::runtime_error("write_viz_data cannot open filename");
350   
351   // Print out score in appropriate column.
352   const char tab('\t');
353   int score = time.real_time();
354   file << tab << score;
355 }
356
357 void
358 write_viz_endl(const char* filename)
359 {
360   std::ofstream file(filename, std::ios_base::app);
361   if (!file.good())
362     throw std::runtime_error("write_viz_endl cannot open filename");
363   file << std::endl;
364 }
365
366
367 // Function template, function objects for the tests.
368 template<typename TestType>
369   struct value_type : public std::pair<const TestType, TestType>
370   {
371     inline value_type& operator++() 
372     { 
373       ++this->second;
374       return *this; 
375     }
376     
377     inline operator TestType() const { return this->second; }
378   };
379
380 template<typename Container, int Iter>
381   void
382   do_loop();
383
384 template<typename Container, int Iter>
385   void*
386   do_thread(void* p = NULL)
387   {
388     do_loop<Container, Iter>();
389     return p;
390   }
391
392 template<typename Container, int Iter, bool Thread>
393   void
394   test_container(const char* filename)
395   {
396     using namespace __gnu_test;
397     time_counter time;
398     resource_counter resource;
399     {
400       start_counters(time, resource);
401       if (!Thread)
402         {
403           // No threads, so run 4x.
404           do_loop<Container, Iter * 4>();
405         }
406       else
407         {
408 #if defined (_GLIBCXX_GCC_GTHR_POSIX_H) && !defined (NOTHREAD)
409           pthread_t  t1, t2, t3, t4;
410           pthread_create(&t1, 0, &do_thread<Container, Iter>, 0);
411           pthread_create(&t2, 0, &do_thread<Container, Iter>, 0);
412           pthread_create(&t3, 0, &do_thread<Container, Iter>, 0);
413           pthread_create(&t4, 0, &do_thread<Container, Iter>, 0);
414           
415           pthread_join(t1, NULL);
416           pthread_join(t2, NULL);
417           pthread_join(t3, NULL);
418           pthread_join(t4, NULL);
419 #endif
420         }
421       stop_counters(time, resource);
422
423       // Detailed text data.
424       Container obj;
425       int status;
426       std::ostringstream comment;
427       comment << "type: " << abi::__cxa_demangle(typeid(obj).name(),
428                                                  0, 0, &status);
429       report_header(filename, comment.str());
430       report_performance("", "", time, resource);
431
432       // Detailed data for visualization.
433       std::string vizfilename(filename);
434       vizfilename += ".dat";
435       write_viz_data(time, vizfilename.c_str());
436     }
437   }
438
439 template<bool Thread>
440   struct test_sequence
441   {
442     test_sequence(const char* filename) : _M_filename(filename) { }
443
444     template<class Container>
445       void
446       operator()(Container)
447       {
448         const int i = 20000;
449         test_container<Container, i, Thread>(_M_filename); 
450       }
451
452   private:
453     const char* _M_filename;
454   };
455
456
457 inline std::string::size_type
458 sequence_find_container(std::string& type)
459 {
460   const std::string::size_type npos = std::string::npos;
461   std::string::size_type n1 = type.find("vector");
462   std::string::size_type n2 = type.find("list");
463   std::string::size_type n3 = type.find("deque");
464   std::string::size_type n4 = type.find("string");
465   
466   if (n1 != npos || n2 != npos || n3 != npos || n4 != npos)
467     return std::min(std::min(n1, n2), std::min(n3, n4));
468   else
469     throw std::runtime_error("sequence_find_container not found");
470 }
471
472 inline std::string::size_type
473 associative_find_container(std::string& type)
474 {
475   using std::string;
476   string::size_type n1 = type.find("map");
477   string::size_type n2 = type.find("set");
478   if (n1 != string::npos || n2 != string::npos)
479     return std::min(n1, n2);
480   else
481     throw std::runtime_error("associative_find_container not found");
482 }
483
484 #endif // _GLIBCXX_PERFORMANCE_H
485