blob: 938f5dd6ff1296c3f5d117565753ad4aab18d6ad [file] [log] [blame]
Mike Dodd8cfa7022010-11-17 11:12:26 -08001/**
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
Jeff Brown220b7ff2011-05-03 15:33:24 -0700117#ifdef ANDROID
118 // Android symbol files may not have the same timestamp as the stripped
119 // files deployed to the device. Suppress spurious warnings.
120 if (file.find("/symbols/") == string::npos) {
121#endif
122
Mike Dodd8cfa7022010-11-17 11:12:26 -0800123 cerr << "warning: the last modified time of the binary file "
124 "does not match that of the sample file for " << file
125 << "\n";
126
127 if (!warned_already) {
128 cerr << "Either this is the wrong binary or the binary "
129 "has been modified since the sample file was created.\n";
130 warned_already = true;
131 }
Jeff Brown220b7ff2011-05-03 15:33:24 -0700132
133#ifdef ANDROID
134 }
135#endif
Mike Dodd8cfa7022010-11-17 11:12:26 -0800136 }
137}
138
139
140opd_header const read_header(string const & sample_filename)
141{
142 int fd = open(sample_filename.c_str(), O_RDONLY);
143 if (fd < 0)
144 throw op_fatal_error("Can't open sample file:" +
145 sample_filename);
146
147 opd_header header;
148 if (read(fd, &header, sizeof(header)) != sizeof(header)) {
149 close(fd);
150 throw op_fatal_error("Can't read sample file header:" +
151 sample_filename);
152 }
153
154 if (memcmp(header.magic, OPD_MAGIC, sizeof(header.magic))) {
155 throw op_fatal_error("Invalid sample file, "
156 "bad magic number: " +
157 sample_filename);
158 close(fd);
159 }
160
161 close(fd);
162
163 return header;
164}
165
166
167namespace {
168
169string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count)
170{
171 string str;
172
173 if (cpu_type == CPU_TIMER_INT) {
174 str += "Profiling through timer interrupt";
175 return str;
176 }
177
178 struct op_event * event = op_find_event(cpu_type, type, um);
179
180 if (!event) {
181 event = op_find_event_any(cpu_type, type);
182 if (!event) {
183 cerr << "Could not locate event " << int(type) << endl;
184 str = "Unknown event";
185 return str;
186 }
187 }
188
189 char const * um_desc = 0;
190
191 for (size_t i = 0; i < event->unit->num; ++i) {
192 if (event->unit->um[i].value == um)
193 um_desc = event->unit->um[i].desc;
194 }
195
196 str += string("Counted ") + event->name;
197 str += string(" events (") + event->desc + ")";
198
199 if (cpu_type != CPU_RTC) {
200 str += " with a unit mask of 0x";
201
202 ostringstream ss;
203 ss << hex << setw(2) << setfill('0') << unsigned(um);
204 str += ss.str();
205
206 str += " (";
207 str += um_desc ? um_desc : "multiple flags";
208 str += ")";
209 }
210
211 str += " count " + op_lexical_cast<string>(count);
212 return str;
213}
214
215string const op_xml_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count)
216{
217 string unit_mask;
218
219 if (cpu_type == CPU_TIMER_INT || cpu_type == CPU_RTC)
220 return xml_utils::get_timer_setup((size_t)count);
221
222 struct op_event * event = op_find_event(cpu_type, type, um);
223 if (!event) {
224 event = op_find_event_any(cpu_type, type);
225 if (!event) {
226 cerr << "Could not locate event " << int(type) << endl;
227 return "";
228 }
229 }
230
231 if (cpu_type != CPU_RTC) {
232 ostringstream str_out;
233 str_out << um;
234 unit_mask = str_out.str();
235 }
236
237 return xml_utils::get_event_setup(string(event->name),
238 (size_t)count, unit_mask);
239}
240
241}
242
243string const describe_header(opd_header const & header)
244{
245 op_cpu cpu = static_cast<op_cpu>(header.cpu_type);
246
247 if (want_xml)
248 return op_xml_print_event(cpu, header.ctr_event,
249 header.ctr_um, header.ctr_count);
250 else
251 return op_print_event(cpu, header.ctr_event,
252 header.ctr_um, header.ctr_count);
253}
254
255
256string const describe_cpu(opd_header const & header)
257{
258 op_cpu cpu = static_cast<op_cpu>(header.cpu_type);
259
260 string str;
261 if (want_xml) {
262 string cpu_name = op_get_cpu_name(cpu);
263
264 str = xml_utils::get_profile_header(cpu_name, header.cpu_speed);
265 } else {
266 str += string("CPU: ") + op_get_cpu_type_str(cpu);
267 str += ", speed ";
268
269 ostringstream ss;
270 ss << header.cpu_speed;
271 str += ss.str() + " MHz (estimated)";
272 }
273 return str;
274}