• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
38 using namespace std;
39 
40 extern verbose vbfd;
41 
op_check_header(opd_header const & h1,opd_header const & h2,string const & filename)42 void 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 
68 namespace {
69 
70 set<string> warned_files;
71 
72 }
73 
is_jit_sample(string const & filename)74 bool 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 
check_mtime(string const & file,opd_header const & header)88 void 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 #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 
123 		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 		}
132 
133 #ifdef ANDROID
134 		}
135 #endif
136 	}
137 }
138 
139 
read_header(string const & sample_filename)140 opd_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 
167 namespace {
168 
op_print_event(op_cpu cpu_type,u32 type,u32 um,u32 count)169 string 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 
op_xml_print_event(op_cpu cpu_type,u32 type,u32 um,u32 count)215 string 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 
describe_header(opd_header const & header)243 string 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 
describe_cpu(opd_header const & header)256 string 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 }
275