OSDN Git Service

* public snapshot of sid simulator
[pf3gnuchains/pf3gnuchains3x.git] / sid / component / profiling / gprof.cxx
1 // gprof.cxx - A component for generating gprof profile data.  -*- C++ -*-
2
3 // Copyright (C) 1999, 2000 Red Hat.
4 // This file is part of SID and is licensed under the GPL.
5 // See the file COPYING.SID for conditions for redistribution.
6
7 #include "config.h"
8
9 #include <sidcomp.h>
10 #include <sidso.h>
11 #include <sidtypes.h>
12 #include <sidcomputil.h>
13 #include <sidattrutil.h>
14 #include <sidpinutil.h>
15 #include <sidbusutil.h>
16 #include <sidmiscutil.h>
17 #include <sidpinattrutil.h>
18 #include <sidschedutil.h>
19 #include <sidwatchutil.h>
20 #include <sidcpuutil.h>
21
22 #include <vector>
23 #include <string>
24 #include <algorithm>
25 #include <functional>
26 #include <queue>
27 #include <deque>
28 #include <map>
29 #include <iostream>
30 #include <cassert>
31 #include <cstdlib>
32 #include <fstream>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38
39 namespace profiling_components
40 {
41   using sid::host_int_8;
42   using sid::host_int_4;
43   using sid::host_int_2;
44   using sid::host_int_1;
45   using sid::big_int_8;
46   using sid::big_int_4;
47   using sid::big_int_2;
48   using sid::big_int_1;
49   using sid::little_int_8;
50   using sid::little_int_4;
51   using sid::little_int_2;
52   using sid::little_int_1;
53   using sid::component;
54   using sid::bus;
55
56   using sidutil::fixed_pin_map_component;
57   using sidutil::fixed_attribute_map_component;
58   using sidutil::no_bus_component;
59   using sidutil::no_accessor_component;
60   using sidutil::fixed_relation_map_component;
61   using sidutil::callback_pin;
62   using sidutil::make_attribute;
63   using sidutil::parse_attribute;
64   using sidutil::std_error_string;
65   using sidutil::endian;
66   using sidutil::endian_unknown;
67   using sidutil::endian_big;
68   using sidutil::endian_little;
69
70   using std::map;
71   using std::hash_map;
72   using std::vector;
73   using std::string;
74   using std::ofstream;
75   using std::cerr;
76   using std::endl;
77   using std::ostream;
78
79 // ----------------------------------------------------------------------------
80
81   class gprof_component: public virtual component,
82                          protected fixed_pin_map_component,
83                          protected no_accessor_component,
84                          protected fixed_attribute_map_component,
85                          protected fixed_relation_map_component,
86                          protected no_bus_component
87   {
88 #ifdef HAVE_HASHING
89     typedef hash_map<host_int_4,host_int_4> hitcount_map_t;
90 #else
91     typedef map<host_int_4,host_int_4> hitcount_map_t;
92 #endif
93     
94     // statistics
95     hitcount_map_t value_hitcount_map;
96     host_int_4 value_count;
97     host_int_4 value_min, value_max;
98     host_int_4 bucket_size;
99
100     string target_attribute;
101     component* target_component;
102
103     string output_file;
104     endian output_file_format;
105
106     callback_pin<gprof_component> accumulate_pin;
107     callback_pin<gprof_component> reset_pin;
108     callback_pin<gprof_component> store_pin;
109
110
111     string bucket_size_get()
112       {
113         return make_attribute (this->bucket_size);
114       }
115
116     component::status bucket_size_set(const string& str)
117       {
118         host_int_4 new_bucket_size;
119         component::status s = parse_attribute (str, new_bucket_size);
120
121         // Reject malformed input
122         if (s != component::ok) return s;
123
124         // Reject change if we already have samples 
125         if ((this->value_count != 0) &&
126             (this->bucket_size != new_bucket_size))
127           {
128             cerr << "sw-profile-gprof: invalid time to change bucket size" << endl;
129             return component::bad_value;
130           }
131
132         // Reject invalid size
133         if (new_bucket_size == 0)
134           {
135             cerr << "sw-profile-gprof: invalid null bucket size." << endl;
136             return component::bad_value;
137           }
138
139         this->bucket_size = new_bucket_size;
140         return component::ok;
141       }
142
143
144     void accumulate (host_int_4)
145       {
146         if (! this->target_component) return;
147
148         string value_str = this->target_component->attribute_value (this->target_attribute);
149         host_int_4 value;
150         component::status s = parse_attribute (value_str, value);
151         if (s != component::ok) return;
152
153         value_count ++;
154
155         assert (this->bucket_size != 0);
156         host_int_4 quantized = (value / this->bucket_size) * this->bucket_size;
157
158         if (quantized < this->value_min) this->value_min = quantized;
159         if (quantized > this->value_max) this->value_max = quantized;
160         this->value_hitcount_map [quantized] ++;
161       }
162
163     void reset (host_int_4)
164       {
165         this->value_hitcount_map.clear ();
166         this->value_min = ~0;
167         this->value_max = 0;
168         value_count = 0;
169       }
170
171
172     // Write given host_int_X in target byte order
173     template <typename IntType>
174     void put_bytes (ostream& o, IntType v, unsigned count)
175       {
176
177         switch (this->output_file_format)
178           {
179           case endian_little:
180             {
181               sid::any_int<IntType, false> lv = v;
182               for (unsigned i=0; i<count; i++)
183                 o.put (lv.read_byte (i));
184             }
185             break;
186
187           case endian_big:
188             {
189               sid::any_int<IntType, true> bv = v;
190               for (unsigned i=0; i<count; i++)
191                 o.put (bv.read_byte (i));
192             }
193             break;
194
195           default:
196             assert (0);
197           }
198       }
199
200     void put_bytes (ostream& o, const char* v, unsigned count)
201       {
202         for (unsigned i=0; i<count; i++)
203           {
204             o.put (*v);
205             if (*v) v++;  // advance unless we've hit NULL terminator
206           }
207       }
208
209
210     void store (host_int_4)
211       {
212         // Fetch endianness from target CPU
213         if (this->output_file_format == endian_unknown)
214           {
215             string value = this->target_component->attribute_value ("endian");
216             component::status s = parse_attribute (value, this->output_file_format);
217             if (s != component::ok)
218               this->output_file_format = endian_unknown;
219           }
220         if (this->output_file_format == endian_unknown)
221           {
222             cerr << "sw-profile-gprof: Unknown endianness for output file." << endl;
223             return;
224           }
225
226         ofstream of (this->output_file.c_str ());
227         if (! of.good())
228           {
229             cerr << "sw-profile-gprof: Error opening "
230                  << this->output_file << ":" << std_error_string();
231             return;
232           }
233
234         // write gmon header
235         put_bytes (of, "gmon", 4);             // gmon_hdr.cookie
236         // version number (1) in target-endian
237         put_bytes (of, host_int_4(1), 4);      // gmon_hdr.version = GMON_VERSION
238         // 12 bytes of padding
239         put_bytes (of, host_int_4(0), 4);      // gmon_hdr.spare
240         put_bytes (of, host_int_4(0), 4);      // gmon_hdr.spare
241         put_bytes (of, host_int_4(0), 4);      // gmon_hdr.spare
242
243         // We may have to loop and dump out several adjacent histogram
244         // tables, because histogram bucket count overflow.  The
245         // bucket counts are limited to 16 bits, but a 32-bit counter
246         // in gprof may be accumulated my multiple overlapping
247         // histogram tables.  We copy the histogram table here, since
248         // its counters will be decremented by up to 2**16-1 per
249         // iteration.
250         hitcount_map_t value_hitcount_map_copy = this->value_hitcount_map;
251         while (true)
252           {
253             // write a new histogram record
254             // GMON_Record_Tag
255             put_bytes (of, host_int_1(0), 1);      // GMON_TAG_TIME_HIST
256             // gmon_hist_hdr
257             put_bytes (of, this->value_min, 4);    // gmon_hist_hdr.low_pc
258             put_bytes (of, this->value_max, 4);    // gmon_hist_hdr.high_pc
259             assert (this->bucket_size != 0);
260             host_int_4 num_buckets = 1 + (this->value_max - this->value_min) / this->bucket_size;
261             put_bytes (of, num_buckets, 4);        // gmon_hist_hdr.hist_size
262             // XXX: actual prof_rate not available here ...
263             put_bytes (of, host_int_4(1), 4);      // gmon_hist_hdr.prof_rate
264             put_bytes (of, "tick", 15);            // gmon_hist_hdr.dimen
265             put_bytes (of, "t", 1);                // gmon_hist_hdr.dimen_abbrev
266
267             // Dump out histogram counts
268             bool overflow = false;
269             for (host_int_4 bucket = this->value_min;
270                  bucket <= this->value_max;
271                  bucket += this->bucket_size)
272               {
273                 const host_int_4 max_count = 65535;
274                 host_int_4 count = 0;
275
276                 // Check if this bucket exists by find() instead of a
277                 // blind []-lookup, because the latter would allocate
278                 // fresh & useless 0-count buckets for all non-touched
279                 // values.
280                 hitcount_map_t::iterator b = value_hitcount_map_copy.find (bucket);
281                 if (b != value_hitcount_map_copy.end())
282                   count = b->second;
283
284                 if (count > max_count) // overflow!
285                   {
286                     put_bytes (of, host_int_2(max_count), 2);
287                     b->second -= max_count;
288                     overflow = true;
289                   }
290                 else
291                   {
292                     put_bytes (of, host_int_2(count), 2);
293                   }
294               }
295
296             if (!overflow)
297               break;
298           }
299
300         of.close ();
301       }
302
303
304   public:
305     gprof_component ():
306       value_count (0),
307       value_min (~0),
308       value_max (0),
309       bucket_size (1), // != 0
310       target_attribute ("pc"),
311       target_component (0),
312       output_file ("gmon.out"),
313       output_file_format (endian_unknown),
314       accumulate_pin (this, & gprof_component::accumulate),
315       reset_pin (this, & gprof_component::reset),
316       store_pin (this, & gprof_component::store)
317       {
318         add_pin ("sample", & this->accumulate_pin);
319         add_attribute ("sample", & this->accumulate_pin, "pin");
320         add_pin ("reset", & this->reset_pin);
321         add_attribute ("reset", & this->reset_pin, "pin");
322         add_pin ("store", & this->store_pin);
323         add_attribute ("store", & this->store_pin, "pin");
324         add_attribute_virtual ("bucket-size", this,
325                                & gprof_component::bucket_size_get,
326                                & gprof_component::bucket_size_set,
327                                "setting");
328         add_attribute_ro ("value-min", & this->value_min, "register");
329         add_attribute_ro ("value-max", & this->value_max, "register");
330         add_attribute_ro ("value-count", & this->value_count, "register");
331         add_attribute ("value-attribute", & this->target_attribute, "setting");
332         add_attribute ("output-file", & this->output_file, "setting");
333         add_attribute ("output-file-endianness", & this->output_file_format, "setting");
334         add_uni_relation ("target-component", & this->target_component);
335       }
336   };
337
338
339
340 // ----------------------------------------------------------------------------
341
342   static
343   vector<string>
344   list_types()
345 {
346   vector<string> types;
347   types.push_back("sw-profile-gprof");
348   return types;
349 }
350   
351   
352   static
353   component*
354   create(const string& typeName)
355 {
356   if (typeName == "sw-profile-gprof")
357     return new gprof_component ();
358
359   return 0;
360 }
361
362
363   static
364   void
365   do_delete(component* c)
366 {
367   delete dynamic_cast<gprof_component*>(c);
368 }
369
370   
371 } // end namespace
372
373
374
375 // static object in root namespace
376 extern const sid::component_library prof_component_library;
377
378 const sid::component_library prof_component_library DLLEXPORT = 
379 {
380   sid::COMPONENT_LIBRARY_MAGIC,
381   & profiling_components::list_types, 
382   & profiling_components::create,
383   & profiling_components::do_delete
384 };
385