blob: 02fa9e069a8e815771e4d1302cff0b98b75bb98c [file] [log] [blame]
Than McIntosh7e2f4e92015-03-05 11:05:02 -05001// 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
22namespace {
23
24// Number of hex digits in a byte.
25const int kNumHexDigitsInByte = 2;
26
27} // namespace
28
29namespace quipper {
30
31event_t* CallocMemoryForEvent(size_t size) {
32 event_t* event = reinterpret_cast<event_t*>(calloc(1, size));
33 CHECK(event);
34 return event;
35}
36
37build_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
43string 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
55bool 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
71uint64_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|.
86size_t GetUint64AlignedStringLength(const string& str) {
87 return AlignSize(str.size() + 1, sizeof(uint64_t));
88}
89
90uint64_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
115uint64_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
153bool 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
173bool 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