/** * @file op_header.cpp * various free function acting on a sample file header * * @remark Copyright 2004 OProfile authors * @remark Read the file COPYING * * @author John Levon * @author Philippe Elie * @Modifications Daniel Hansel */ #include <cstring> #include <iostream> #include <cstdlib> #include <iomanip> #include <set> #include <sstream> #include <cstring> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "op_config.h" #include "op_exception.h" #include "odb.h" #include "op_cpu_type.h" #include "op_file.h" #include "op_header.h" #include "op_events.h" #include "string_manip.h" #include "format_output.h" #include "xml_utils.h" #include "cverb.h" using namespace std; extern verbose vbfd; void op_check_header(opd_header const & h1, opd_header const & h2, string const & filename) { if (h1.mtime != h2.mtime) { ostringstream os; os << "header timestamps are different (" << h1.mtime << ", " << h2.mtime << ") for " << filename << "\n"; throw op_fatal_error(os.str()); } if (h1.is_kernel != h2.is_kernel) { ostringstream os; os << "header is_kernel flags are different for " << filename << "\n"; throw op_fatal_error(os.str()); } // Note that in the generated ELF file for anonymous code the vma // of the symbol is exaclty the same vma as the code had during sampling. // Note that we don't check CPU speed since that can vary // freely on the same machine } namespace { set<string> warned_files; } bool is_jit_sample(string const & filename) { // suffix for JIT sample files (see FIXME in check_mtime() below) string suf = ".jo"; string::size_type pos; pos = filename.rfind(suf); // for JIT sample files do not output the warning to stderr. if (pos != string::npos && pos == filename.size() - suf.size()) return true; else return false; } void check_mtime(string const & file, opd_header const & header) { time_t const newmtime = op_get_mtime(file.c_str()); if (newmtime == header.mtime) return; if (warned_files.find(file) != warned_files.end()) return; warned_files.insert(file); // Files we couldn't get mtime of have zero mtime if (!header.mtime) { // FIXME: header.mtime for JIT sample files is 0. The problem could be that // in opd_mangling.c:opd_open_sample_file() the call of fill_header() // think that the JIT sample file is not a binary file. if (is_jit_sample(file)) { cverb << vbfd << "warning: could not check that the binary file " << file << " has not been modified since " "the profile was taken. Results may be inaccurate.\n"; } else { cerr << "warning: could not check that the binary file " << file << " has not been modified since " "the profile was taken. Results may be inaccurate.\n"; } } else { static bool warned_already = false; #ifdef ANDROID // Android symbol files may not have the same timestamp as the stripped // files deployed to the device. Suppress spurious warnings. if (file.find("/symbols/") == string::npos) { #endif cerr << "warning: the last modified time of the binary file " "does not match that of the sample file for " << file << "\n"; if (!warned_already) { cerr << "Either this is the wrong binary or the binary " "has been modified since the sample file was created.\n"; warned_already = true; } #ifdef ANDROID } #endif } } opd_header const read_header(string const & sample_filename) { int fd = open(sample_filename.c_str(), O_RDONLY); if (fd < 0) throw op_fatal_error("Can't open sample file:" + sample_filename); opd_header header; if (read(fd, &header, sizeof(header)) != sizeof(header)) { close(fd); throw op_fatal_error("Can't read sample file header:" + sample_filename); } if (memcmp(header.magic, OPD_MAGIC, sizeof(header.magic))) { throw op_fatal_error("Invalid sample file, " "bad magic number: " + sample_filename); close(fd); } close(fd); return header; } namespace { string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count) { string str; if (cpu_type == CPU_TIMER_INT) { str += "Profiling through timer interrupt"; return str; } struct op_event * event = op_find_event(cpu_type, type, um); if (!event) { event = op_find_event_any(cpu_type, type); if (!event) { cerr << "Could not locate event " << int(type) << endl; str = "Unknown event"; return str; } } char const * um_desc = 0; for (size_t i = 0; i < event->unit->num; ++i) { if (event->unit->um[i].value == um) um_desc = event->unit->um[i].desc; } str += string("Counted ") + event->name; str += string(" events (") + event->desc + ")"; if (cpu_type != CPU_RTC) { str += " with a unit mask of 0x"; ostringstream ss; ss << hex << setw(2) << setfill('0') << unsigned(um); str += ss.str(); str += " ("; str += um_desc ? um_desc : "multiple flags"; str += ")"; } str += " count " + op_lexical_cast<string>(count); return str; } string const op_xml_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count) { string unit_mask; if (cpu_type == CPU_TIMER_INT || cpu_type == CPU_RTC) return xml_utils::get_timer_setup((size_t)count); struct op_event * event = op_find_event(cpu_type, type, um); if (!event) { event = op_find_event_any(cpu_type, type); if (!event) { cerr << "Could not locate event " << int(type) << endl; return ""; } } if (cpu_type != CPU_RTC) { ostringstream str_out; str_out << um; unit_mask = str_out.str(); } return xml_utils::get_event_setup(string(event->name), (size_t)count, unit_mask); } } string const describe_header(opd_header const & header) { op_cpu cpu = static_cast<op_cpu>(header.cpu_type); if (want_xml) return op_xml_print_event(cpu, header.ctr_event, header.ctr_um, header.ctr_count); else return op_print_event(cpu, header.ctr_event, header.ctr_um, header.ctr_count); } string const describe_cpu(opd_header const & header) { op_cpu cpu = static_cast<op_cpu>(header.cpu_type); string str; if (want_xml) { string cpu_name = op_get_cpu_name(cpu); str = xml_utils::get_profile_header(cpu_name, header.cpu_speed); } else { str += string("CPU: ") + op_get_cpu_type_str(cpu); str += ", speed "; ostringstream ss; ss << header.cpu_speed; str += ss.str() + " MHz (estimated)"; } return str; }