op_header.cpp revision 8cfa702f803c5ef6a2b062a489a1b2cf66b45b5e
1/**
2 * @file op_header.cpp
3 * various free function acting on a sample file header
4 *
5 * @remark Copyright 2004 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 * @Modifications Daniel Hansel
11 */
12
13#include <cstring>
14#include <iostream>
15#include <cstdlib>
16#include <iomanip>
17#include <set>
18#include <sstream>
19#include <cstring>
20
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <unistd.h>
25
26#include "op_config.h"
27#include "op_exception.h"
28#include "odb.h"
29#include "op_cpu_type.h"
30#include "op_file.h"
31#include "op_header.h"
32#include "op_events.h"
33#include "string_manip.h"
34#include "format_output.h"
35#include "xml_utils.h"
36#include "cverb.h"
37
38using namespace std;
39
40extern verbose vbfd;
41
42void op_check_header(opd_header const & h1, opd_header const & h2,
43		     string const & filename)
44{
45	if (h1.mtime != h2.mtime) {
46		ostringstream os;
47		os << "header timestamps are different ("
48		   << h1.mtime << ", " << h2.mtime << ") for "
49		   << filename << "\n";
50		throw op_fatal_error(os.str());
51	}
52
53	if (h1.is_kernel != h2.is_kernel) {
54		ostringstream os;
55		os << "header is_kernel flags are different for "
56		   << filename << "\n";
57		throw op_fatal_error(os.str());
58	}
59
60	// Note that in the generated ELF file for anonymous code the vma
61	// of the symbol is exaclty the same vma as the code had during sampling.
62
63	// Note that we don't check CPU speed since that can vary
64	// freely on the same machine
65}
66
67
68namespace {
69
70set<string> warned_files;
71
72}
73
74bool is_jit_sample(string const & filename)
75{
76	// suffix for JIT sample files (see FIXME in check_mtime() below)
77	string suf = ".jo";
78
79	string::size_type pos;
80	pos = filename.rfind(suf);
81	// for JIT sample files do not output the warning to stderr.
82	if (pos != string::npos && pos == filename.size() - suf.size())
83		return true;
84	else
85		return false;
86}
87
88void check_mtime(string const & file, opd_header const & header)
89{
90	time_t const newmtime = op_get_mtime(file.c_str());
91
92	if (newmtime == header.mtime)
93		return;
94
95	if (warned_files.find(file) != warned_files.end())
96		return;
97
98	warned_files.insert(file);
99
100	// Files we couldn't get mtime of have zero mtime
101	if (!header.mtime) {
102		// FIXME: header.mtime for JIT sample files is 0. The problem could be that
103		//        in opd_mangling.c:opd_open_sample_file() the call of fill_header()
104		//        think that the JIT sample file is not a binary file.
105		if (is_jit_sample(file)) {
106			cverb << vbfd << "warning: could not check that the binary file "
107			      << file << " has not been modified since "
108			      "the profile was taken. Results may be inaccurate.\n";
109		} else {
110			cerr << "warning: could not check that the binary file "
111			     << file << " has not been modified since "
112			     "the profile was taken. Results may be inaccurate.\n";
113		}
114	} else {
115		static bool warned_already = false;
116
117		cerr << "warning: the last modified time of the binary file "
118		     "does not match that of the sample file for " << file
119		     << "\n";
120
121		if (!warned_already) {
122			cerr << "Either this is the wrong binary or the binary "
123			"has been modified since the sample file was created.\n";
124			warned_already = true;
125		}
126	}
127}
128
129
130opd_header const read_header(string const & sample_filename)
131{
132	int fd = open(sample_filename.c_str(), O_RDONLY);
133	if (fd < 0)
134		throw op_fatal_error("Can't open sample file:" +
135				     sample_filename);
136
137	opd_header header;
138	if (read(fd, &header, sizeof(header)) != sizeof(header)) {
139		close(fd);
140		throw op_fatal_error("Can't read sample file header:" +
141				     sample_filename);
142	}
143
144	if (memcmp(header.magic, OPD_MAGIC, sizeof(header.magic))) {
145		throw op_fatal_error("Invalid sample file, "
146				     "bad magic number: " +
147				     sample_filename);
148		close(fd);
149	}
150
151	close(fd);
152
153	return header;
154}
155
156
157namespace {
158
159string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count)
160{
161	string str;
162
163	if (cpu_type == CPU_TIMER_INT) {
164		str += "Profiling through timer interrupt";
165		return str;
166	}
167
168	struct op_event * event = op_find_event(cpu_type, type, um);
169
170	if (!event) {
171		event = op_find_event_any(cpu_type, type);
172		if (!event) {
173			cerr << "Could not locate event " << int(type) << endl;
174			str = "Unknown event";
175			return str;
176		}
177	}
178
179	char const * um_desc = 0;
180
181	for (size_t i = 0; i < event->unit->num; ++i) {
182		if (event->unit->um[i].value == um)
183			um_desc = event->unit->um[i].desc;
184	}
185
186	str += string("Counted ") + event->name;
187	str += string(" events (") + event->desc + ")";
188
189	if (cpu_type != CPU_RTC) {
190		str += " with a unit mask of 0x";
191
192		ostringstream ss;
193		ss << hex << setw(2) << setfill('0') << unsigned(um);
194		str += ss.str();
195
196		str += " (";
197		str += um_desc ? um_desc : "multiple flags";
198		str += ")";
199	}
200
201	str += " count " + op_lexical_cast<string>(count);
202	return str;
203}
204
205string const op_xml_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count)
206{
207	string unit_mask;
208
209	if (cpu_type == CPU_TIMER_INT || cpu_type == CPU_RTC)
210		return xml_utils::get_timer_setup((size_t)count);
211
212	struct op_event * event = op_find_event(cpu_type, type, um);
213	if (!event) {
214		event = op_find_event_any(cpu_type, type);
215		if (!event) {
216			cerr << "Could not locate event " << int(type) << endl;
217			return "";
218		}
219	}
220
221	if (cpu_type != CPU_RTC) {
222		ostringstream str_out;
223		str_out << um;
224		unit_mask = str_out.str();
225	}
226
227	return xml_utils::get_event_setup(string(event->name),
228		(size_t)count, unit_mask);
229}
230
231}
232
233string const describe_header(opd_header const & header)
234{
235	op_cpu cpu = static_cast<op_cpu>(header.cpu_type);
236
237	if (want_xml)
238		return op_xml_print_event(cpu, header.ctr_event,
239	                      header.ctr_um, header.ctr_count);
240	else
241		return op_print_event(cpu, header.ctr_event,
242	                      header.ctr_um, header.ctr_count);
243}
244
245
246string const describe_cpu(opd_header const & header)
247{
248	op_cpu cpu = static_cast<op_cpu>(header.cpu_type);
249
250	string str;
251	if (want_xml) {
252		string cpu_name = op_get_cpu_name(cpu);
253
254		str = xml_utils::get_profile_header(cpu_name, header.cpu_speed);
255	} else {
256		str += string("CPU: ") + op_get_cpu_type_str(cpu);
257		str += ", speed ";
258
259		ostringstream ss;
260		ss << header.cpu_speed;
261		str += ss.str() + " MHz (estimated)";
262	}
263	return str;
264}
265