summaryrefslogtreecommitdiffstats
path: root/meta/packages/oprofile/oprofile/xml_callgraph.patch
blob: f089e7dc4a0eb7fb5dbc4cb52d736ad9f8a9728d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
 ChangeLog                |   10 ++
 libpp/format_output.cpp  |  178 +++++++++++++++++++++++++++++++++++++++++------
 libpp/format_output.h    |   40 ++++++++--
 libpp/xml_utils.cpp      |   17 +---
 libutil++/xml_output.cpp |    3
 libutil++/xml_output.h   |    3
 pp/opreport.cpp          |   37 +++++++--
 pp/opreport_options.cpp  |    5 -
 8 files changed, 238 insertions(+), 55 deletions(-)


Index: oprofile/libpp/format_output.cpp
===================================================================
--- oprofile.orig/libpp/format_output.cpp
+++ oprofile/libpp/format_output.cpp
@@ -562,6 +562,20 @@ ostringstream bytes_out;
 map<string, size_t> symbol_data_table;
 size_t symbol_data_index = 0;
 
+/* Return any existing index or add to the table */
+size_t xml_get_symbol_index(string const name)
+{
+	size_t index = symbol_data_index;
+	map<string, size_t>::iterator it = symbol_data_table.find(name);
+
+	if (it == symbol_data_table.end()) {
+		symbol_data_table[name] = symbol_data_index++;
+		return index;
+	}
+
+	return it->second;
+}
+
 
 class symbol_details_t {
 public:
@@ -577,14 +591,15 @@ symbol_details_array_t symbol_details;
 size_t detail_table_index = 0;
 
 xml_formatter::
-xml_formatter(profile_container const & p,
+xml_formatter(profile_container const *p,
 		symbol_collection & s)
 	:
 	profile(p),
 	symbols(s),
 	need_details(false)
 {
-	counts.total = profile.samples_count();
+	if (profile)
+		counts.total = profile->samples_count();
 }
 
 
@@ -640,12 +655,11 @@ void xml_formatter::output_symbol_data(o
 		string const image = get_image_name(symb->image_name, true);
 		string const qname = image + ":" + name;
 		map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
-		size_t si = xml_support->get_symbol_index(it);
 
-		if (sd_it->second == si) {
+		if (sd_it != symbol_data_table.end()) {
 			// first time we've seen this symbol
 			out << open_element(SYMBOL_DATA, true);
-			out << init_attr(TABLE_ID, si);
+			out << init_attr(TABLE_ID, sd_it->second);
 
 			field_datum datum(*symb, symb->sample, 0, counts);
 
@@ -660,9 +674,12 @@ void xml_formatter::output_symbol_data(o
 				output_attribute(out, datum, ff_vma, STARTING_ADDR);
 
 				if (need_details)
-					xml_support->output_symbol_bytes(bytes_out, symb, si);
+					xml_support->output_symbol_bytes(bytes_out, symb, sd_it->second);
 			}
 			out << close_element();
+
+			// seen so remove (otherwise get several "no symbols")
+			symbol_data_table.erase(qname);
 		}
 	}
 	out << close_element(SYMBOL_TABLE);
@@ -675,8 +692,8 @@ output_symbol_details(symbol_entry const
 	if (!has_sample_counts(symb->sample.counts, lo, hi))
 		return "";
 
-	sample_container::samples_iterator it = profile.begin(symb);
-	sample_container::samples_iterator end = profile.end(symb);
+	sample_container::samples_iterator it = profile->begin(symb);
+	sample_container::samples_iterator end = profile->end(symb);
 
 	ostringstream str;
 	for (; it != end; ++it) {
@@ -725,10 +742,11 @@ output_symbol_details(symbol_entry const
 
 void xml_formatter::
 output_symbol(ostream & out,
-	symbol_collection::const_iterator const it, size_t lo, size_t hi)
+	symbol_entry const * symb, size_t lo, size_t hi, bool is_module)
 {
-	symbol_entry const * symb = *it;
 	ostringstream str;
+	// pointless reference to is_module, remove insane compiler warning
+	size_t indx = is_module ? 0 : 1;
 
 	// output symbol's summary data for each profile class
 	bool got_samples = false;
@@ -752,27 +770,21 @@ output_symbol(ostream & out,
 	
 	string const image = get_image_name(symb->image_name, true);
 	string const qname = image + ":" + name;
-	map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
-	size_t si = xml_support->get_symbol_index(it);
 
-	// if this is the first time we've seen this symbol, save it's index
-	if (sd_it == symbol_data_table.end())
-		symbol_data_table[qname] = si;
-	else
-		si = sd_it->second;
+	indx = xml_get_symbol_index(qname);
 
-	out << init_attr(ID_REF, si);
+	out << init_attr(ID_REF, indx);
 
 	if (need_details) {
 		ostringstream details;
-		symbol_details_t & sd = symbol_details[si];
+		symbol_details_t & sd = symbol_details[indx];
 		size_t const detail_lo = sd.index;
 
 		string detail_str = output_symbol_details(symb, sd.index, lo, hi);
 
 		if (detail_str.size() > 0) {
 			if (sd.id < 0)
-				sd.id = si;
+				sd.id = indx;
 			details << detail_str;
 		}
 
@@ -828,5 +840,131 @@ output_attribute(ostream & out, field_da
 	}
 }
 
+xml_cg_formatter::
+xml_cg_formatter(callgraph_container const * cg, symbol_collection & s)
+	:
+	xml_formatter(NULL, s),
+	callgraph(cg)
+{
+	counts.total = callgraph->samples_count();
+}
+
+void xml_cg_formatter::output(ostream & out)
+{
+	xml_support->build_subclasses(out);
+
+	xml_support->output_program_structure(out);
+	output_symbol_data(out);
+
+	out << close_element(PROFILE);
+}
+
+void xml_cg_formatter::
+output_symbol_core(ostream & out, cg_symbol::children const cg_symb,
+	string const selfname, string const qname,
+	size_t lo, size_t hi, bool is_module, tag_t tag)
+{
+
+	cg_symbol::children::const_iterator cit;
+	cg_symbol::children::const_iterator cend = cg_symb.end();
+
+	for (cit = cg_symb.begin(); cit != cend; ++cit) {
+		string binary = get_image_name((cit)->app_name, true);
+		string module = get_image_name((cit)->image_name, true);
+		bool got_samples = false, self = false;
+		ostringstream str;
+		size_t indx;
+
+		for (size_t p = lo; p <= hi; ++p)
+			got_samples |= xml_support->output_summary_data(str, cit->sample.counts, p);
+
+		if (!got_samples)
+			continue;
+
+		cverb << vxml << " <!-- symbol_ref=" << symbol_names.name(cit->name) << " -->" << endl;
+
+		if (is_module) {
+			out << open_element(MODULE, true);
+			out << init_attr(NAME, module) << close_element(NONE, true);
+		}
+
+		out << open_element(SYMBOL, true);
+
+		string const symname = symbol_names.name(cit->name);
+		assert(symname.size() > 0);
+
+		string const symqname = module + ":" + symname;
+
+		// Find any self references and handle
+	        if ((symname == selfname) && (tag == CALLEES)) {
+			self = true;
+			indx = xml_get_symbol_index(qname);
+		} else
+			indx = xml_get_symbol_index(symqname);
+
+		out << init_attr(ID_REF, indx);
+
+		if (self)
+			out << init_attr(SELFREF, "true");
+
+		out << close_element(NONE, true);
+		out << str.str();
+		out << close_element(SYMBOL);
+
+		if (is_module)
+			out << close_element(MODULE);
+	}
+}
+
+
+void xml_cg_formatter::
+output_symbol(ostream & out,
+	symbol_entry const * symb, size_t lo, size_t hi, bool is_module)
+{
+	cg_symbol const * cg_symb = dynamic_cast<const cg_symbol *>(symb);
+	ostringstream str;
+
+	// output symbol's summary data for each profile class
+	bool got_samples = false;
+
+	for (size_t p = lo; p <= hi; ++p) {
+		got_samples |= xml_support->output_summary_data(str,
+		    symb->sample.counts, p);
+	}
+
+	if (!got_samples)
+		return;
+
+	cverb << vxml << " <!-- symbol_ref=" << symbol_names.name(symb->name) << " -->" << endl;
+
+	out << open_element(SYMBOL, true);
+
+	string const name = symbol_names.name(symb->name);
+	assert(name.size() > 0);
+
+	string const image = get_image_name(symb->image_name, true);
+	string const qname = image + ":" + name;
+
+	string const selfname = symbol_names.demangle(symb->name) + " [self]";
+
+	out << init_attr(ID_REF, xml_get_symbol_index(qname));
+
+	out << close_element(NONE, true);
+
+	out << open_element(CALLERS);
+	if (cg_symb)
+		output_symbol_core(out, cg_symb->callers, selfname, qname, lo, hi, is_module, CALLERS);
+	out << close_element(CALLERS);
+
+	out << open_element(CALLEES);
+	if (cg_symb)
+		output_symbol_core(out, cg_symb->callees, selfname, qname, lo, hi, is_module, CALLEES);
+
+	out << close_element(CALLEES);
+
+	// output summary
+	out << str.str();
+	out << close_element(SYMBOL);
+}
 
 } // namespace format_output
Index: oprofile/libpp/format_output.h
===================================================================
--- oprofile.orig/libpp/format_output.h
+++ oprofile/libpp/format_output.h
@@ -227,7 +227,7 @@ private:
 class xml_formatter : public formatter {
 public:
 	/// build a ready to use formatter
-	xml_formatter(profile_container const & profile,
+	xml_formatter(profile_container const * profile,
 		symbol_collection & symbols);
 
 	// output body of XML output
@@ -235,9 +235,9 @@ public:
 
 	/** output one symbol symb to out according to the output format
 	 * specifier previously set by call(s) to add_format() */
-	void output_symbol(std::ostream & out,
-		symbol_collection::const_iterator const it,
-		size_t lo, size_t hi);
+	virtual void output_symbol(std::ostream & out,
+		symbol_entry const * symb, size_t lo, size_t hi,
+		bool is_module);
 
 	/// output details for the symbol
 	std::string output_symbol_details(symbol_entry const * symb,
@@ -246,9 +246,12 @@ public:
 	/// set the output_details boolean
 	void show_details(bool);
 
+	// output SymbolData XML elements
+	void output_symbol_data(std::ostream & out);
+
 private:
 	/// container we work from
-	profile_container const & profile;
+	profile_container const * profile;
  
 	// ordered collection of symbols associated with this profile
 	symbol_collection & symbols;
@@ -256,9 +259,6 @@ private:
 	/// true if we need to show details for each symbols
 	bool need_details;
 
-	// output SymbolData XML elements
-	void output_symbol_data(std::ostream & out);
-
 	// count of DetailData items output so far
 	size_t detail_count;
 
@@ -270,6 +270,30 @@ private:
 			      format_flags fl, tag_t tag);
 };
 
+// callgraph XML output version
+class xml_cg_formatter : public xml_formatter {
+public:
+	/// build a ready to use formatter
+	xml_cg_formatter(callgraph_container const * callgraph,
+		symbol_collection & symbols);
+
+	// output body of XML output
+	void output(std::ostream & out);
+
+	/** output one symbol symb to out according to the output format
+	 * specifier previously set by call(s) to add_format() */
+	virtual void output_symbol(std::ostream & out,
+		symbol_entry const * symb, size_t lo, size_t hi, bool is_module);
+
+private:
+	/// container we work from
+	callgraph_container const * callgraph;
+
+	void output_symbol_core(std::ostream & out,
+		cg_symbol::children const cg_symb,
+		std::string const selfname, std::string const qname,
+		size_t lo, size_t hi, bool is_module, tag_t tag);
+};
 
 } // namespace format_output 
 
Index: oprofile/libpp/xml_utils.cpp
===================================================================
--- oprofile.orig/libpp/xml_utils.cpp
+++ oprofile/libpp/xml_utils.cpp
@@ -268,13 +268,6 @@ void xml_utils::output_xml_header(string
 	cout << close_element(SETUP) << endl;
 }
 
-size_t xml_utils::get_symbol_index(sym_iterator const it)
-{
-	return it - symbols_begin;
-}
-
-
-
 class subclass_info_t {
 public:
 	string unitmask;
@@ -443,7 +436,7 @@ public:
 	bool is_closed(string const & n);
 protected:
 	void output_summary(ostream & out);
-	void output_symbols(ostream & out);
+	void output_symbols(ostream & out, bool is_module);
 
 	string name;
 	sym_iterator begin;
@@ -593,7 +586,7 @@ void module_info::output(ostream & out)
 	out << open_element(MODULE, true);
 	out << init_attr(NAME, name) << close_element(NONE, true);
 	output_summary(out);
-	output_symbols(out);
+	output_symbols(out, true);
 	out << close_element(MODULE);
 }
 
@@ -605,13 +598,13 @@ void module_info::output_summary(ostream
 }
 
 
-void module_info::output_symbols(ostream & out)
+void module_info::output_symbols(ostream & out, bool is_module)
 {
 	if (begin == (sym_iterator)0)
 		return;
 
 	for (sym_iterator it = begin; it != end; ++it)
-		xml_out->output_symbol(out, it, lo, hi);
+		xml_out->output_symbol(out, *it, lo, hi, is_module);
 }
 
 
@@ -791,7 +784,7 @@ void binary_info::output(ostream & out)
 	out << init_attr(NAME, name) << close_element(NONE, true);
 
 	output_summary(out);
-	output_symbols(out);
+	output_symbols(out, false);
 	for (size_t a = 0; a < nr_modules; ++a)
 		my_modules[a].output(out);
 
Index: oprofile/libutil++/xml_output.cpp
===================================================================
--- oprofile.orig/libutil++/xml_output.cpp
+++ oprofile/libutil++/xml_output.cpp
@@ -47,8 +47,11 @@ string const xml_tag_map[] = {
 	"binary",
 	"module",
 		"name",
+	"callers",
+	"callees",
 	"symbol",
 		"idref",
+		"self",
 		"detaillo",
 		"detailhi",
 	"symboltable",
Index: oprofile/libutil++/xml_output.h
===================================================================
--- oprofile.orig/libutil++/xml_output.h
+++ oprofile/libutil++/xml_output.h
@@ -28,7 +28,8 @@ typedef enum {
 	THREAD, THREAD_ID,
 	BINARY,
 	MODULE, NAME,
-	SYMBOL, ID_REF, DETAIL_LO, DETAIL_HI,
+	CALLERS, CALLEES,
+	SYMBOL, ID_REF, SELFREF, DETAIL_LO, DETAIL_HI,
 	SYMBOL_TABLE,
 	SYMBOL_DATA, STARTING_ADDR,
 		SOURCE_FILE, SOURCE_LINE, CODE_LENGTH,
Index: oprofile/pp/opreport.cpp
===================================================================
--- oprofile.orig/pp/opreport.cpp
+++ oprofile/pp/opreport.cpp
@@ -378,7 +378,7 @@ void output_symbols(profile_container co
 	format_output::opreport_formatter * text_out = 0;
 
 	if (options::xml) {
-		xml_out = new format_output::xml_formatter(pc, symbols);
+		xml_out = new format_output::xml_formatter(&pc, symbols);
 		xml_out->show_details(options::details);
 		out = xml_out;
 		// for XML always output long filenames
@@ -450,21 +450,40 @@ void output_cg_symbols(callgraph_contain
 	options::sort_by.sort(symbols, options::reverse_sort,
 	                      options::long_filenames);
 
-	format_output::cg_formatter out(cg);
+	format_output::formatter * out;
+	format_output::xml_cg_formatter * xml_out = 0;
+	format_output::cg_formatter * text_out = 0;
 
-	out.set_nr_classes(nr_classes);
-	out.show_long_filenames(options::long_filenames);
-	out.show_header(options::show_header);
-	out.vma_format_64bit(output_hints & cf_64bit_vma);
-	out.show_global_percent(options::global_percent);
+	if (options::xml) {
+		xml_out = new format_output::xml_cg_formatter(&cg, symbols);
+		out = xml_out;
+		// for XML always output long filenames
+		out->show_long_filenames(true);
+	} else {
+		text_out = new format_output::cg_formatter(cg);
+		out = text_out;
+		out->show_long_filenames(options::long_filenames);
+	}
+
+	out->set_nr_classes(nr_classes);
+	out->show_header(options::show_header);
+	out->vma_format_64bit(output_hints & cf_64bit_vma);
+	out->show_global_percent(options::global_percent);
 
 	format_flags flags = get_format_flags(output_hints);
 	if (multiple_apps)
 		flags = format_flags(flags | ff_app_name);
 
-	out.add_format(flags);
+	out->add_format(flags);
+
+	if (options::xml) {
+		xml_support = new xml_utils(xml_out, symbols, nr_classes,
+			&options::symbol_filter, options::archive_path);
+		xml_out->output(cout);
+	} else {
+		text_out->output(cout, symbols);
+	}
 
-	out.output(cout, symbols);
 }
 
 
Index: oprofile/pp/opreport_options.cpp
===================================================================
--- oprofile.orig/pp/opreport_options.cpp
+++ oprofile/pp/opreport_options.cpp
@@ -177,11 +177,6 @@ void check_options(bool diff)
 	}
 
 	if (xml) {
-		if (callgraph) {
-			cerr << "--callgraph is incompatible with --xml" << endl;
-			do_exit = true;
-		}
-
 		if (accumulated) {
 			cerr << "--accumulated is incompatible with --xml" << endl;
 			do_exit = true;
Index: oprofile/ChangeLog
===================================================================
--- oprofile.orig/ChangeLog
+++ oprofile/ChangeLog
@@ -1,5 +1,15 @@
 2007-05-09  Richard Purdie  <rpurdie@openedhand.com>
 
+ 	* libpp/format_output.cpp:
+	* libpp/format_output.h:
+	* libpp/xml_utils.cpp:
+	* libutil++/xml_output.cpp:
+	* libutil++/xml_output.h:
+	* pp/opreport.cpp:
+	* pp/opreport_options.cpp: Add callgraph XML output
+
+2007-05-09  Richard Purdie  <rpurdie@openedhand.com>
+
 	* libpp/callgraph_container.cpp:
 	* libpp/callgraph_container.h:
 	* libpp/format_output.cpp: