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#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 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} 275