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 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 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 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 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 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 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 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 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