1 /** 2 * @file profile_container.cpp 3 * profile file container 4 * 5 * @remark Copyright 2002 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Philippe Elie 9 * @author John Levon 10 */ 11 12 #include <set> 13 #include <vector> 14 #include <string> 15 #include <iostream> 16 #include <sstream> 17 #include <algorithm> 18 #include <numeric> 19 20 #include "symbol.h" 21 #include "op_header.h" 22 #include "profile.h" 23 #include "symbol_functors.h" 24 #include "profile_container.h" 25 #include "sample_container.h" 26 #include "symbol_container.h" 27 #include "populate_for_spu.h" 28 29 using namespace std; 30 31 namespace { 32 33 struct filename_by_samples { 34 filename_by_samples(debug_name_id id, double percent_) 35 : filename(id), percent(percent_) 36 {} 37 38 bool operator<(filename_by_samples const & lhs) const { 39 if (percent != lhs.percent) 40 return percent < lhs.percent; 41 return filename < lhs.filename; 42 } 43 44 debug_name_id filename; 45 // ratio of samples which belongs to this filename. 46 double percent; 47 }; 48 49 } // anon namespace 50 51 52 profile_container::profile_container(bool debug_info_, bool need_details_, 53 extra_images const & extra_) 54 : 55 symbols(new symbol_container), 56 samples(new sample_container), 57 debug_info(debug_info_), 58 need_details(need_details_), 59 extra_found_images(extra_) 60 { 61 } 62 63 64 profile_container::~profile_container() 65 { 66 } 67 68 69 // Post condition: 70 // the symbols/samples are sorted by increasing vma. 71 // the range of sample_entry inside each symbol entry are valid 72 // the samples_by_file_loc member var is correctly setup. 73 void profile_container::add(profile_t const & profile, 74 op_bfd const & abfd, string const & app_name, 75 size_t pclass) 76 { 77 string const image_name = abfd.get_filename(); 78 opd_header header = profile.get_header(); 79 80 for (symbol_index_t i = 0; i < abfd.syms.size(); ++i) { 81 82 unsigned long long start = 0, end = 0; 83 symbol_entry symb_entry; 84 85 abfd.get_symbol_range(i, start, end); 86 87 profile_t::iterator_pair p_it = 88 profile.samples_range(start, end); 89 count_type count = accumulate(p_it.first, p_it.second, 0ull); 90 91 // skip entries with no samples 92 if (count == 0) 93 continue; 94 95 symb_entry.sample.counts[pclass] = count; 96 total_count[pclass] += count; 97 98 symb_entry.size = end - start; 99 100 symb_entry.name = symbol_names.create(abfd.syms[i].name()); 101 symb_entry.sym_index = i; 102 103 symb_entry.sample.file_loc.linenr = 0; 104 if (debug_info) { 105 string filename; 106 if (abfd.get_linenr(i, start, filename, 107 symb_entry.sample.file_loc.linenr)) { 108 symb_entry.sample.file_loc.filename = 109 debug_names.create(filename); 110 } 111 } 112 113 symb_entry.image_name = image_names.create(image_name); 114 symb_entry.app_name = image_names.create(app_name); 115 116 symb_entry.sample.vma = abfd.syms[i].vma(); 117 if ((header.spu_profile == cell_spu_profile) && 118 header.embedded_offset) { 119 symb_entry.spu_offset = header.embedded_offset; 120 symb_entry.embedding_filename = 121 image_names.create(abfd.get_embedding_filename()); 122 } else { 123 symb_entry.spu_offset = 0; 124 } 125 symbol_entry const * symbol = symbols->insert(symb_entry); 126 127 if (need_details) 128 add_samples(abfd, i, p_it, symbol, pclass, start); 129 } 130 } 131 132 133 void 134 profile_container::add_samples(op_bfd const & abfd, symbol_index_t sym_index, 135 profile_t::iterator_pair const & p_it, 136 symbol_entry const * symbol, size_t pclass, 137 unsigned long start) 138 { 139 bfd_vma base_vma = abfd.syms[sym_index].vma(); 140 141 profile_t::const_iterator it; 142 for (it = p_it.first; it != p_it.second ; ++it) { 143 sample_entry sample; 144 145 sample.counts[pclass] = it.count(); 146 147 sample.file_loc.linenr = 0; 148 if (debug_info) { 149 string filename; 150 if (abfd.get_linenr(sym_index, it.vma(), filename, 151 sample.file_loc.linenr)) { 152 sample.file_loc.filename = 153 debug_names.create(filename); 154 } 155 } 156 157 sample.vma = (it.vma() - start) + base_vma; 158 159 samples->insert(symbol, sample); 160 } 161 } 162 163 164 symbol_collection const 165 profile_container::select_symbols(symbol_choice & choice) const 166 { 167 symbol_collection result; 168 169 double const threshold = choice.threshold / 100.0; 170 171 symbol_container::symbols_t::iterator it = symbols->begin(); 172 symbol_container::symbols_t::iterator const end = symbols->end(); 173 174 for (; it != end; ++it) { 175 if (choice.match_image 176 && (image_names.name(it->image_name) != choice.image_name)) 177 continue; 178 179 double const percent = 180 op_ratio(it->sample.counts[0], total_count[0]); 181 182 if (percent >= threshold) { 183 result.push_back(&*it); 184 185 choice.hints = it->output_hint(choice.hints); 186 } 187 } 188 189 return result; 190 } 191 192 193 vector<debug_name_id> const 194 profile_container::select_filename(double threshold) const 195 { 196 set<debug_name_id> filename_set; 197 198 threshold /= 100.0; 199 200 // Trying to iterate on symbols to create the set of filenames which 201 // contain sample does not work: a symbol can contain samples and this 202 // symbol is in a source file that contain zero sample because only 203 // inline function in this source file contains samples. 204 sample_container::samples_iterator sit = samples->begin(); 205 sample_container::samples_iterator const send = samples->end(); 206 207 for (; sit != send; ++sit) { 208 debug_name_id name_id = sit->second.file_loc.filename; 209 if (name_id.set()) 210 filename_set.insert(name_id); 211 } 212 213 // Give a sort order on filename for the selected pclass. 214 vector<filename_by_samples> file_by_samples; 215 216 set<debug_name_id>::const_iterator it = filename_set.begin(); 217 set<debug_name_id>::const_iterator const end = filename_set.end(); 218 for (; it != end; ++it) { 219 // FIXME: is samples_count() the right interface now ? 220 count_array_t counts = samples_count(*it); 221 222 double const ratio = op_ratio(counts[0], total_count[0]); 223 filename_by_samples const f(*it, ratio); 224 225 file_by_samples.push_back(f); 226 } 227 228 // now sort the file_by_samples entry. 229 sort(file_by_samples.begin(), file_by_samples.end()); 230 231 // 2.91.66 doesn't like const_reverse_iterator in this context 232 vector<filename_by_samples>::reverse_iterator cit 233 = file_by_samples.rbegin(); 234 vector<filename_by_samples>::reverse_iterator const cend 235 = file_by_samples.rend(); 236 237 vector<debug_name_id> result; 238 for (; cit != cend; ++cit) { 239 if (cit->percent >= threshold) 240 result.push_back(cit->filename); 241 } 242 243 return result; 244 } 245 246 247 count_array_t profile_container::samples_count() const 248 { 249 return total_count; 250 } 251 252 253 // Rest here are delegated to our private implementation. 254 255 symbol_entry const * 256 profile_container::find_symbol(string const & image_name, bfd_vma vma) const 257 { 258 return symbols->find_by_vma(image_name, vma); 259 } 260 261 262 symbol_collection const 263 profile_container::find_symbol(debug_name_id filename, size_t linenr) const 264 { 265 return symbols->find(filename, linenr); 266 } 267 268 269 symbol_collection const 270 profile_container::select_symbols(debug_name_id filename) const 271 { 272 return symbols->find(filename); 273 } 274 275 sample_entry const * 276 profile_container::find_sample(symbol_entry const * symbol, bfd_vma vma) const 277 { 278 return samples->find_by_vma(symbol, vma); 279 } 280 281 282 count_array_t profile_container::samples_count(debug_name_id filename_id) const 283 { 284 return samples->accumulate_samples(filename_id); 285 } 286 287 288 count_array_t profile_container::samples_count(debug_name_id filename, 289 size_t linenr) const 290 { 291 return samples->accumulate_samples(filename, linenr); 292 } 293 294 295 sample_container::samples_iterator 296 profile_container::begin(symbol_entry const * symbol) const 297 { 298 return samples->begin(symbol); 299 } 300 301 302 sample_container::samples_iterator 303 profile_container::end(symbol_entry const * symbol) const 304 { 305 return samples->end(symbol); 306 } 307 308 309 sample_container::samples_iterator profile_container::begin() const 310 { 311 return samples->begin(); 312 } 313 314 315 sample_container::samples_iterator profile_container::end() const 316 { 317 return samples->end(); 318 } 319 320 symbol_entry const * profile_container::find(symbol_entry const & symbol) const 321 { 322 return symbols->find(symbol); 323 } 324 325 symbol_container::symbols_t::iterator profile_container::begin_symbol() const 326 { 327 return symbols->begin(); 328 } 329 330 symbol_container::symbols_t::iterator profile_container::end_symbol() const 331 { 332 return symbols->end(); 333 } 334