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