blob: 6550f21f9a5e73c86b75d11f17490ac1c23afbdb [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
2 * @file opgprof.cpp
3 * Implement opgprof utility
4 *
5 * @remark Copyright 2003 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 */
11
12#include <iostream>
13#include <cstdio>
14
15#include "op_header.h"
16#include "profile.h"
17#include "op_libiberty.h"
18#include "op_fileio.h"
19#include "string_filter.h"
20#include "profile_container.h"
21#include "arrange_profiles.h"
22#include "image_errors.h"
23#include "opgprof_options.h"
24#include "cverb.h"
25#include "op_file.h"
26
27using namespace std;
28
29extern profile_classes classes;
30
31namespace {
32
33#define GMON_VERSION 1
34#define GMON_TAG_TIME_HIST 0
35#define GMON_TAG_CG_ARC 1
36
37struct gmon_hdr {
38 char cookie[4];
39 u32 version;
40 u32 spare[3];
41};
42
43
44void op_write_vma(FILE * fp, op_bfd const & abfd, bfd_vma vma)
45{
46 // bfd vma write size is a per binary property not a bfd
47 // configuration property
48 switch (abfd.bfd_arch_bits_per_address()) {
49 case 32:
50 op_write_u32(fp, vma);
51 break;
52 case 64:
53 op_write_u64(fp, vma);
54 break;
55 default:
56 cerr << "oprofile: unknown vma size for this binary\n";
57 exit(EXIT_FAILURE);
58 }
59}
60
61
62void get_vma_range(bfd_vma & min, bfd_vma & max,
63 profile_container const & samples)
64{
65 min = bfd_vma(-1);
66 max = 0;
67
68 sample_container::samples_iterator it = samples.begin();
69 sample_container::samples_iterator end = samples.end();
70 for (; it != end ; ++it) {
71 if (it->second.vma < min)
72 min = it->second.vma;
73 if (it->second.vma > max)
74 max = it->second.vma;
75 }
76
77 if (min == bfd_vma(-1))
78 min = 0;
79 // we must return a range [min, max) not a range [min, max]
80 if (max != 0)
81 max += 1;
82}
83
84
85/**
86 * @param abfd bfd object
87 * @param samples_files profile container to act on
88 * @param gap a power of 2
89 *
90 * return true if all sample in samples_files are at least aligned on gap. This
91 * function is used to get at runtime the right size of gprof bin size
92 * reducing gmon.out on arch with fixed size instruction length
93 *
94 */
95bool aligned_samples(profile_container const & samples, int gap)
96{
97 sample_container::samples_iterator it = samples.begin();
98 sample_container::samples_iterator end = samples.end();
99 for (; it != end ; ++it) {
100 if (it->second.vma % gap)
101 return false;
102 }
103
104 return true;
105}
106
107
108void output_cg(FILE * fp, op_bfd const & abfd, profile_t const & cg_db)
109{
110 opd_header const & header = cg_db.get_header();
111 bfd_vma offset = 0;
112 if (header.is_kernel)
113 offset = abfd.get_start_offset(0);
114 else
115 offset = header.anon_start;
116
117 profile_t::iterator_pair p_it = cg_db.samples_range();
118 for (; p_it.first != p_it.second; ++p_it.first) {
119 bfd_vma from = p_it.first.vma() >> 32;
120 bfd_vma to = p_it.first.vma() & 0xffffffff;
121
122 op_write_u8(fp, GMON_TAG_CG_ARC);
123 op_write_vma(fp, abfd, abfd.offset_to_pc(from + offset));
124 op_write_vma(fp, abfd, abfd.offset_to_pc(to + offset));
125 u32 count = p_it.first.count();
126 if (count != p_it.first.count()) {
127 count = (u32)-1;
128 cerr << "Warning: capping sample count by "
129 << p_it.first.count() - count << endl;
130 }
131 op_write_u32(fp, p_it.first.count());
132 }
133}
134
135
136void output_gprof(op_bfd const & abfd, profile_container const & samples,
137 profile_t const & cg_db, string const & gmon_filename)
138{
139 static gmon_hdr hdr = { { 'g', 'm', 'o', 'n' }, GMON_VERSION, {0, 0, 0 } };
140
141 bfd_vma low_pc;
142 bfd_vma high_pc;
143
144 /* FIXME worth to try more multiplier ? */
145 int multiplier = 2;
146 if (aligned_samples(samples, 4))
147 multiplier = 8;
148
149 cverb << vdebug << "opgrof multiplier: " << multiplier << endl;
150
151 get_vma_range(low_pc, high_pc, samples);
152
153 cverb << vdebug << "low_pc: " << hex << low_pc << " " << "high_pc: "
154 << high_pc << dec << endl;
155
156 // round-down low_pc to ensure bin number is correct in the inner loop
157 low_pc = (low_pc / multiplier) * multiplier;
158 // round-up high_pc to ensure a correct histsize calculus
159 high_pc = ((high_pc + multiplier - 1) / multiplier) * multiplier;
160
161 cverb << vdebug << "low_pc: " << hex << low_pc << " " << "high_pc: "
162 << high_pc << dec << endl;
163
164 size_t histsize = (high_pc - low_pc) / multiplier;
165
166 // FIXME: must we skip the flat profile write if histsize == 0 ?
167 // (this can occur with callgraph w/o samples to the binary) but in
168 // this case user must gprof --no-flat-profile which is a bit boring
169 // and result *seems* weirds.
170
171 FILE * fp = op_open_file(gmon_filename.c_str(), "w");
172
173 op_write_file(fp, &hdr, sizeof(gmon_hdr));
174 op_write_u8(fp, GMON_TAG_TIME_HIST);
175
176 op_write_vma(fp, abfd, low_pc);
177 op_write_vma(fp, abfd, high_pc);
178 /* size of histogram */
179 op_write_u32(fp, histsize);
180 /* profiling rate */
181 op_write_u32(fp, 1);
182 op_write_file(fp, "samples\0\0\0\0\0\0\0\0", 15);
183 /* abbreviation */
184 op_write_u8(fp, '1');
185
186 u16 * hist = (u16*)xcalloc(histsize, sizeof(u16));
187
188 profile_container::symbol_choice choice;
189 choice.threshold = options::threshold;
190 symbol_collection symbols = samples.select_symbols(choice);
191
192 symbol_collection::const_iterator sit = symbols.begin();
193 symbol_collection::const_iterator send = symbols.end();
194
195 for (; sit != send; ++sit) {
196 sample_container::samples_iterator it = samples.begin(*sit);
197 sample_container::samples_iterator end = samples.end(*sit);
198 for (; it != end ; ++it) {
199 u32 pos = (it->second.vma - low_pc) / multiplier;
200 count_type count = it->second.counts[0];
201
202 if (pos >= histsize) {
203 cerr << "Bogus histogram bin " << pos
204 << ", larger than " << pos << " !\n";
205 continue;
206 }
207
208 if (hist[pos] + count > (u16)-1) {
209 hist[pos] = (u16)-1;
210 cerr << "Warning: capping sample count by "
211 << hist[pos] + count - ((u16)-1) << endl;
212 } else {
213 hist[pos] += (u16)count;
214 }
215 }
216 }
217
218 op_write_file(fp, hist, histsize * sizeof(u16));
219
220 if (!cg_db.empty())
221 output_cg(fp, abfd, cg_db);
222
223 op_close_file(fp);
224
225 free(hist);
226}
227
228
229void
230load_samples(op_bfd const & abfd, list<profile_sample_files> const & files,
231 string const & image, profile_container & samples)
232{
233 list<profile_sample_files>::const_iterator it = files.begin();
234 list<profile_sample_files>::const_iterator const end = files.end();
235
236 for (; it != end; ++it) {
237 // we can get call graph w/o any samples to the binary
238 if (it->sample_filename.empty())
239 continue;
240
241 cverb << vsfile << "loading flat samples files : "
242 << it->sample_filename << endl;
243
244 profile_t profile;
245
246 profile.add_sample_file(it->sample_filename);
247 profile.set_offset(abfd);
248
249 check_mtime(abfd.get_filename(), profile.get_header());
250
251 samples.add(profile, abfd, image, 0);
252 }
253}
254
255
256void load_cg(profile_t & cg_db, list<profile_sample_files> const & files)
257{
258 list<profile_sample_files>::const_iterator it = files.begin();
259 list<profile_sample_files>::const_iterator const end = files.end();
260
261 /* the list of non cg files is a super set of the list of cg file
262 * (module always log a samples to non-cg files before logging
263 * call stack) so by using the list of non-cg file we are sure to get
264 * all existing cg files.
265 */
266 for (; it != end; ++it) {
267 list<string>::const_iterator cit;
268 list<string>::const_iterator const cend = it->cg_files.end();
269 for (cit = it->cg_files.begin(); cit != cend; ++cit) {
270 // FIXME: do we need filtering ?
271 /* We can't handle start_offset now but after splitting
272 * data in from/to eip. */
273 cverb << vsfile << "loading cg samples file : "
274 << *cit << endl;
275 cg_db.add_sample_file(*cit);
276 }
277 }
278}
279
280
281int opgprof(options::spec const & spec)
282{
283 handle_options(spec);
284
285 profile_container samples(false, true, classes.extra_found_images);
286
287 bool ok = image_profile.error == image_ok;
288 // FIXME: symbol_filter would be allowed through option
289 op_bfd abfd(image_profile.image, string_filter(),
290 classes.extra_found_images, ok);
291 if (!ok && image_profile.error == image_ok)
292 image_profile.error = image_format_failure;
293
294 if (image_profile.error != image_ok) {
295 report_image_error(image_profile, true,
296 classes.extra_found_images);
297 exit(EXIT_FAILURE);
298 }
299
300 profile_t cg_db;
301
302 image_group_set const & groups = image_profile.groups[0];
303 image_group_set::const_iterator it;
304 for (it = groups.begin(); it != groups.end(); ++it) {
305 load_samples(abfd, it->files, image_profile.image, samples);
306
307 load_cg(cg_db, it->files);
308 }
309
310 output_gprof(abfd, samples, cg_db, options::gmon_filename);
311
312 return 0;
313}
314
315
316} // anonymous namespace
317
318
319int main(int argc, char const * argv[])
320{
321 return run_pp_tool(argc, argv, opgprof);
322}