1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #define LOG_TAG "perf_reader" 6 7 #include "perf_utils.h" 8 9 #include <sys/stat.h> 10 11 #include <cctype> 12 #include <cstddef> 13 #include <cstdlib> 14 #include <cstring> 15 #include <fstream> // NOLINT(readability/streams) 16 #include <iomanip> 17 #include <sstream> 18 19 #include "base/logging.h" 20 #include "base/macros.h" 21 22 namespace { 23 24 // Number of hex digits in a byte. 25 const int kNumHexDigitsInByte = 2; 26 27 } // namespace 28 29 namespace quipper { 30 31 event_t* CallocMemoryForEvent(size_t size) { 32 event_t* event = reinterpret_cast<event_t*>(calloc(1, size)); 33 CHECK(event); 34 return event; 35 } 36 37 build_id_event* CallocMemoryForBuildID(size_t size) { 38 build_id_event* event = reinterpret_cast<build_id_event*>(calloc(1, size)); 39 CHECK(event); 40 return event; 41 } 42 43 string HexToString(const u8* array, size_t length) { 44 // Convert the bytes to hex digits one at a time. 45 // There will be kNumHexDigitsInByte hex digits, and 1 char for NUL. 46 char buffer[kNumHexDigitsInByte + 1]; 47 string result = ""; 48 for (size_t i = 0; i < length; ++i) { 49 snprintf(buffer, sizeof(buffer), "%02x", array[i]); 50 result += buffer; 51 } 52 return result; 53 } 54 55 bool StringToHex(const string& str, u8* array, size_t length) { 56 const int kHexRadix = 16; 57 char* err; 58 // Loop through kNumHexDigitsInByte characters at a time (to get one byte) 59 // Stop when there are no more characters, or the array has been filled. 60 for (size_t i = 0; 61 (i + 1) * kNumHexDigitsInByte <= str.size() && i < length; 62 ++i) { 63 string one_byte = str.substr(i * kNumHexDigitsInByte, kNumHexDigitsInByte); 64 array[i] = strtol(one_byte.c_str(), &err, kHexRadix); 65 if (*err) 66 return false; 67 } 68 return true; 69 } 70 71 uint64_t AlignSize(uint64_t size, uint32_t align_size) { 72 return ((size + align_size - 1) / align_size) * align_size; 73 } 74 75 // In perf data, strings are packed into the smallest number of 8-byte blocks 76 // possible, including the null terminator. 77 // e.g. 78 // "0123" -> 5 bytes -> packed into 8 bytes 79 // "0123456" -> 8 bytes -> packed into 8 bytes 80 // "01234567" -> 9 bytes -> packed into 16 bytes 81 // "0123456789abcd" -> 15 bytes -> packed into 16 bytes 82 // "0123456789abcde" -> 16 bytes -> packed into 16 bytes 83 // "0123456789abcdef" -> 17 bytes -> packed into 24 bytes 84 // 85 // Returns the size of the 8-byte-aligned memory for storing |string|. 86 size_t GetUint64AlignedStringLength(const string& str) { 87 return AlignSize(str.size() + 1, sizeof(uint64_t)); 88 } 89 90 uint64_t GetSampleFieldsForEventType(uint32_t event_type, 91 uint64_t sample_type) { 92 uint64_t mask = kuint64max; 93 switch (event_type) { 94 case PERF_RECORD_MMAP: 95 case PERF_RECORD_LOST: 96 case PERF_RECORD_COMM: 97 case PERF_RECORD_EXIT: 98 case PERF_RECORD_THROTTLE: 99 case PERF_RECORD_UNTHROTTLE: 100 case PERF_RECORD_FORK: 101 case PERF_RECORD_READ: 102 case PERF_RECORD_MMAP2: 103 // See perf_event.h "struct" sample_id and sample_id_all. 104 mask = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | 105 PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER; 106 break; 107 case PERF_RECORD_SAMPLE: 108 break; 109 default: 110 LOG(FATAL) << "Unknown event type " << event_type; 111 } 112 return sample_type & mask; 113 } 114 115 uint64_t GetPerfSampleDataOffset(const event_t& event) { 116 uint64_t offset = kuint64max; 117 switch (event.header.type) { 118 case PERF_RECORD_SAMPLE: 119 offset = offsetof(event_t, sample.array); 120 break; 121 case PERF_RECORD_MMAP: 122 offset = sizeof(event.mmap) - sizeof(event.mmap.filename) + 123 GetUint64AlignedStringLength(event.mmap.filename); 124 break; 125 case PERF_RECORD_FORK: 126 case PERF_RECORD_EXIT: 127 offset = sizeof(event.fork); 128 break; 129 case PERF_RECORD_COMM: 130 offset = sizeof(event.comm) - sizeof(event.comm.comm) + 131 GetUint64AlignedStringLength(event.comm.comm); 132 break; 133 case PERF_RECORD_LOST: 134 offset = sizeof(event.lost); 135 break; 136 case PERF_RECORD_READ: 137 offset = sizeof(event.read); 138 break; 139 case PERF_RECORD_MMAP2: 140 offset = sizeof(event.mmap2) - sizeof(event.mmap2.filename) + 141 GetUint64AlignedStringLength(event.mmap2.filename); 142 break; 143 default: 144 LOG(FATAL) << "Unknown/unsupported event type " << event.header.type; 145 break; 146 } 147 // Make sure the offset was valid 148 CHECK_NE(offset, kuint64max); 149 CHECK_EQ(offset % sizeof(uint64_t), 0U); 150 return offset; 151 } 152 153 bool ReadFileToData(const string& filename, std::vector<char>* data) { 154 std::ifstream in(filename.c_str(), std::ios::binary); 155 if (!in.good()) { 156 LOG(ERROR) << "Failed to open file " << filename; 157 return false; 158 } 159 in.seekg(0, in.end); 160 size_t length = in.tellg(); 161 in.seekg(0, in.beg); 162 data->resize(length); 163 164 in.read(&(*data)[0], length); 165 166 if (!in.good()) { 167 LOG(ERROR) << "Error reading from file " << filename; 168 return false; 169 } 170 return true; 171 } 172 173 bool WriteDataToFile(const std::vector<char>& data, const string& filename) { 174 std::ofstream out(filename.c_str(), std::ios::binary); 175 out.seekp(0, std::ios::beg); 176 out.write(&data[0], data.size()); 177 return out.good(); 178 } 179 180 } // namespace quipper 181