~arosales/test/oprofile

« back to all changes in this revision

Viewing changes to libpp/format_output.cpp

  • Committer: Antonio Rosales
  • Date: 2013-03-28 08:40:26 UTC
  • Revision ID: antonio.rosales@canonical.com-20130328084026-gpqns1mkqd7cnr05
Move files up one directory.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file format_output.cpp
 
3
 * outputting format for symbol lists
 
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
/* older glibc has C99 INFINITY in _GNU_SOURCE */
 
13
#ifndef _GNU_SOURCE
 
14
#define _GNU_SOURCE
 
15
#endif
 
16
 
 
17
#include <cassert>
 
18
#include <sstream>
 
19
#include <iomanip>
 
20
#include <iostream>
 
21
#include <cmath>
 
22
 
 
23
#include "string_manip.h"
 
24
#include "string_filter.h"
 
25
 
 
26
#include "format_output.h"
 
27
#include "profile_container.h"
 
28
#include "callgraph_container.h"
 
29
#include "diff_container.h"
 
30
#include "arrange_profiles.h"
 
31
#include "xml_output.h"
 
32
#include "xml_utils.h"
 
33
#include "cverb.h"
 
34
 
 
35
using namespace std;
 
36
 
 
37
namespace {
 
38
 
 
39
 
 
40
string const get_linenr_info(file_location const floc, bool lf)
 
41
{
 
42
        ostringstream out;
 
43
 
 
44
        string const & filename = lf
 
45
                ? debug_names.name(floc.filename)
 
46
                : debug_names.basename(floc.filename);
 
47
 
 
48
        if (!filename.empty())
 
49
                out << filename << ":" << floc.linenr;
 
50
        else 
 
51
                out << "(no location information)";
 
52
 
 
53
        return out.str();
 
54
}
 
55
 
 
56
string get_vma(bfd_vma vma, bool vma_64)
 
57
{
 
58
        ostringstream out;
 
59
        int width = vma_64 ? 16 : 8;
 
60
 
 
61
        out << hex << setw(width) << setfill('0') << vma;
 
62
 
 
63
        return out.str();
 
64
}
 
65
 
 
66
string get_percent(count_type dividend, count_type divisor)
 
67
{
 
68
        double ratio = op_ratio(dividend, divisor);
 
69
 
 
70
        return ::format_percent(ratio * 100, percent_int_width,
 
71
                             percent_fract_width);
 
72
}
 
73
 
 
74
bool extract_linenr_info(string const & info, string & file, size_t & line)
 
75
{
 
76
        line = 0;
 
77
        file = "";
 
78
        string::size_type colon_pos = info.find(":");
 
79
 
 
80
        if (colon_pos == string::npos)
 
81
                return false;
 
82
 
 
83
        file = info.substr(0, colon_pos);
 
84
        istringstream is_info(info.substr(colon_pos+1));
 
85
        is_info >> line;
 
86
        return true;
 
87
}
 
88
 
 
89
 
 
90
} // anonymous namespace
 
91
 
 
92
namespace format_output {
 
93
 
 
94
formatter::formatter(extra_images const & extra)
 
95
        :
 
96
        nr_classes(1),
 
97
        flags(ff_none),
 
98
        vma_64(false),
 
99
        long_filenames(false),
 
100
        need_header(true),
 
101
        extra_found_images(extra)
 
102
{
 
103
        format_map[ff_vma] = field_description(9, "vma", &formatter::format_vma);
 
104
        format_map[ff_nr_samples] = field_description(9, "samples", &formatter::format_nr_samples);
 
105
        format_map[ff_nr_samples_cumulated] = field_description(14, "cum. samples", &formatter::format_nr_cumulated_samples);
 
106
        format_map[ff_percent] = field_description(9, "%", &formatter::format_percent);
 
107
        format_map[ff_percent_cumulated] = field_description(11, "cum. %", &formatter::format_cumulated_percent);
 
108
        format_map[ff_linenr_info] = field_description(28, "linenr info", &formatter::format_linenr_info);
 
109
        format_map[ff_image_name] = field_description(25, "image name", &formatter::format_image_name);
 
110
        format_map[ff_app_name] = field_description(25, "app name", &formatter::format_app_name);
 
111
        format_map[ff_symb_name] = field_description(30, "symbol name", &formatter::format_symb_name);
 
112
        format_map[ff_percent_details] = field_description(9, "%", &formatter::format_percent_details);
 
113
        format_map[ff_percent_cumulated_details] = field_description(10, "cum. %", &formatter::format_cumulated_percent_details);
 
114
        format_map[ff_diff] = field_description(10, "diff %", &formatter::format_diff);
 
115
}
 
116
 
 
117
 
 
118
formatter::~formatter()
 
119
{
 
120
}
 
121
 
 
122
 
 
123
void formatter::set_nr_classes(size_t nr)
 
124
{
 
125
        nr_classes = nr;
 
126
}
 
127
 
 
128
 
 
129
void formatter::add_format(format_flags flag)
 
130
{
 
131
        flags = static_cast<format_flags>(flags | flag);
 
132
}
 
133
 
 
134
 
 
135
void formatter::show_header(bool on_off)
 
136
{
 
137
        need_header = on_off;
 
138
}
 
139
 
 
140
 
 
141
void formatter::vma_format_64bit(bool on_off)
 
142
{
 
143
        vma_64 = on_off;
 
144
}
 
145
 
 
146
 
 
147
void formatter::show_long_filenames(bool on_off)
 
148
{
 
149
        long_filenames = on_off;
 
150
}
 
151
 
 
152
 
 
153
void formatter::show_global_percent(bool on_off)
 
154
{
 
155
        global_percent = on_off;
 
156
}
 
157
 
 
158
 
 
159
void formatter::output_header(ostream & out)
 
160
{
 
161
        if (!need_header)
 
162
                return;
 
163
 
 
164
        size_t padding = 0;
 
165
 
 
166
        // first output the vma field
 
167
        if (flags & ff_vma)
 
168
                padding = output_header_field(out, ff_vma, padding);
 
169
 
 
170
        // the field repeated for each profile class
 
171
        for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) {
 
172
                if (flags & ff_nr_samples)
 
173
                        padding = output_header_field(out,
 
174
                              ff_nr_samples, padding);
 
175
 
 
176
                if (flags & ff_nr_samples_cumulated)
 
177
                        padding = output_header_field(out, 
 
178
                               ff_nr_samples_cumulated, padding);
 
179
 
 
180
                if (flags & ff_percent)
 
181
                        padding = output_header_field(out,
 
182
                               ff_percent, padding);
 
183
 
 
184
                if (flags & ff_percent_cumulated)
 
185
                        padding = output_header_field(out,
 
186
                               ff_percent_cumulated, padding);
 
187
 
 
188
                if (flags & ff_diff)
 
189
                        padding = output_header_field(out,
 
190
                                ff_diff, padding);
 
191
 
 
192
                if (flags & ff_percent_details)
 
193
                        padding = output_header_field(out,
 
194
                               ff_percent_details, padding);
 
195
 
 
196
                if (flags & ff_percent_cumulated_details)
 
197
                        padding = output_header_field(out,
 
198
                               ff_percent_cumulated_details, padding);
 
199
        }
 
200
 
 
201
        // now the remaining field
 
202
        if (flags & ff_linenr_info)
 
203
                padding = output_header_field(out, ff_linenr_info, padding);
 
204
 
 
205
        if (flags & ff_image_name)
 
206
                padding = output_header_field(out, ff_image_name, padding);
 
207
 
 
208
        if (flags & ff_app_name)
 
209
                padding = output_header_field(out, ff_app_name, padding);
 
210
 
 
211
        if (flags & ff_symb_name)
 
212
                padding = output_header_field(out, ff_symb_name, padding);
 
213
 
 
214
        out << "\n";
 
215
}
 
216
 
 
217
 
 
218
/// describe each possible field of colummned output.
 
219
// FIXME: use % of the screen width here. sum of % equal to 100, then calculate
 
220
// ratio between 100 and the selected % to grow non fixed field use also
 
221
// lib[n?]curses to get the console width (look info source) (so on add a fixed
 
222
// field flags)
 
223
size_t formatter::
 
224
output_field(ostream & out, field_datum const & datum,
 
225
             format_flags fl, size_t padding, bool hide_immutable)
 
226
{
 
227
        if (!hide_immutable) {
 
228
                out << string(padding, ' ');
 
229
 
 
230
                field_description const & field(format_map[fl]);
 
231
                string str = (this->*field.formatter)(datum);
 
232
                out << str;
 
233
 
 
234
                // at least one separator char
 
235
                padding = 1;
 
236
                if (str.length() < field.width)
 
237
                        padding = field.width - str.length();
 
238
        } else {
 
239
                field_description const & field(format_map[fl]);
 
240
                padding += field.width;
 
241
        }
 
242
 
 
243
        return padding;
 
244
}
 
245
 
 
246
 
 
247
size_t formatter::
 
248
output_header_field(ostream & out, format_flags fl, size_t padding)
 
249
{
 
250
        out << string(padding, ' ');
 
251
 
 
252
        field_description const & field(format_map[fl]);
 
253
        out << field.header_name;
 
254
 
 
255
        // at least one separator char
 
256
        padding = 1;
 
257
        if (field.header_name.length() < field.width)
 
258
                padding = field.width - field.header_name.length();
 
259
 
 
260
        return padding;
 
261
}
 
262
 
 
263
 
 
264
string formatter::format_vma(field_datum const & f)
 
265
{
 
266
        return get_vma(f.sample.vma, vma_64);
 
267
}
 
268
 
 
269
 
 
270
string formatter::format_symb_name(field_datum const & f)
 
271
{
 
272
        return symbol_names.demangle(f.symbol.name);
 
273
}
 
274
 
 
275
 
 
276
string formatter::format_image_name(field_datum const & f)
 
277
{
 
278
        return get_image_name(f.symbol.image_name, 
 
279
                long_filenames 
 
280
                        ? image_name_storage::int_real_filename
 
281
                        : image_name_storage::int_real_basename,
 
282
                extra_found_images);
 
283
}
 
284
 
 
285
 
 
286
string formatter::format_app_name(field_datum const & f)
 
287
{
 
288
        return get_image_name(f.symbol.app_name,
 
289
                long_filenames 
 
290
                        ? image_name_storage::int_real_filename
 
291
                        : image_name_storage::int_real_basename,
 
292
                extra_found_images);
 
293
}
 
294
 
 
295
 
 
296
string formatter::format_linenr_info(field_datum const & f)
 
297
{
 
298
        return get_linenr_info(f.sample.file_loc, long_filenames);
 
299
}
 
300
 
 
301
 
 
302
string formatter::format_nr_samples(field_datum const & f)
 
303
{
 
304
        ostringstream out;
 
305
        out << f.sample.counts[f.pclass];
 
306
        return out.str();
 
307
}
 
308
 
 
309
 
 
310
string formatter::format_nr_cumulated_samples(field_datum const & f)
 
311
{
 
312
        if (f.diff == -INFINITY)
 
313
                return "---";
 
314
        ostringstream out;
 
315
        f.counts.cumulated_samples[f.pclass] += f.sample.counts[f.pclass];
 
316
        out << f.counts.cumulated_samples[f.pclass];
 
317
        return out.str();
 
318
}
 
319
 
 
320
 
 
321
string formatter::format_percent(field_datum const & f)
 
322
{
 
323
        if (f.diff == -INFINITY)
 
324
                return "---";
 
325
        return get_percent(f.sample.counts[f.pclass], f.counts.total[f.pclass]);
 
326
}
 
327
 
 
328
 
 
329
string formatter::format_cumulated_percent(field_datum const & f)
 
330
{
 
331
        if (f.diff == -INFINITY)
 
332
                return "---";
 
333
        f.counts.cumulated_percent[f.pclass] += f.sample.counts[f.pclass];
 
334
 
 
335
        return get_percent(f.counts.cumulated_percent[f.pclass],
 
336
                           f.counts.total[f.pclass]);
 
337
}
 
338
 
 
339
 
 
340
string formatter::format_percent_details(field_datum const & f)
 
341
{
 
342
        return get_percent(f.sample.counts[f.pclass],
 
343
                f.counts.total[f.pclass]);
 
344
}
 
345
 
 
346
 
 
347
string formatter::format_cumulated_percent_details(field_datum const & f)
 
348
{
 
349
        f.counts.cumulated_percent_details[f.pclass] += f.sample.counts[f.pclass];
 
350
 
 
351
        return get_percent(f.counts.cumulated_percent_details[f.pclass],
 
352
                           f.counts.total[f.pclass]);
 
353
}
 
354
 
 
355
 
 
356
string formatter::format_diff(field_datum const & f)
 
357
{
 
358
        if (f.diff == INFINITY)
 
359
                return "+++";
 
360
        else if (f.diff == -INFINITY)
 
361
                return "---";
 
362
 
 
363
        return ::format_percent(f.diff, percent_int_width,
 
364
                                percent_fract_width, true);
 
365
}
 
366
 
 
367
 
 
368
void formatter::
 
369
do_output(ostream & out, symbol_entry const & symb, sample_entry const & sample,
 
370
          counts_t & c, diff_array_t const & diffs, bool hide_immutable)
 
371
{
 
372
        size_t padding = 0;
 
373
 
 
374
        // first output the vma field
 
375
        field_datum datum(symb, sample, 0, c, extra_found_images);
 
376
        if (flags & ff_vma)
 
377
                padding = output_field(out, datum, ff_vma, padding, false);
 
378
 
 
379
        // repeated fields for each profile class
 
380
        for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) {
 
381
                field_datum datum(symb, sample, pclass, c,
 
382
                                  extra_found_images, diffs[pclass]);
 
383
 
 
384
                if (flags & ff_nr_samples)
 
385
                        padding = output_field(out, datum,
 
386
                               ff_nr_samples, padding, false);
 
387
 
 
388
                if (flags & ff_nr_samples_cumulated)
 
389
                        padding = output_field(out, datum, 
 
390
                               ff_nr_samples_cumulated, padding, false);
 
391
 
 
392
                if (flags & ff_percent)
 
393
                        padding = output_field(out, datum,
 
394
                               ff_percent, padding, false);
 
395
 
 
396
                if (flags & ff_percent_cumulated)
 
397
                        padding = output_field(out, datum,
 
398
                               ff_percent_cumulated, padding, false);
 
399
 
 
400
                if (flags & ff_diff)
 
401
                        padding = output_field(out, datum,
 
402
                                ff_diff, padding, false);
 
403
 
 
404
                if (flags & ff_percent_details)
 
405
                        padding = output_field(out, datum,
 
406
                               ff_percent_details, padding, false);
 
407
 
 
408
                if (flags & ff_percent_cumulated_details)
 
409
                        padding = output_field(out, datum,
 
410
                               ff_percent_cumulated_details, padding, false);
 
411
        }
 
412
 
 
413
        // now the remaining field
 
414
        if (flags & ff_linenr_info)
 
415
                padding = output_field(out, datum, ff_linenr_info,
 
416
                       padding, false);
 
417
 
 
418
        if (flags & ff_image_name)
 
419
                padding = output_field(out, datum, ff_image_name,
 
420
                       padding, hide_immutable);
 
421
 
 
422
        if (flags & ff_app_name)
 
423
                padding = output_field(out, datum, ff_app_name,
 
424
                       padding, hide_immutable);
 
425
 
 
426
        if (flags & ff_symb_name)
 
427
                padding = output_field(out, datum, ff_symb_name,
 
428
                       padding, hide_immutable);
 
429
 
 
430
        out << "\n";
 
431
}
 
432
 
 
433
 
 
434
opreport_formatter::opreport_formatter(profile_container const & p)
 
435
        :
 
436
        formatter(p.extra_found_images),
 
437
        profile(p),
 
438
        need_details(false)
 
439
{
 
440
        counts.total = profile.samples_count();
 
441
}
 
442
 
 
443
 
 
444
void opreport_formatter::show_details(bool on_off)
 
445
{
 
446
        need_details = on_off;
 
447
}
 
448
 
 
449
 
 
450
void opreport_formatter::output(ostream & out, symbol_entry const * symb)
 
451
{
 
452
        do_output(out, *symb, symb->sample, counts);
 
453
 
 
454
        if (need_details)
 
455
                output_details(out, symb);
 
456
}
 
457
 
 
458
 
 
459
void opreport_formatter::
 
460
output(ostream & out, symbol_collection const & syms)
 
461
{
 
462
        output_header(out);
 
463
 
 
464
        symbol_collection::const_iterator it = syms.begin();
 
465
        symbol_collection::const_iterator end = syms.end();
 
466
        for (; it != end; ++it)
 
467
                output(out, *it);
 
468
}
 
469
 
 
470
 
 
471
void opreport_formatter::
 
472
output_details(ostream & out, symbol_entry const * symb)
 
473
{
 
474
        counts_t c = counts;
 
475
 
 
476
        if (!global_percent)
 
477
                c.total = symb->sample.counts;
 
478
 
 
479
        // cumulated percent are relative to current symbol.
 
480
        c.cumulated_samples = count_array_t();
 
481
        c.cumulated_percent = count_array_t();
 
482
 
 
483
        sample_container::samples_iterator it = profile.begin(symb);
 
484
        sample_container::samples_iterator end = profile.end(symb);
 
485
        for (; it != end; ++it) {
 
486
                out << "  ";
 
487
                do_output(out, *symb, it->second, c, diff_array_t(), true);
 
488
        }
 
489
}
 
490
 
 
491
 
 
492
cg_formatter::cg_formatter(callgraph_container const & profile)
 
493
        :
 
494
        formatter(profile.extra_found_images)
 
495
{
 
496
        counts.total = profile.samples_count();
 
497
}
 
498
 
 
499
 
 
500
void cg_formatter::output(ostream & out, symbol_collection const & syms)
 
501
{
 
502
        // amount of spacing prefixing child and parent lines
 
503
        string const child_parent_prefix("  ");
 
504
 
 
505
        output_header(out);
 
506
 
 
507
        out << string(79, '-') << endl;
 
508
 
 
509
        symbol_collection::const_iterator it;
 
510
        symbol_collection::const_iterator end = syms.end();
 
511
 
 
512
        for (it = syms.begin(); it < end; ++it) {
 
513
                cg_symbol const * sym = dynamic_cast<cg_symbol const *>(*it);
 
514
 
 
515
                cg_symbol::children::const_iterator cit;
 
516
                cg_symbol::children::const_iterator cend = sym->callers.end();
 
517
 
 
518
                counts_t c;
 
519
                if (global_percent)
 
520
                        c.total = counts.total;
 
521
                else
 
522
                        c.total = sym->total_caller_count;
 
523
 
 
524
                for (cit = sym->callers.begin(); cit != cend; ++cit) {
 
525
                        out << child_parent_prefix;
 
526
                        do_output(out, *cit, cit->sample, c);
 
527
                }
 
528
 
 
529
                do_output(out, *sym, sym->sample, counts);
 
530
 
 
531
                c = counts_t();
 
532
                if (global_percent)
 
533
                        c.total = counts.total;
 
534
                else
 
535
                        c.total = sym->total_callee_count;
 
536
 
 
537
                cend = sym->callees.end();
 
538
 
 
539
                for (cit = sym->callees.begin(); cit != cend; ++cit) {
 
540
                        out << child_parent_prefix;
 
541
                        do_output(out, *cit, cit->sample, c);
 
542
                }
 
543
 
 
544
                out << string(79, '-') << endl;
 
545
        }
 
546
}
 
547
 
 
548
 
 
549
diff_formatter::diff_formatter(diff_container const & profile,
 
550
                               extra_images const & extra)
 
551
        :
 
552
        formatter(extra)
 
553
{
 
554
        counts.total = profile.samples_count();
 
555
}
 
556
 
 
557
 
 
558
void diff_formatter::output(ostream & out, diff_collection const & syms)
 
559
{
 
560
        output_header(out);
 
561
 
 
562
        diff_collection::const_iterator it = syms.begin();
 
563
        diff_collection::const_iterator end = syms.end();
 
564
        for (; it != end; ++it)
 
565
                do_output(out, *it, it->sample, counts, it->diffs);
 
566
}
 
567
 
 
568
// local variables used in generation of XML
 
569
// buffer details for output later
 
570
ostringstream bytes_out;
 
571
 
 
572
// module+symbol table for detecting duplicate symbols
 
573
map<string, size_t> symbol_data_table;
 
574
size_t symbol_data_index = 0;
 
575
 
 
576
/* Return any existing index or add to the table */
 
577
size_t xml_get_symbol_index(string const & name)
 
578
{
 
579
        size_t index = symbol_data_index;
 
580
        map<string, size_t>::iterator it = symbol_data_table.find(name);
 
581
 
 
582
        if (it == symbol_data_table.end()) {
 
583
                symbol_data_table[name] = symbol_data_index++;
 
584
                return index;
 
585
        }
 
586
 
 
587
        return it->second;
 
588
}
 
589
 
 
590
 
 
591
class symbol_details_t {
 
592
public:
 
593
        symbol_details_t() { size = index = 0; id = -1; }
 
594
        int id;
 
595
        size_t size;
 
596
        size_t index;
 
597
        string details;
 
598
};
 
599
 
 
600
typedef growable_vector<symbol_details_t> symbol_details_array_t;
 
601
symbol_details_array_t symbol_details;
 
602
size_t detail_table_index = 0;
 
603
 
 
604
xml_formatter::
 
605
xml_formatter(profile_container const * p,
 
606
              symbol_collection & s, extra_images const & extra,
 
607
              string_filter const & sf)
 
608
        :
 
609
        formatter(extra),
 
610
        profile(p),
 
611
        symbols(s),
 
612
        need_details(false),
 
613
        symbol_filter(sf)
 
614
{
 
615
        if (profile)
 
616
                counts.total = profile->samples_count();
 
617
}
 
618
 
 
619
 
 
620
void xml_formatter::
 
621
show_details(bool on_off)
 
622
{
 
623
        need_details = on_off;
 
624
}
 
625
 
 
626
 
 
627
void xml_formatter::output(ostream & out)
 
628
{
 
629
        xml_support->build_subclasses(out);
 
630
 
 
631
        xml_support->output_program_structure(out);
 
632
        output_symbol_data(out);
 
633
        if (need_details) {
 
634
                out << open_element(DETAIL_TABLE);
 
635
                for (size_t i = 0; i < symbol_details.size(); ++i) {
 
636
                        int id = symbol_details[i].id;
 
637
 
 
638
                        if (id >= 0) {
 
639
                                out << open_element(SYMBOL_DETAILS, true);
 
640
                                out << init_attr(TABLE_ID, (size_t)id);
 
641
                                out << close_element(NONE, true);
 
642
                                out << symbol_details[i].details;
 
643
                                out << close_element(SYMBOL_DETAILS);
 
644
                        }
 
645
                }
 
646
                out << close_element(DETAIL_TABLE);
 
647
 
 
648
                // output bytesTable
 
649
                out << open_element(BYTES_TABLE);
 
650
                out << bytes_out.str();
 
651
                out << close_element(BYTES_TABLE);
 
652
        }
 
653
 
 
654
        out << close_element(PROFILE);
 
655
}
 
656
 
 
657
bool
 
658
xml_formatter::get_bfd_object(symbol_entry const * symb, op_bfd * & abfd) const
 
659
{
 
660
        bool ok = true;
 
661
 
 
662
        string const & image_name = get_image_name(symb->image_name,
 
663
                image_name_storage::int_filename, extra_found_images);
 
664
        if (symb->spu_offset) {
 
665
                // FIXME: what about archive:tmp, actually it's not supported
 
666
                // for spu since oparchive doesn't archive the real file but
 
667
                // in future it would work ?
 
668
                string tmp = get_image_name(symb->embedding_filename, 
 
669
                        image_name_storage::int_filename, extra_found_images);
 
670
                if (abfd && abfd->get_filename() == tmp)
 
671
                        return true;
 
672
                delete abfd;
 
673
                abfd = new op_bfd(symb->spu_offset, tmp,
 
674
                                  symbol_filter, extra_found_images, ok);
 
675
        } else {
 
676
                if (abfd && abfd->get_filename() == image_name)
 
677
                        return true;
 
678
                delete abfd;
 
679
                abfd = new op_bfd(image_name, symbol_filter,
 
680
                                  extra_found_images, ok);
 
681
 
 
682
        }
 
683
 
 
684
        if (!ok) {
 
685
                report_image_error(image_name, image_format_failure,
 
686
                                   false, extra_found_images);
 
687
                delete abfd;
 
688
                abfd = 0;
 
689
                return false;
 
690
        }
 
691
 
 
692
        return true;
 
693
}
 
694
 
 
695
void xml_formatter::
 
696
output_the_symbol_data(ostream & out, symbol_entry const * symb, op_bfd * & abfd)
 
697
{
 
698
        string const name = symbol_names.name(symb->name);
 
699
        assert(name.size() > 0);
 
700
 
 
701
        string const image = get_image_name(symb->image_name,
 
702
                image_name_storage::int_filename, extra_found_images);
 
703
        string const qname = image + ":" + name;
 
704
        map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
 
705
 
 
706
        if (sd_it != symbol_data_table.end()) {
 
707
                // first time we've seen this symbol
 
708
                out << open_element(SYMBOL_DATA, true);
 
709
                out << init_attr(TABLE_ID, sd_it->second);
 
710
 
 
711
                field_datum datum(*symb, symb->sample, 0, counts,
 
712
                                  extra_found_images);
 
713
 
 
714
                output_attribute(out, datum, ff_symb_name, NAME);
 
715
 
 
716
                if (flags & ff_linenr_info) {
 
717
                        output_attribute(out, datum, ff_linenr_info, SOURCE_FILE);
 
718
                        output_attribute(out, datum, ff_linenr_info, SOURCE_LINE);
 
719
                }
 
720
 
 
721
                if (name.size() > 0 && name[0] != '?') {
 
722
                        output_attribute(out, datum, ff_vma, STARTING_ADDR);
 
723
 
 
724
                        if (need_details) {
 
725
                                get_bfd_object(symb, abfd);
 
726
                                if (abfd && abfd->symbol_has_contents(symb->sym_index))
 
727
                                        xml_support->output_symbol_bytes(bytes_out, symb, sd_it->second, *abfd);
 
728
                        }
 
729
                }
 
730
                out << close_element();
 
731
 
 
732
                // seen so remove (otherwise get several "no symbols")
 
733
                symbol_data_table.erase(qname);
 
734
        }
 
735
}
 
736
 
 
737
void xml_formatter::output_cg_children(ostream & out, 
 
738
        cg_symbol::children const cg_symb, op_bfd * & abfd)
 
739
{
 
740
        cg_symbol::children::const_iterator cit;
 
741
        cg_symbol::children::const_iterator cend = cg_symb.end();
 
742
 
 
743
        for (cit = cg_symb.begin(); cit != cend; ++cit) {
 
744
                string const name = symbol_names.name(cit->name);
 
745
                string const image = get_image_name(cit->image_name,
 
746
                        image_name_storage::int_filename, extra_found_images);
 
747
                string const qname = image + ":" + name;
 
748
                map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
 
749
 
 
750
                if (sd_it != symbol_data_table.end()) {
 
751
                        symbol_entry const * child = &(*cit);
 
752
                        output_the_symbol_data(out, child, abfd);
 
753
                }
 
754
        }
 
755
}
 
756
 
 
757
void xml_formatter::output_symbol_data(ostream & out)
 
758
{
 
759
        op_bfd * abfd = NULL;
 
760
        sym_iterator it = symbols.begin();
 
761
        sym_iterator end = symbols.end();
 
762
 
 
763
        out << open_element(SYMBOL_TABLE);
 
764
        for ( ; it != end; ++it) {
 
765
                symbol_entry const * symb = *it;
 
766
                cg_symbol const * cg_symb = dynamic_cast<cg_symbol const *>(symb);
 
767
                output_the_symbol_data(out, symb, abfd);
 
768
                if (cg_symb) {
 
769
                        /* make sure callers/callees are included in SYMBOL_TABLE */
 
770
                        output_cg_children(out, cg_symb->callers, abfd);
 
771
                        output_cg_children(out, cg_symb->callees, abfd);
 
772
                }
 
773
        }
 
774
        out << close_element(SYMBOL_TABLE);
 
775
 
 
776
        delete abfd;
 
777
}
 
778
 
 
779
string  xml_formatter::
 
780
output_symbol_details(symbol_entry const * symb,
 
781
    size_t & detail_index, size_t const lo, size_t const hi)
 
782
{
 
783
        if (!has_sample_counts(symb->sample.counts, lo, hi))
 
784
                return "";
 
785
 
 
786
        sample_container::samples_iterator it = profile->begin(symb);
 
787
        sample_container::samples_iterator end = profile->end(symb);
 
788
 
 
789
        ostringstream str;
 
790
        for (; it != end; ++it) {
 
791
                counts_t c;
 
792
 
 
793
                for (size_t p = lo; p <= hi; ++p)  {
 
794
                        size_t count = it->second.counts[p];
 
795
 
 
796
                        if (count == 0) continue;
 
797
 
 
798
                        str << open_element(DETAIL_DATA, true);
 
799
                        str << init_attr(TABLE_ID, detail_index++);
 
800
 
 
801
                        // first output the vma field
 
802
                        field_datum datum(*symb, it->second, 0, c, 
 
803
                                          extra_found_images, 0.0);
 
804
                        output_attribute(str, datum, ff_vma, VMA);
 
805
                        if (ff_linenr_info) {
 
806
                                string sym_file;
 
807
                                size_t sym_line;
 
808
                                string samp_file;
 
809
                                size_t samp_line;
 
810
                                string sym_info = get_linenr_info(symb->sample.file_loc, true);
 
811
                                string samp_info = get_linenr_info(it->second.file_loc, true);
 
812
 
 
813
                                if (extract_linenr_info(samp_info, samp_file, samp_line)) {
 
814
                                        if (extract_linenr_info(sym_info, sym_file, sym_line)) {
 
815
                                                // only output source_file if it is different than the symbol's 
 
816
                                                // source file.  this can happen with inlined functions in
 
817
                                                // #included header files
 
818
                                                if (sym_file != samp_file)
 
819
                                                        str << init_attr(SOURCE_FILE, samp_file);
 
820
                                        }
 
821
                                        str << init_attr(SOURCE_LINE, samp_line);
 
822
                                }
 
823
                        }
 
824
                        str << close_element(NONE, true);
 
825
 
 
826
                        // output buffered sample data
 
827
                        output_sample_data(str, it->second, p);
 
828
 
 
829
                        str << close_element(DETAIL_DATA);
 
830
                }
 
831
        }
 
832
        return str.str();
 
833
}
 
834
 
 
835
void xml_formatter::
 
836
output_symbol(ostream & out,
 
837
        symbol_entry const * symb, size_t lo, size_t hi, bool is_module)
 
838
{
 
839
        ostringstream str;
 
840
        // pointless reference to is_module, remove insane compiler warning
 
841
        size_t indx = is_module ? 0 : 1;
 
842
 
 
843
        // output symbol's summary data for each profile class
 
844
        bool got_samples = false;
 
845
 
 
846
        for (size_t p = lo; p <= hi; ++p) {
 
847
                got_samples |= xml_support->output_summary_data(str,
 
848
                    symb->sample.counts, p);
 
849
        }
 
850
 
 
851
        if (!got_samples)
 
852
                return;
 
853
 
 
854
        if (cverb << vxml)
 
855
                out << "<!-- symbol_ref=" << symbol_names.name(symb->name) <<
 
856
                        " -->" << endl;
 
857
 
 
858
        out << open_element(SYMBOL, true);
 
859
 
 
860
        string const name = symbol_names.name(symb->name);
 
861
        assert(name.size() > 0);
 
862
        
 
863
        string const image = get_image_name(symb->image_name,
 
864
                image_name_storage::int_filename, extra_found_images);
 
865
        string const qname = image + ":" + name;
 
866
 
 
867
        indx = xml_get_symbol_index(qname);
 
868
 
 
869
        out << init_attr(ID_REF, indx);
 
870
 
 
871
        if (need_details) {
 
872
                ostringstream details;
 
873
                symbol_details_t & sd = symbol_details[indx];
 
874
                size_t const detail_lo = sd.index;
 
875
 
 
876
                string detail_str = output_symbol_details(symb, sd.index, lo, hi);
 
877
 
 
878
                if (detail_str.size() > 0) {
 
879
                        if (sd.id < 0)
 
880
                                sd.id = indx;
 
881
                        details << detail_str;
 
882
                }
 
883
 
 
884
                if (sd.index > detail_lo) {
 
885
                        sd.details = sd.details + details.str();
 
886
                        out << init_attr(DETAIL_LO, detail_lo);
 
887
                        out << init_attr(DETAIL_HI, sd.index-1);
 
888
                }
 
889
        }
 
890
        out << close_element(NONE, true);
 
891
        // output summary
 
892
        out << str.str();
 
893
        out << close_element(SYMBOL);
 
894
}
 
895
 
 
896
 
 
897
void xml_formatter::
 
898
output_sample_data(ostream & out, sample_entry const & sample, size_t pclass)
 
899
{
 
900
        out << open_element(COUNT, true);
 
901
        out << init_attr(CLASS, classes.v[pclass].name);
 
902
        out << close_element(NONE, true);
 
903
        out << sample.counts[pclass];
 
904
        out << close_element(COUNT);
 
905
}
 
906
 
 
907
 
 
908
void xml_formatter::
 
909
output_attribute(ostream & out, field_datum const & datum,
 
910
                 format_flags fl, tag_t tag)
 
911
{
 
912
        field_description const & field(format_map[fl]);
 
913
 
 
914
        string str = (this->*field.formatter)(datum);
 
915
 
 
916
        if (!str.empty()) {
 
917
                if (fl == ff_linenr_info && (tag == SOURCE_LINE || tag == SOURCE_FILE)) {
 
918
                        string file;
 
919
                        size_t line;
 
920
 
 
921
                        if (extract_linenr_info(str, file, line)) {
 
922
                                if (tag == SOURCE_LINE)
 
923
                                        out << init_attr(tag, line);
 
924
                                else
 
925
                                        out << init_attr(tag, file);
 
926
                        }
 
927
                } else
 
928
                        out << " " << init_attr(tag, str);
 
929
        }
 
930
}
 
931
 
 
932
xml_cg_formatter::
 
933
xml_cg_formatter(callgraph_container const & cg, symbol_collection & s,
 
934
                 string_filter const & sf)
 
935
        :
 
936
        xml_formatter(0, s, cg.extra_found_images, sf),
 
937
        callgraph(cg)
 
938
{
 
939
        counts.total = callgraph.samples_count();
 
940
}
 
941
 
 
942
void xml_cg_formatter::
 
943
output_symbol_core(ostream & out, cg_symbol::children const cg_symb,
 
944
       string const selfname, string const qname,
 
945
       size_t lo, size_t hi, bool is_module, tag_t tag)
 
946
{
 
947
        cg_symbol::children::const_iterator cit;
 
948
        cg_symbol::children::const_iterator cend = cg_symb.end();
 
949
 
 
950
        for (cit = cg_symb.begin(); cit != cend; ++cit) {
 
951
                string const & module = get_image_name((cit)->image_name,
 
952
                        image_name_storage::int_filename, extra_found_images);
 
953
                bool self = false;
 
954
                ostringstream str;
 
955
                size_t indx;
 
956
 
 
957
                // output symbol's summary data for each profile class
 
958
                for (size_t p = lo; p <= hi; ++p)
 
959
                        xml_support->output_summary_data(str, cit->sample.counts, p);
 
960
 
 
961
                if (cverb << vxml)
 
962
                        out << "<!-- symbol_ref=" << symbol_names.name(cit->name) <<
 
963
                                " -->" << endl;
 
964
 
 
965
                if (is_module) {
 
966
                        out << open_element(MODULE, true);
 
967
                        out << init_attr(NAME, module) << close_element(NONE, true);
 
968
                }
 
969
 
 
970
                out << open_element(SYMBOL, true);
 
971
 
 
972
                string const symname = symbol_names.name(cit->name);
 
973
                assert(symname.size() > 0);
 
974
 
 
975
                string const symqname = module + ":" + symname;
 
976
 
 
977
                // Find any self references and handle
 
978
                if ((symname == selfname) && (tag == CALLEES)) {
 
979
                        self = true;
 
980
                        indx = xml_get_symbol_index(qname);
 
981
                } else {
 
982
                        indx = xml_get_symbol_index(symqname);
 
983
                }
 
984
 
 
985
                out << init_attr(ID_REF, indx);
 
986
 
 
987
                if (self)
 
988
                        out << init_attr(SELFREF, "true");
 
989
 
 
990
                out << close_element(NONE, true);
 
991
                out << str.str();
 
992
                out << close_element(SYMBOL);
 
993
 
 
994
                if (is_module)
 
995
                        out << close_element(MODULE);
 
996
        }
 
997
}
 
998
 
 
999
 
 
1000
void xml_cg_formatter::
 
1001
output_symbol(ostream & out,
 
1002
        symbol_entry const * symb, size_t lo, size_t hi, bool is_module)
 
1003
{
 
1004
        cg_symbol const * cg_symb = dynamic_cast<cg_symbol const *>(symb);
 
1005
        ostringstream str;
 
1006
        size_t indx;
 
1007
 
 
1008
        // output symbol's summary data for each profile class
 
1009
        for (size_t p = lo; p <= hi; ++p)
 
1010
                xml_support->output_summary_data(str, symb->sample.counts, p);
 
1011
 
 
1012
        if (cverb << vxml)
 
1013
                out << "<!-- symbol_ref=" << symbol_names.name(symb->name) <<
 
1014
                        " -->" << endl;
 
1015
 
 
1016
        out << open_element(SYMBOL, true);
 
1017
 
 
1018
        string const name = symbol_names.name(symb->name);
 
1019
        assert(name.size() > 0);
 
1020
 
 
1021
        string const image = get_image_name(symb->image_name,
 
1022
                image_name_storage::int_filename, extra_found_images);
 
1023
        string const qname = image + ":" + name;
 
1024
 
 
1025
        string const selfname = symbol_names.demangle(symb->name) + " [self]";
 
1026
 
 
1027
        indx = xml_get_symbol_index(qname);
 
1028
 
 
1029
        out << init_attr(ID_REF, indx);
 
1030
 
 
1031
        out << close_element(NONE, true);
 
1032
 
 
1033
        out << open_element(CALLERS);
 
1034
        if (cg_symb)
 
1035
                output_symbol_core(out, cg_symb->callers, selfname, qname, lo, hi, is_module, CALLERS);
 
1036
        out << close_element(CALLERS);
 
1037
 
 
1038
        out << open_element(CALLEES);
 
1039
        if (cg_symb)
 
1040
                output_symbol_core(out, cg_symb->callees, selfname, qname, lo, hi, is_module, CALLEES);
 
1041
 
 
1042
        out << close_element(CALLEES);
 
1043
 
 
1044
        // output summary
 
1045
        out << str.str();
 
1046
        out << close_element(SYMBOL);
 
1047
}
 
1048
 
 
1049
} // namespace format_output