1 // gprof.cxx - A component for generating gprof profile data. -*- C++ -*-
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.
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>
39 namespace profiling_components
41 using sid::host_int_8;
42 using sid::host_int_4;
43 using sid::host_int_2;
44 using sid::host_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;
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;
79 // ----------------------------------------------------------------------------
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
89 typedef hash_map<host_int_4,host_int_4> hitcount_map_t;
91 typedef map<host_int_4,host_int_4> hitcount_map_t;
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;
100 string target_attribute;
101 component* target_component;
104 endian output_file_format;
106 callback_pin<gprof_component> accumulate_pin;
107 callback_pin<gprof_component> reset_pin;
108 callback_pin<gprof_component> store_pin;
111 string bucket_size_get()
113 return make_attribute (this->bucket_size);
116 component::status bucket_size_set(const string& str)
118 host_int_4 new_bucket_size;
119 component::status s = parse_attribute (str, new_bucket_size);
121 // Reject malformed input
122 if (s != component::ok) return s;
124 // Reject change if we already have samples
125 if ((this->value_count != 0) &&
126 (this->bucket_size != new_bucket_size))
128 cerr << "sw-profile-gprof: invalid time to change bucket size" << endl;
129 return component::bad_value;
132 // Reject invalid size
133 if (new_bucket_size == 0)
135 cerr << "sw-profile-gprof: invalid null bucket size." << endl;
136 return component::bad_value;
139 this->bucket_size = new_bucket_size;
140 return component::ok;
144 void accumulate (host_int_4)
146 if (! this->target_component) return;
148 string value_str = this->target_component->attribute_value (this->target_attribute);
150 component::status s = parse_attribute (value_str, value);
151 if (s != component::ok) return;
155 assert (this->bucket_size != 0);
156 host_int_4 quantized = (value / this->bucket_size) * this->bucket_size;
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] ++;
163 void reset (host_int_4)
165 this->value_hitcount_map.clear ();
166 this->value_min = ~0;
172 // Write given host_int_X in target byte order
173 template <typename IntType>
174 void put_bytes (ostream& o, IntType v, unsigned count)
177 switch (this->output_file_format)
181 sid::any_int<IntType, false> lv = v;
182 for (unsigned i=0; i<count; i++)
183 o.put (lv.read_byte (i));
189 sid::any_int<IntType, true> bv = v;
190 for (unsigned i=0; i<count; i++)
191 o.put (bv.read_byte (i));
200 void put_bytes (ostream& o, const char* v, unsigned count)
202 for (unsigned i=0; i<count; i++)
205 if (*v) v++; // advance unless we've hit NULL terminator
210 void store (host_int_4)
212 // Fetch endianness from target CPU
213 if (this->output_file_format == endian_unknown)
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;
220 if (this->output_file_format == endian_unknown)
222 cerr << "sw-profile-gprof: Unknown endianness for output file." << endl;
226 ofstream of (this->output_file.c_str ());
229 cerr << "sw-profile-gprof: Error opening "
230 << this->output_file << ":" << std_error_string();
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
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
250 hitcount_map_t value_hitcount_map_copy = this->value_hitcount_map;
253 // write a new histogram record
255 put_bytes (of, host_int_1(0), 1); // GMON_TAG_TIME_HIST
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
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)
273 const host_int_4 max_count = 65535;
274 host_int_4 count = 0;
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
280 hitcount_map_t::iterator b = value_hitcount_map_copy.find (bucket);
281 if (b != value_hitcount_map_copy.end())
284 if (count > max_count) // overflow!
286 put_bytes (of, host_int_2(max_count), 2);
287 b->second -= max_count;
292 put_bytes (of, host_int_2(count), 2);
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)
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,
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);
340 // ----------------------------------------------------------------------------
346 vector<string> types;
347 types.push_back("sw-profile-gprof");
354 create(const string& typeName)
356 if (typeName == "sw-profile-gprof")
357 return new gprof_component ();
365 do_delete(component* c)
367 delete dynamic_cast<gprof_component*>(c);
375 // static object in root namespace
376 extern const sid::component_library prof_component_library;
378 const sid::component_library prof_component_library DLLEXPORT =
380 sid::COMPONENT_LIBRARY_MAGIC,
381 & profiling_components::list_types,
382 & profiling_components::create,
383 & profiling_components::do_delete