• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file xml_utils.cpp
3  * utility routines for generating XML
4  *
5  * @remark Copyright 2006 OProfile authors
6  * @remark Read the file COPYING
7  *
8  * @author Dave Nomura
9  */
10 
11 #include <iostream>
12 #include <sstream>
13 
14 #include "xml_utils.h"
15 #include "format_output.h"
16 #include "arrange_profiles.h"
17 #include "op_bfd.h"
18 #include "cverb.h"
19 
20 using namespace std;
21 
22 bool want_xml = false;
23 
24 size_t nr_classes = 0;
25 size_t nr_cpus = 0;
26 size_t nr_events = 0;
27 sym_iterator symbols_begin;
28 sym_iterator symbols_end;
29 // handle on xml_formatter object
30 format_output::xml_formatter * xml_out;
31 xml_utils * xml_support;
32 size_t xml_utils::events_index = 0;
33 bool xml_utils::has_nonzero_masks = false;
34 ostringstream xml_options;
35 
36 
37 
38 namespace {
39 
has_separated_cpu_info()40 bool has_separated_cpu_info()
41 {
42 	return classes.v[0].ptemplate.cpu != "all";
43 }
44 
45 
get_event_num(size_t pclass)46 string get_event_num(size_t pclass)
47 {
48 	return classes.v[pclass].ptemplate.event;
49 }
50 
51 
get_next_event_num_pclass(size_t start)52 size_t get_next_event_num_pclass(size_t start)
53 {
54 	string cur_event = get_event_num(start);
55 	size_t i;
56 	for (i = start;
57 		i < nr_classes && get_event_num(i) == cur_event;
58 		++i) ;
59 	return i;
60 }
61 
62 
dump_symbol(string const & prefix,sym_iterator it,bool want_nl=true)63 void dump_symbol(string const & prefix, sym_iterator it, bool want_nl = true)
64 {
65 	if (it == symbols_end)
66 		cverb << vxml << prefix << "END";
67 	else
68 		cverb << vxml << prefix << symbol_names.name((*it)->name);
69 	if (want_nl)
70 		cverb << vxml << endl;
71 }
72 
73 
dump_symbols(string const & prefix,sym_iterator b,sym_iterator e)74 void dump_symbols(string const & prefix, sym_iterator b, sym_iterator e)
75 {
76 	if (b == (sym_iterator)0)
77 		return;
78 
79 	for (sym_iterator it = b; it != e; ++it)
80 		dump_symbol(prefix, it, true);
81 }
82 
83 
84 
dump_classes()85 void dump_classes()
86 {
87 	cverb << vxml << "<!-- classes dump" << endl;
88 	cverb << vxml << classes.event;
89 	cverb << vxml << "classes.size= " << classes.v.size() << endl;
90 	for (size_t i = 0; i < classes.v.size(); ++i) {
91 		cverb << vxml << "--- class " << i << ":" << classes.v[i].name << " ---" << endl;
92 		cverb << vxml << classes.v[i].ptemplate;
93 	}
94 	cverb << vxml << "-->" << endl;
95 }
96 
97 
has_separated_thread_info()98 bool has_separated_thread_info()
99 {
100 	return classes.v[0].ptemplate.tid != "all";
101 }
102 
103 
get_cpu_num(size_t pclass)104 string get_cpu_num(size_t pclass)
105 {
106 	return classes.v[pclass].ptemplate.cpu;
107 }
108 
109 
110 };  // anonymous namespace
111 
xml_utils(format_output::xml_formatter * xo,symbol_collection const & s,size_t nc,extra_images const & extra)112 xml_utils::xml_utils(format_output::xml_formatter * xo,
113 		     symbol_collection const & s, size_t nc,
114 		     extra_images const & extra)
115 	:
116 	has_subclasses(false),
117 	bytes_index(0),
118 	extra_found_images(extra)
119 {
120 	xml_out = xo;
121 	nr_classes = nc;
122 	symbols_begin = s.begin();
123 	symbols_end = s.end();
124 	multiple_events = get_next_event_num_pclass(0) != nr_classes;
125 
126 	if (has_separated_cpu_info()) {
127 		size_t cpus = 0;
128 		// count number of cpus
129 		for (size_t p = 0; p < nr_classes; ++p)  {
130 			size_t cpu = atoi(classes.v[p].ptemplate.cpu.c_str());
131 			if (cpu > cpus) cpus = cpu;
132 		}
133 		// cpus names start with 0
134 		nr_cpus = cpus + 1;
135 	}
136 }
137 
138 
get_timer_setup(size_t count)139 string xml_utils::get_timer_setup(size_t count)
140 {
141 	return open_element(TIMER_SETUP, true) +
142 		init_attr(RTC_INTERRUPTS, count) + close_element();
143 }
144 
145 
get_event_setup(string event,size_t count,string unit_mask)146 string xml_utils::get_event_setup(string event, size_t count,
147                                       string unit_mask)
148 {
149 	ostringstream str;
150 
151 	str << open_element(EVENT_SETUP, true);
152 	str << init_attr(TABLE_ID, events_index++);
153 	str << init_attr(EVENT_NAME, event);
154 	if (unit_mask.size() != 0) str << init_attr(UNIT_MASK, unit_mask);
155 	str << init_attr(SETUP_COUNT, (size_t)count) + close_element();
156 	return str.str();
157 }
158 
159 
get_profile_header(string cpu_name,double const speed)160 string xml_utils::get_profile_header(string cpu_name, double const speed)
161 {
162 	ostringstream str;
163 	string cpu_type;
164 	string processor;
165 	string::size_type slash_pos = cpu_name.find("/");
166 
167 	if (slash_pos == string::npos) {
168 		cpu_type = cpu_name;
169 		processor = "";
170 	} else {
171 		cpu_type = cpu_name.substr(0, slash_pos);
172 		processor = cpu_name.substr(slash_pos+1);
173 	}
174 
175 	str << init_attr(CPU_NAME, cpu_type) << endl;
176 	if (processor.size() > 0)
177 		str << init_attr(PROCESSOR, string(processor)) << endl;
178 	if (nr_cpus > 1) str << init_attr(SEPARATED_CPUS, nr_cpus) << endl;
179 	str << init_attr(MHZ, speed) << endl;
180 
181 	return str.str();
182 }
183 
184 
set_nr_cpus(size_t cpus)185 void xml_utils::set_nr_cpus(size_t cpus)
186 {
187 	nr_cpus = cpus;
188 }
189 
set_nr_events(size_t events)190 void xml_utils::set_nr_events(size_t events)
191 {
192 	nr_events = events;
193 }
194 
set_has_nonzero_masks()195 void xml_utils::set_has_nonzero_masks()
196 {
197 	has_nonzero_masks = true;
198 }
199 
200 
add_option(tag_t tag,string const & value)201 void xml_utils::add_option(tag_t tag, string const & value)
202 {
203 	xml_options << init_attr(tag, value);
204 }
205 
206 
add_option(tag_t tag,list<string> const & value)207 void xml_utils::add_option(tag_t tag, list<string> const & value)
208 {
209 	list<string>::const_iterator begin = value.begin();
210 	list<string>::const_iterator end = value.end();
211 	list<string>::const_iterator cit = begin;
212 	ostringstream str;
213 
214 	for (; cit != end; ++cit) {
215 		if (cit != begin)
216 			str << ",";
217 		str << *cit;
218 	}
219 	xml_options << init_attr(tag, str.str());
220 }
221 
222 
add_option(tag_t tag,vector<string> const & value)223 void xml_utils::add_option(tag_t tag, vector<string> const & value)
224 {
225 	vector<string>::const_iterator begin = value.begin();
226 	vector<string>::const_iterator end = value.end();
227 	vector<string>::const_iterator cit = begin;
228 	ostringstream str;
229 
230 	for (; cit != end; ++cit) {
231 		if (cit != begin)
232 			str << ",";
233 		str << *cit;
234 	}
235 	xml_options << init_attr(tag, str.str());
236 }
237 
238 
add_option(tag_t tag,bool value)239 void xml_utils::add_option(tag_t tag, bool value)
240 {
241 	xml_options << init_attr(tag, (value ? "true" : "false"));
242 }
243 
244 
output_xml_header(string const & command_options,string const & cpu_info,string const & events)245 void xml_utils::output_xml_header(string const & command_options,
246                        string const & cpu_info, string const & events)
247 {
248 	// the integer portion indicates the schema version and should change
249 	// both here and in the schema file when major changes are made to
250 	// the schema.  changes to opreport, or minor changes to the schema
251 	// can be indicated by changes to the fraction part.
252 	string const schema_version = "3.0";
253 
254 	// This is the XML version, not schema version.
255 	string const xml_header = "<?xml version=\"1.0\" ?>";
256 
257 	cout << xml_header << endl;
258 	cout << open_element(PROFILE, true);
259 	cout << init_attr(SCHEMA_VERSION, schema_version);
260 
261 	cout << cpu_info;
262 	cout << init_attr(TITLE, "opreport " + command_options);
263 	cout << close_element(NONE, true);
264 
265 	cout << open_element(OPTIONS, true) << xml_options.str();
266 	cout << close_element();
267 
268 	cout << open_element(SETUP) << events;
269 	cout << close_element(SETUP) << endl;
270 }
271 
272 class subclass_info_t {
273 public:
274 	string unitmask;
275 	string subclass_name;
276 };
277 
278 typedef growable_vector<subclass_info_t> subclass_array_t;
279 typedef growable_vector<subclass_array_t> event_subclass_t;
280 typedef growable_vector<event_subclass_t> cpu_subclass_t;
281 
build_subclasses(ostream & out)282 void xml_utils::build_subclasses(ostream & out)
283 {
284 	size_t subclasses = 0;
285 	string subclass_name;
286 	// when --separate=cpu we will have an event_subclass array for each cpu
287 	cpu_subclass_t cpu_subclasses;
288 
289 	event_subclass_t event_subclasses;
290 
291 	if (nr_cpus <= 1 && nr_events <= 1 && !has_nonzero_masks)
292 		return;
293 
294 	out << open_element(CLASSES);
295 	for (size_t i = 0; i < classes.v.size(); ++i) {
296 		profile_class & pclass = classes.v[i];
297 		size_t event = atoi(pclass.ptemplate.event.c_str());
298 
299 		subclass_array_t * sc_ptr;
300 
301 		// select the right subclass array
302 		if (nr_cpus == 1) {
303 			sc_ptr = &event_subclasses[event];
304 		} else {
305 			size_t cpu = atoi(pclass.ptemplate.cpu.c_str());
306 			sc_ptr = &cpu_subclasses[cpu][event];
307 		}
308 
309 		// search for an existing unitmask
310 		subclass_name = "";
311 		for (size_t j = 0; j < sc_ptr->size(); ++j) {
312 			if ((*sc_ptr)[j].unitmask == pclass.ptemplate.unitmask) {
313 				subclass_name = (*sc_ptr)[j].subclass_name;
314 				break;
315 			}
316 		}
317 
318 		if (subclass_name.size() == 0) {
319 			ostringstream str;
320 			size_t new_index = sc_ptr->size();
321 
322 			// no match found, create a new entry
323 			str << "c" << subclasses++;
324 			subclass_name = str.str();
325 			(*sc_ptr)[new_index].unitmask = pclass.ptemplate.unitmask;
326 			(*sc_ptr)[new_index].subclass_name = subclass_name;
327 			out << open_element(CLASS, true);
328 			out << init_attr(NAME, subclass_name);
329 			if (nr_cpus > 1)
330 				out << init_attr(CPU_NUM, pclass.ptemplate.cpu);
331 			if (nr_events > 1)
332 				out << init_attr(EVENT_NUM, event);
333 			if (has_nonzero_masks)
334 				out << init_attr(EVENT_MASK, pclass.ptemplate.unitmask);
335 			out << close_element();
336 		}
337 
338 		pclass.name = subclass_name;
339 	}
340 	out << close_element(CLASSES);
341 	has_subclasses = true;
342 }
343 
344 
345 string
get_counts_string(count_array_t const & counts,size_t begin,size_t end)346 get_counts_string(count_array_t const & counts, size_t begin, size_t end)
347 {
348 	ostringstream str;
349 	bool got_count = false;
350 
351 	// if no cpu separation then return a simple count, omit zero counts
352 	if (nr_cpus == 1) {
353 		size_t count = counts[begin];
354 		if (count == 0)
355 			return "";
356 		str << count;
357 		return str.str();
358 	}
359 
360 	for (size_t p = begin; p != end; ++p) {
361 		size_t count = counts[p];
362 		if (p != begin) str << ",";
363 		if (count != 0) {
364 			got_count = true;
365 			str << count;
366 		}
367 	}
368 	return got_count ? str.str() : "";
369 }
370 
371 
372 void
output_symbol_bytes(ostream & out,symbol_entry const * symb,size_t sym_id,op_bfd const & abfd)373 xml_utils::output_symbol_bytes(ostream & out, symbol_entry const * symb,
374 			       size_t sym_id, op_bfd const & abfd)
375 {
376 	size_t size = symb->size;
377 	scoped_array<unsigned char> contents(new unsigned char[size]);
378 	if (abfd.get_symbol_contents(symb->sym_index, contents.get())) {
379 		string const name = symbol_names.name(symb->name);
380 		out << open_element(BYTES, true) << init_attr(TABLE_ID, sym_id);
381 		out << close_element(NONE, true);
382 		for (size_t i = 0; i < size; ++i) {
383 			char hex_map[] = "0123456789ABCDEF";
384 			char hex[2];
385 			hex[0] = hex_map[(contents[i] >> 4) & 0xf];
386 			hex[1] = hex_map[contents[i] & 0xf];
387 			out << hex[0] << hex[1];
388 		}
389 		out << close_element(BYTES);
390 	}
391 }
392 
393 
394 bool
output_summary_data(ostream & out,count_array_t const & summary,size_t pclass)395 xml_utils::output_summary_data(ostream & out, count_array_t const & summary, size_t pclass)
396 {
397 	size_t const count = summary[pclass];
398 
399 	if (count == 0)
400 		return false;
401 
402 	out << open_element(COUNT, has_subclasses);
403 	if (has_subclasses) {
404 		out << init_attr(CLASS, classes.v[pclass].name);
405 		out << close_element(NONE, true);
406 	}
407 	out << count;
408 	out << close_element(COUNT);
409 	return true;
410 }
411 
412 class module_info {
413 public:
module_info()414 	module_info()
415 		{ lo = hi = 0; name = ""; begin = end = (sym_iterator)0;}
416 	void dump();
417 	void build_module(string const & n, sym_iterator it,
418 	                  size_t l, size_t h);
get_name()419 	string get_name() { return name; }
set_lo(size_t l)420 	void set_lo(size_t l) { lo = l; }
set_hi(size_t h)421 	void set_hi(size_t h) { hi = h; }
get_summary()422 	count_array_t const & get_summary() { return summary; }
423 	void set_begin(sym_iterator b);
424 	void set_end(sym_iterator e);
425 	void add_to_summary(count_array_t const & counts);
426 	void output(ostream & out);
427 	bool is_closed(string const & n);
428 protected:
429 	void output_summary(ostream & out);
430 	void output_symbols(ostream & out, bool is_module);
431 
432 	string name;
433 	sym_iterator begin;
434 	sym_iterator end;
435 
436 	// summary sample data
437 	count_array_t summary;
438 
439 	// range of profile classes approprate for this module
440 	size_t lo;
441 	size_t hi;
442 };
443 
444 class thread_info : public module_info {
445 public:
thread_info()446 	thread_info() { nr_modules = 0; }
447 
448 	void build_thread(string const & tid, size_t l, size_t h);
449 	bool add_modules(string const & module, sym_iterator it);
450 	void add_module_symbol(string const & n, sym_iterator it);
451 	void summarize();
452 	void set_end(sym_iterator end);
get_tid()453 	string const get_tid() { return thread_id; }
454 	void output(ostream & out);
455 	void dump();
456 private:
457 	// indices into the classes array applicable to this process
458 	size_t nr_modules;
459 	string thread_id;
460 	growable_vector<module_info> my_modules;
461 };
462 
463 class process_info : public module_info {
464 public:
process_info()465 	process_info() { nr_threads = 0; }
466 	void build_process(string const & pid, size_t l, size_t h);
467 	void add_thread(string const & tid, size_t l, size_t h);
468 	void add_modules(string const & module,
469 		string const & app_name, sym_iterator it);
470 	void summarize();
471 	void set_end(sym_iterator end);
472 	void output(ostream & out);
473 	void dump();
474 private:
475 	size_t nr_threads;
476 	string process_id;
477 	growable_vector<thread_info> my_threads;
478 
479 };
480 class process_root_info {
481 public:
process_root_info()482 	process_root_info() { nr_processes = 0; }
483 	process_info * add_process(string const & pid, size_t lo, size_t hi);
484 	void add_modules(string const & module, string const & app_name,
485 		sym_iterator it);
486 	void summarize();
487 	void summarize_processes(extra_images const & extra_found_images);
488 	void set_process_end();
489 	void output_process_symbols(ostream & out);
490 	void dump_processes();
491 private:
492 	size_t nr_processes;
493 
494 	growable_vector<process_info> processes;
495 };
496 
497 class binary_info : public module_info {
498 public:
binary_info()499 	binary_info() { nr_modules = 0; }
500 	void output(ostream & out);
501 	binary_info * build_binary(string const & n);
502 	void add_module_symbol(string const & module, string const & app,
503 		sym_iterator it);
504 	void close_binary(sym_iterator it);
505 	void dump();
506 private:
507 	size_t nr_modules;
508 
509 	growable_vector<module_info> my_modules;
510 };
511 
512 
513 class binary_root_info {
514 public:
binary_root_info()515 	binary_root_info() { nr_binaries = 0; }
516 	binary_info * add_binary(string const & n, sym_iterator it);
517 	void summarize_binaries(extra_images const & extra_found_images);
518 	void output_binary_symbols(ostream & out);
519 	void dump_binaries();
520 private:
521 	size_t nr_binaries;
522 
523 	growable_vector<binary_info> binaries;
524 };
525 
526 static process_root_info processes_root;
527 static binary_root_info binaries_root;
528 
529 
530 void module_info::
build_module(string const & n,sym_iterator it,size_t l,size_t h)531 build_module(string const & n, sym_iterator it, size_t l, size_t h)
532 {
533 	name = n;
534 	begin = it;
535 	lo = l;
536 	hi = h;
537 }
538 
539 
add_to_summary(count_array_t const & counts)540 void module_info::add_to_summary(count_array_t const & counts)
541 {
542 	for (size_t pclass = lo ; pclass <= hi; ++pclass)
543 		summary[pclass] += counts[pclass];
544 }
545 
546 
set_begin(sym_iterator b)547 void module_info::set_begin(sym_iterator b)
548 {
549 	if (begin == (sym_iterator)0)
550 		begin = b;
551 }
552 
553 
set_end(sym_iterator e)554 void module_info::set_end(sym_iterator e)
555 {
556 	if (end == (sym_iterator)0)
557 		end = e;
558 }
559 
560 
is_closed(string const & n)561 bool module_info::is_closed(string const & n)
562 {
563 	return (name == n) && end != (sym_iterator)0;
564 }
565 
566 
dump()567 void module_info::dump()
568 {
569 	cverb << vxml << "	module:class(" << lo << "," << hi << ")=";
570 	cverb << vxml << name << endl;
571 	dump_symbols("		", begin, end);
572 }
573 
574 
output(ostream & out)575 void module_info::output(ostream & out)
576 {
577 	out << open_element(MODULE, true);
578 	out << init_attr(NAME, name) << close_element(NONE, true);
579 	output_summary(out);
580 	output_symbols(out, true);
581 	out << close_element(MODULE);
582 }
583 
584 
output_summary(ostream & out)585 void module_info::output_summary(ostream & out)
586 {
587 	for (size_t p = lo; p <= hi; ++p)
588 		(void)xml_support->output_summary_data(out, summary, p);
589 }
590 
591 
output_symbols(ostream & out,bool is_module)592 void module_info::output_symbols(ostream & out, bool is_module)
593 {
594 	if (begin == (sym_iterator)0)
595 		return;
596 
597 	for (sym_iterator it = begin; it != end; ++it)
598 		xml_out->output_symbol(out, *it, lo, hi, is_module);
599 }
600 
601 
close_binary(sym_iterator it)602 void binary_info::close_binary(sym_iterator it)
603 {
604 	set_end(it);
605 	if (nr_modules > 0) {
606 		module_info & m = my_modules[nr_modules-1];
607 		m.set_end(it);
608 	}
609 }
610 
611 
dump()612 void binary_info::dump()
613 {
614 	cverb << vxml << "app_name=" << name << endl;
615 	if (begin != (sym_iterator)0)
616 		dump_symbols("	", begin, end);
617 
618 	for (size_t i = 0; i < nr_modules; ++i)
619 		my_modules[i].dump();
620 }
621 
622 
623 void binary_info::
add_module_symbol(string const & module,string const & app,sym_iterator it)624 add_module_symbol(string const & module, string const & app,
625 	sym_iterator it)
626 {
627 	size_t m = nr_modules;
628 
629 	if (module == app) {
630 		// set begin symbol for binary if not set
631 		set_begin(it);
632 
633 		if (m > 0) {
634 			// close out current module
635 			module_info & mod = my_modules[m-1];
636 			mod.set_end(it);
637 		}
638 
639 		// add symbol count to binary count
640 		add_to_summary((*it)->sample.counts);
641 		return;
642 	}
643 
644 	string current_module_name = (m == 0 ? "" : my_modules[m-1].get_name());
645 	if (module != current_module_name) {
646 		// we have a module distinct from it's binary: --separate=lib
647 		// and this is the first symbol for this module
648 		if (m != 0) {
649 			// close out current module
650 			module_info & mod = my_modules[m-1];
651 			mod.set_end(it);
652 			add_to_summary(mod.get_summary());
653 		}
654 
655 		// mark end of enclosing binary symbols if there have been any
656 		// NOTE: it is possible for the binary's symbols to follow its
657 		// module symbols
658 		if (begin != (sym_iterator)0 && end == (sym_iterator)0)
659 			set_end(it);
660 
661 		// build the new module
662 		nr_modules++;
663 		my_modules[m].build_module(module, it, 0, nr_classes-1);
664 	}
665 
666 	// propagate this symbols counts to the module
667 	my_modules[nr_modules-1].add_to_summary((*it)->sample.counts);
668 }
669 
670 
671 void binary_root_info::
summarize_binaries(extra_images const & extra_found_images)672 summarize_binaries(extra_images const & extra_found_images)
673 {
674 	binary_info * current_binary = 0;
675 	string current_binary_name = "";
676 
677 	for (sym_iterator it = symbols_begin ; it != symbols_end; ++it) {
678 		string binary = get_image_name((*it)->app_name,
679 			image_name_storage::int_filename, extra_found_images);
680 		string module = get_image_name((*it)->image_name,
681 			image_name_storage::int_filename, extra_found_images);
682 
683 		if (binary != current_binary_name) {
684 			current_binary = binaries_root.add_binary(binary, it);
685 			current_binary_name = binary;
686 		}
687 
688 		current_binary->add_module_symbol(module, binary, it);
689 	}
690 
691 	// close out last binary and module
692 	current_binary->close_binary(symbols_end);
693 }
694 
695 
696 process_info *
add_process(string const & pid,size_t lo,size_t hi)697 process_root_info::add_process(string const & pid, size_t lo, size_t hi)
698 {
699 	processes[nr_processes].build_process(pid, lo, hi);
700 	return &processes[nr_processes++];
701 }
702 
703 
704 void process_root_info::
add_modules(string const & module,string const & app_name,sym_iterator it)705 add_modules(string const & module, string const & app_name,
706 	sym_iterator it)
707 {
708 	for (size_t p = 0; p < nr_processes; ++p)
709 		processes[p].add_modules(module, app_name, it);
710 }
711 
712 
713 
summarize()714 void process_root_info::summarize()
715 {
716 	for (size_t p = 0; p < nr_processes; ++p)
717 		processes[p].summarize();
718 }
719 
720 
721 void process_root_info::
summarize_processes(extra_images const & extra_found_images)722 summarize_processes(extra_images const & extra_found_images)
723 {
724 	// add modules to the appropriate threads in the process hierarchy
725 	for (sym_iterator it = symbols_begin ; it != symbols_end; ++it) {
726 		string binary = get_image_name((*it)->app_name,
727 			image_name_storage::int_filename, extra_found_images);
728 		string module = get_image_name((*it)->image_name,
729 			image_name_storage::int_filename, extra_found_images);
730 
731 		processes_root.add_modules(module, binary, it);
732 	}
733 
734 	// set end symbol boundary for all modules in all threads
735 	processes_root.set_process_end();
736 
737 	// propagate summaries to process/thread
738 	processes_root.summarize();
739 }
740 
741 
set_process_end()742 void process_root_info::set_process_end()
743 {
744 	for (size_t p = 0; p < nr_processes; ++p)
745 		processes[p].set_end(symbols_end);
746 }
747 
output_process_symbols(ostream & out)748 void process_root_info::output_process_symbols(ostream & out)
749 {
750 	for (size_t p = 0; p < nr_processes; ++p)
751 		processes[p].output(out);
752 }
753 
754 
dump_processes()755 void process_root_info::dump_processes()
756 {
757 	cverb << vxml << "<!-- processes_dump:" << endl;
758 	for (size_t p = 0; p < nr_processes; ++p)
759 		processes[p].dump();
760 	cverb << vxml << "end processes_dump -->" << endl;
761 }
762 
763 binary_info *
build_binary(string const & n)764 binary_info::build_binary(string const & n)
765 {
766 	name = n;
767 	lo = 0;
768 	hi = nr_classes-1;
769 	return this;
770 }
771 
772 
output(ostream & out)773 void binary_info::output(ostream & out)
774 {
775 	out << open_element(BINARY, true);
776 	out << init_attr(NAME, name) << close_element(NONE, true);
777 
778 	output_summary(out);
779 	output_symbols(out, false);
780 	for (size_t a = 0; a < nr_modules; ++a)
781 		my_modules[a].output(out);
782 
783 	out << close_element(BINARY);
784 }
785 
786 
787 binary_info *
add_binary(string const & n,sym_iterator it)788 binary_root_info::add_binary(string const & n, sym_iterator it)
789 {
790 	size_t a = nr_binaries++;
791 
792 	// close out previous binary and module
793 	if (a > 0) binaries[a-1].close_binary(it);
794 	return binaries[a].build_binary(n);
795 }
796 
797 
output_binary_symbols(ostream & out)798 void binary_root_info::output_binary_symbols(ostream & out)
799 {
800 	for (size_t a = 0; a < nr_binaries; ++a)
801 		binaries[a].output(out);
802 }
803 
804 
dump_binaries()805 void binary_root_info::dump_binaries()
806 {
807 	cverb << vxml << "<!-- binaries_dump:" << endl;
808 	for (size_t p = 0; p < nr_binaries; ++p)
809 		binaries[p].dump();
810 	cverb << vxml << "end processes_dump -->" << endl;
811 }
812 
813 
build_process(string const & pid,size_t l,size_t h)814 void process_info::build_process(string const & pid, size_t l, size_t h)
815 {
816 	process_id = pid;
817 	lo = l;
818 	hi = h;
819 }
820 
821 
add_thread(string const & tid,size_t l,size_t h)822 void process_info::add_thread(string const & tid, size_t l, size_t h)
823 {
824 	my_threads[nr_threads++].build_thread(tid, l, h);
825 }
826 
827 
add_modules(string const & module,string const & app_name,sym_iterator it)828 void process_info::add_modules(string const & module,
829 	string const & app_name, sym_iterator it)
830 {
831 	bool added = false;
832 	for (size_t t = 0; t < nr_threads; ++t)
833 		added |= my_threads[t].add_modules(module, it);
834 	if (added && name.size() == 0) name = app_name;
835 }
836 
837 
summarize()838 void process_info::summarize()
839 {
840 	for (size_t t = 0; t < nr_threads; ++t) {
841 		thread_info & thr = my_threads[t];
842 		thr.summarize();
843 		add_to_summary(thr.get_summary());
844 	}
845 }
846 
847 
build_thread(string const & tid,size_t l,size_t h)848 void thread_info::build_thread(string const & tid, size_t l, size_t h)
849 {
850 	thread_id = tid;
851 	lo = l;
852 	hi = h;
853 }
854 
855 
summarize()856 void thread_info::summarize()
857 {
858 	for (size_t m = 0; m < nr_modules; ++m)
859 		add_to_summary(my_modules[m].get_summary());
860 }
861 
862 
set_end(sym_iterator end)863 void thread_info::set_end(sym_iterator end)
864 {
865 	for (size_t m = 0; m < nr_modules; ++m)
866 		my_modules[m].set_end(end);
867 }
868 
869 
add_module_symbol(string const & n,sym_iterator it)870 void thread_info::add_module_symbol(string const & n, sym_iterator it)
871 {
872 	module_info & m = my_modules[nr_modules++];
873 	m.build_module(n, it, lo, hi);
874 	m.add_to_summary((*it)->sample.counts);
875 }
876 
output(ostream & out)877 void thread_info::output(ostream & out)
878 {
879 	ostringstream thread_summary;
880 	ostringstream modules_output;
881 
882 	output_summary(thread_summary);
883 
884 	for (size_t m = 0; m < nr_modules; ++m)
885 		my_modules[m].output(modules_output);
886 
887 	// ignore threads with no sample data
888 	if (modules_output.str().size() == 0 && thread_summary.str().size() == 0)
889 		return;
890 
891 	out << open_element(THREAD, true);
892 	out << init_attr(THREAD_ID, thread_id) << close_element(NONE, true);
893 	out << thread_summary.str();
894 	out << modules_output.str();
895 	out << close_element(THREAD);
896 }
897 
898 
add_modules(string const & module,sym_iterator it)899 bool thread_info::add_modules(string const & module, sym_iterator it)
900 {
901 	string old_name =
902 		(nr_modules == 0 ? "" : my_modules[nr_modules-1].get_name());
903 	if (nr_modules > 0 && old_name != module) {
904 		module_info & m = my_modules[nr_modules-1];
905 		// close out previous module if it hasn't already been closed out
906 		if (!m.is_closed(old_name))
907 			m.set_end(it);
908 	}
909 
910 	// add a new module for this symbol if it has a non-zero count
911 	if (nr_modules == 0 || module != old_name) {
912 		if (has_sample_counts((*it)->sample.counts, lo, hi)) {
913 			add_module_symbol(module, it);
914 			return true;
915 		}
916 	} else {
917 		// propagate symbols count to module
918 		my_modules[nr_modules-1].add_to_summary((*it)->sample.counts);
919 	}
920 	return false;
921 }
922 
923 
dump()924 void thread_info::dump()
925 {
926 	cverb << vxml << "tid=" << thread_id << endl;
927 	for (size_t i = 0; i < nr_modules; ++i)
928 		my_modules[i].dump();
929 }
930 
931 
set_end(sym_iterator end)932 void process_info::set_end(sym_iterator end)
933 {
934 	for (size_t t = 0; t < nr_threads; ++t)
935 		my_threads[t].set_end(end);
936 }
937 
938 
output(ostream & out)939 void process_info::output(ostream & out)
940 {
941 	ostringstream process_summary;
942 	ostringstream thread_output;
943 
944 	output_summary(process_summary);
945 
946 	for (size_t t = 0; t < nr_threads; ++t)
947 		my_threads[t].output(thread_output);
948 
949 	// ignore processes with no sample data
950 	if (thread_output.str().size() == 0 && process_summary.str().size() == 0)
951 		return;
952 
953 	out << open_element(PROCESS, true);
954 	out << init_attr(PROC_ID, process_id);
955 	out << init_attr(NAME, name) << close_element(NONE, true);
956 	out << process_summary.str();
957 	out << thread_output.str();
958 	out << close_element(PROCESS);
959 }
960 
961 
dump()962 void process_info::dump()
963 {
964 	cverb << vxml << "pid=" << process_id << " app=" << name << endl;
965 	for (size_t i = 0; i < nr_threads; ++i)
966 		my_threads[i].dump();
967 }
968 
get_next_tgid_pclass(size_t start)969 size_t get_next_tgid_pclass(size_t start)
970 {
971 	string cur_tgid = classes.v[start].ptemplate.tgid;
972 	size_t i = start;
973 	for (i = start;
974 		i < nr_classes && classes.v[i].ptemplate.tgid == cur_tgid;
975 		++i) ;
976 	return i;
977 }
978 
979 
get_next_tid_pclass(size_t start)980 size_t get_next_tid_pclass(size_t start)
981 {
982 	string cur_tid = classes.v[start].ptemplate.tid;
983 	size_t i;
984 	for (i = start;
985 		i < nr_classes && classes.v[i].ptemplate.tid == cur_tid;
986 		++i) ;
987 	return i;
988 }
989 
990 
991 // build the process/thread/module hierarchy that will allow us later
992 // to collect the summary sample data at each level and then
993 // traverse the hierarchy to intersperse the summary data for the
994 // symbols
build_process_tree()995 void build_process_tree()
996 {
997 	size_t tgid = 0;
998 	size_t tid = 0;
999 
1000 	// build the structure representing the process/thread/module hierarchy
1001 	// for holding the summary data associated with each level and to be
1002 	// traversed when outputting the body of the XML
1003 	do {
1004 		size_t next_tgid = get_next_tgid_pclass(tgid);
1005 		string const tgid_str = classes.v[tgid].ptemplate.tgid;
1006 
1007 		process_info * p = processes_root.add_process(tgid_str, tgid, next_tgid-1);
1008 
1009 		do {
1010 			size_t next_tid = get_next_tid_pclass(tid);
1011 
1012 			// build array of threads associated with this process
1013 			p->add_thread(classes.v[tid].ptemplate.tid, tid, next_tid-1);
1014 			tid = next_tid;
1015 		} while (tid != next_tgid);
1016 		tgid = next_tgid;
1017 	} while (tgid != nr_classes);
1018 }
1019 
output_program_structure(ostream & out)1020 void xml_utils::output_program_structure(ostream & out)
1021 {
1022 
1023 	if (cverb << vxml)
1024 		dump_classes();
1025 
1026 	if (has_separated_thread_info()) {
1027 		build_process_tree();
1028 		processes_root.summarize_processes(extra_found_images);
1029 		if (cverb << vxml)
1030 			processes_root.dump_processes();
1031 		processes_root.output_process_symbols(out);
1032 	} else {
1033 		binaries_root.summarize_binaries(extra_found_images);
1034 		if (cverb << vxml)
1035 			binaries_root.dump_binaries();
1036 		binaries_root.output_binary_symbols(out);
1037 	}
1038 }
1039