00001
00012 #include <iostream>
00013 #include <cstdio>
00014
00015 #include "op_header.h"
00016 #include "profile.h"
00017 #include "op_libiberty.h"
00018 #include "op_fileio.h"
00019 #include "string_filter.h"
00020 #include "profile_container.h"
00021 #include "arrange_profiles.h"
00022 #include "image_errors.h"
00023 #include "opgprof_options.h"
00024 #include "cverb.h"
00025 #include "op_file.h"
00026
00027 using namespace std;
00028
00029 extern profile_classes classes;
00030
00031 namespace {
00032
00033 #define GMON_VERSION 1
00034 #define GMON_TAG_TIME_HIST 0
00035 #define GMON_TAG_CG_ARC 1
00036
00037 struct gmon_hdr {
00038 char cookie[4];
00039 u32 version;
00040 u32 spare[3];
00041 };
00042
00043
00044 void op_write_vma(FILE * fp, op_bfd const & abfd, bfd_vma vma)
00045 {
00046
00047
00048 switch (abfd.bfd_arch_bits_per_address()) {
00049 case 32:
00050 op_write_u32(fp, vma);
00051 break;
00052 case 64:
00053 op_write_u64(fp, vma);
00054 break;
00055 default:
00056 cerr << "oprofile: unknown vma size for this binary\n";
00057 exit(EXIT_FAILURE);
00058 }
00059 }
00060
00061
00062 void get_vma_range(bfd_vma & min, bfd_vma & max,
00063 profile_container const & samples)
00064 {
00065 min = bfd_vma(-1);
00066 max = 0;
00067
00068 sample_container::samples_iterator it = samples.begin();
00069 sample_container::samples_iterator end = samples.end();
00070 for (; it != end ; ++it) {
00071 if (it->second.vma < min)
00072 min = it->second.vma;
00073 if (it->second.vma > max)
00074 max = it->second.vma;
00075 }
00076
00077 if (min == bfd_vma(-1))
00078 min = 0;
00079
00080 if (max != 0)
00081 max += 1;
00082 }
00083
00084
00095 bool aligned_samples(profile_container const & samples, int gap)
00096 {
00097 sample_container::samples_iterator it = samples.begin();
00098 sample_container::samples_iterator end = samples.end();
00099 for (; it != end ; ++it) {
00100 if (it->second.vma % gap)
00101 return false;
00102 }
00103
00104 return true;
00105 }
00106
00107
00108 void output_cg(FILE * fp, op_bfd const & abfd, profile_t const & cg_db)
00109 {
00110 opd_header const & header = cg_db.get_header();
00111 bfd_vma offset = 0;
00112 if (header.is_kernel)
00113 offset = abfd.get_start_offset(0);
00114 else
00115 offset = header.anon_start;
00116
00117 profile_t::iterator_pair p_it = cg_db.samples_range();
00118 for (; p_it.first != p_it.second; ++p_it.first) {
00119 bfd_vma from = p_it.first.vma() >> 32;
00120 bfd_vma to = p_it.first.vma() & 0xffffffff;
00121
00122 op_write_u8(fp, GMON_TAG_CG_ARC);
00123 op_write_vma(fp, abfd, abfd.offset_to_pc(from + offset));
00124 op_write_vma(fp, abfd, abfd.offset_to_pc(to + offset));
00125 u32 count = p_it.first.count();
00126 if (count != p_it.first.count()) {
00127 count = (u32)-1;
00128 cerr << "Warning: capping sample count by "
00129 << p_it.first.count() - count << endl;
00130 }
00131 op_write_u32(fp, p_it.first.count());
00132 }
00133 }
00134
00135
00136 void output_gprof(op_bfd const & abfd, profile_container const & samples,
00137 profile_t const & cg_db, string const & gmon_filename)
00138 {
00139 static gmon_hdr hdr = { { 'g', 'm', 'o', 'n' }, GMON_VERSION, {0, 0, 0 } };
00140
00141 bfd_vma low_pc;
00142 bfd_vma high_pc;
00143
00144
00145 int multiplier = 2;
00146 if (aligned_samples(samples, 4))
00147 multiplier = 8;
00148
00149 cverb << vdebug << "opgrof multiplier: " << multiplier << endl;
00150
00151 get_vma_range(low_pc, high_pc, samples);
00152
00153 cverb << vdebug << "low_pc: " << hex << low_pc << " " << "high_pc: "
00154 << high_pc << dec << endl;
00155
00156
00157 low_pc = (low_pc / multiplier) * multiplier;
00158
00159 high_pc = ((high_pc + multiplier - 1) / multiplier) * multiplier;
00160
00161 cverb << vdebug << "low_pc: " << hex << low_pc << " " << "high_pc: "
00162 << high_pc << dec << endl;
00163
00164 size_t histsize = (high_pc - low_pc) / multiplier;
00165
00166
00167
00168
00169
00170
00171 FILE * fp = op_open_file(gmon_filename.c_str(), "w");
00172
00173 op_write_file(fp, &hdr, sizeof(gmon_hdr));
00174 op_write_u8(fp, GMON_TAG_TIME_HIST);
00175
00176 op_write_vma(fp, abfd, low_pc);
00177 op_write_vma(fp, abfd, high_pc);
00178
00179 op_write_u32(fp, histsize);
00180
00181 op_write_u32(fp, 1);
00182 op_write_file(fp, "samples\0\0\0\0\0\0\0\0", 15);
00183
00184 op_write_u8(fp, '1');
00185
00186 u16 * hist = (u16*)xcalloc(histsize, sizeof(u16));
00187
00188 profile_container::symbol_choice choice;
00189 choice.threshold = options::threshold;
00190 symbol_collection symbols = samples.select_symbols(choice);
00191
00192 symbol_collection::const_iterator sit = symbols.begin();
00193 symbol_collection::const_iterator send = symbols.end();
00194
00195 for (; sit != send; ++sit) {
00196 sample_container::samples_iterator it = samples.begin(*sit);
00197 sample_container::samples_iterator end = samples.end(*sit);
00198 for (; it != end ; ++it) {
00199 u32 pos = (it->second.vma - low_pc) / multiplier;
00200 count_type count = it->second.counts[0];
00201
00202 if (pos >= histsize) {
00203 cerr << "Bogus histogram bin " << pos
00204 << ", larger than " << pos << " !\n";
00205 continue;
00206 }
00207
00208 if (hist[pos] + count > (u16)-1) {
00209 hist[pos] = (u16)-1;
00210 cerr << "Warning: capping sample count by "
00211 << hist[pos] + count - ((u16)-1) << endl;
00212 } else {
00213 hist[pos] += (u16)count;
00214 }
00215 }
00216 }
00217
00218 op_write_file(fp, hist, histsize * sizeof(u16));
00219
00220 if (!cg_db.empty())
00221 output_cg(fp, abfd, cg_db);
00222
00223 op_close_file(fp);
00224
00225 free(hist);
00226 }
00227
00228
00229 void
00230 load_samples(op_bfd const & abfd, list<profile_sample_files> const & files,
00231 string const & image, profile_container & samples)
00232 {
00233 list<profile_sample_files>::const_iterator it = files.begin();
00234 list<profile_sample_files>::const_iterator const end = files.end();
00235
00236 for (; it != end; ++it) {
00237
00238 if (it->sample_filename.empty())
00239 continue;
00240
00241 cverb << vsfile << "loading flat samples files : "
00242 << it->sample_filename << endl;
00243
00244 profile_t profile;
00245
00246 profile.add_sample_file(it->sample_filename);
00247 profile.set_offset(abfd);
00248
00249 check_mtime(abfd.get_filename(), profile.get_header());
00250
00251 samples.add(profile, abfd, image, 0);
00252 }
00253 }
00254
00255
00256 void load_cg(profile_t & cg_db, list<profile_sample_files> const & files)
00257 {
00258 list<profile_sample_files>::const_iterator it = files.begin();
00259 list<profile_sample_files>::const_iterator const end = files.end();
00260
00261
00262
00263
00264
00265
00266 for (; it != end; ++it) {
00267 list<string>::const_iterator cit;
00268 list<string>::const_iterator const cend = it->cg_files.end();
00269 for (cit = it->cg_files.begin(); cit != cend; ++cit) {
00270
00271
00272
00273 cverb << vsfile << "loading cg samples file : "
00274 << *cit << endl;
00275 cg_db.add_sample_file(*cit);
00276 }
00277 }
00278 }
00279
00280
00281 int opgprof(options::spec const & spec)
00282 {
00283 handle_options(spec);
00284
00285 profile_container samples(false, true, classes.extra_found_images);
00286
00287 bool ok = image_profile.error == image_ok;
00288
00289 op_bfd abfd(image_profile.image, string_filter(),
00290 classes.extra_found_images, ok);
00291 if (!ok && image_profile.error == image_ok)
00292 image_profile.error = image_format_failure;
00293
00294 if (image_profile.error != image_ok) {
00295 report_image_error(image_profile, true,
00296 classes.extra_found_images);
00297 exit(EXIT_FAILURE);
00298 }
00299
00300 profile_t cg_db;
00301
00302 image_group_set const & groups = image_profile.groups[0];
00303 image_group_set::const_iterator it;
00304 for (it = groups.begin(); it != groups.end(); ++it) {
00305 load_samples(abfd, it->files, image_profile.image, samples);
00306
00307 load_cg(cg_db, it->files);
00308 }
00309
00310 output_gprof(abfd, samples, cg_db, options::gmon_filename);
00311
00312 return 0;
00313 }
00314
00315
00316 }
00317
00318
00319 int main(int argc, char const * argv[])
00320 {
00321 return run_pp_tool(argc, argv, opgprof);
00322 }