Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(305)

Side by Side Diff: src/perf-jit.cc

Issue 1809203007: Linux perf integration with the new support for JIT. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fixes Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/perf-jit.h ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "src/perf-jit.h"
29
30 #include "src/assembler.h"
31 #include "src/objects-inl.h"
32
33 #if V8_OS_LINUX
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <unistd.h>
37 #endif // V8_OS_LINUX
38
39 namespace v8 {
40 namespace internal {
41
42 #if V8_OS_LINUX
43
44 struct PerfJitHeader {
45 uint32_t magic_;
46 uint32_t version_;
47 uint32_t size_;
48 uint32_t elf_mach_target_;
49 uint32_t reserved_;
50 uint32_t process_id_;
51 uint64_t time_stamp_;
52 uint64_t flags_;
53
54 static const uint32_t kMagic = 0x4A695444;
55 static const uint32_t kVersion = 1;
56 };
57
58 struct PerfJitBase {
59 enum PerfJitEvent { kLoad = 0, kMove = 1, kDebugInfo = 2, kClose = 3 };
60
61 uint32_t event_;
62 uint32_t size_;
63 uint64_t time_stamp_;
64 };
65
66 struct PerfJitCodeLoad : PerfJitBase {
67 uint32_t process_id_;
68 uint32_t thread_id_;
69 uint64_t vma_;
70 uint64_t code_address_;
71 uint64_t code_size_;
72 uint64_t code_id_;
73 };
74
75 struct PerfJitDebugEntry {
76 uint64_t address_;
77 int line_number_;
78 int column_;
79 // Followed by null-terminated name or \0xff\0 if same as previous.
80 };
81
82 struct PerfJitCodeDebugInfo : PerfJitBase {
83 uint64_t address_;
84 uint64_t entry_count_;
85 // Followed by entry_count_ instances of PerfJitDebugEntry.
86 };
87
88 const char PerfJitLogger::kFilenameFormatString[] = "./jit-%d.dump";
89
90 // Extra padding for the PID in the filename
91 const int PerfJitLogger::kFilenameBufferPadding = 16;
92
93 void PerfJitLogger::OpenJitDumpFile() {
94 // Open the perf JIT dump file.
95 perf_output_handle_ = nullptr;
96
97 int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding;
98 ScopedVector<char> perf_dump_name(bufferSize);
99 int size = SNPrintF(perf_dump_name, kFilenameFormatString,
100 base::OS::GetCurrentProcessId());
101 CHECK_NE(size, -1);
102
103 int fd = open(perf_dump_name.start(), O_CREAT | O_TRUNC | O_RDWR, 0666);
104 if (fd == -1) return;
105
106 marker_address_ = OpenMarkerFile(fd);
107 if (marker_address_ == nullptr) return;
108
109 perf_output_handle_ = fdopen(fd, "w+");
110 if (perf_output_handle_ == nullptr) return;
111
112 setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize);
113 }
114
115 void PerfJitLogger::CloseJitDumpFile() {
116 if (perf_output_handle_ == nullptr) return;
117 fclose(perf_output_handle_);
118 perf_output_handle_ = nullptr;
119 }
120
121 void* PerfJitLogger::OpenMarkerFile(int fd) {
122 long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int)
123 if (page_size == -1) return nullptr;
124
125 // Mmap the file so that there is a mmap record in the perf_data file.
126 //
127 // The map must be PROT_EXEC to ensure it is not ignored by perf record.
128 void* marker_address =
129 mmap(nullptr, page_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
130 return (marker_address == MAP_FAILED) ? nullptr : marker_address;
131 }
132
133 void PerfJitLogger::CloseMarkerFile(void* marker_address) {
134 if (marker_address == nullptr) return;
135 long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int)
136 if (page_size == -1) return;
137 munmap(marker_address, page_size);
138 }
139
140 PerfJitLogger::PerfJitLogger()
141 : perf_output_handle_(nullptr), code_index_(0), marker_address_(nullptr) {
142 OpenJitDumpFile();
143 if (perf_output_handle_ == nullptr) return;
144 LogWriteHeader();
145 }
146
147 PerfJitLogger::~PerfJitLogger() { CloseJitDumpFile(); }
148
149 uint64_t PerfJitLogger::GetTimestamp() {
150 struct timespec ts;
151 int result = clock_gettime(CLOCK_MONOTONIC, &ts);
152 DCHECK_EQ(0, result);
153 USE(result);
154 static const uint64_t kNsecPerSec = 1000000000;
155 return (ts.tv_sec * kNsecPerSec) + ts.tv_nsec;
156 }
157
158 void PerfJitLogger::LogRecordedBuffer(AbstractCode* abstract_code,
159 SharedFunctionInfo* shared,
160 const char* name, int length) {
161 if (perf_output_handle_ == nullptr) return;
162 if (FLAG_perf_basic_prof_only_functions &&
163 (abstract_code->kind() != AbstractCode::FUNCTION &&
164 abstract_code->kind() != AbstractCode::INTERPRETED_FUNCTION &&
165 abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION)) {
166 return;
167 }
168
169 // We only support non-interpreted functions.
170 if (!abstract_code->IsCode()) return;
171 Code* code = abstract_code->GetCode();
172 DCHECK(code->instruction_start() == code->address() + Code::kHeaderSize);
173
174 const char* code_name = name;
175 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start());
176 uint32_t code_size = code->is_crankshafted() ? code->safepoint_table_offset()
177 : code->instruction_size();
178
179 static const char string_terminator[] = "\0";
180
181 PerfJitCodeLoad code_load;
182 code_load.event_ = PerfJitCodeLoad::kLoad;
183 code_load.size_ = sizeof(code_load) + length + 1 + code_size;
184 code_load.time_stamp_ = GetTimestamp();
185 code_load.process_id_ =
186 static_cast<uint32_t>(base::OS::GetCurrentProcessId());
187 code_load.thread_id_ = static_cast<uint32_t>(base::OS::GetCurrentThreadId());
188 code_load.vma_ = 0x0; // Our addresses are absolute.
189 code_load.code_address_ = reinterpret_cast<uint64_t>(code_pointer);
190 code_load.code_size_ = code_size;
191 code_load.code_id_ = code_index_;
192
193 code_index_++;
194
195 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load));
196 LogWriteBytes(code_name, length);
197 LogWriteBytes(string_terminator, 1);
198 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size);
199
200 if (FLAG_perf_prof_debug_info) {
201 LogWriteDebugInfo(code, shared);
202 }
203 }
204
205 void PerfJitLogger::LogWriteDebugInfo(Code* code, SharedFunctionInfo* shared) {
206 // Compute the entry count and get the name of the script.
207 uint32_t entry_count = 0;
208 for (RelocIterator it(code, RelocInfo::kPositionMask); !it.done();
209 it.next()) {
210 entry_count++;
211 }
212 if (entry_count == 0) return;
213 Handle<Script> script(Script::cast(shared->script()));
214 Handle<Object> name_or_url(Script::GetNameOrSourceURL(script));
215
216 int name_length = 0;
217 base::SmartArrayPointer<char> name_string;
218 if (name_or_url->IsString()) {
219 name_string =
220 Handle<String>::cast(name_or_url)
221 ->ToCString(DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &name_length);
222 DCHECK_EQ(0, name_string.get()[name_length]);
223 } else {
224 const char unknown[] = "<unknown>";
225 name_length = static_cast<int>(strlen(unknown));
226 char* buffer = NewArray<char>(name_length);
227 base::OS::StrNCpy(buffer, name_length + 1, unknown,
228 static_cast<size_t>(name_length));
229 name_string = base::SmartArrayPointer<char>(buffer);
230 }
231 DCHECK_EQ(name_length, strlen(name_string.get()));
232
233 PerfJitCodeDebugInfo debug_info;
234
235 debug_info.event_ = PerfJitCodeLoad::kDebugInfo;
236 debug_info.time_stamp_ = GetTimestamp();
237 debug_info.address_ = reinterpret_cast<uint64_t>(code->instruction_start());
238 debug_info.entry_count_ = entry_count;
239
240 uint32_t size = sizeof(debug_info);
241 // Add the sizes of fixed parts of entries.
242 size += entry_count * sizeof(PerfJitDebugEntry);
243 // Add the size of the name after the first entry.
244 size += static_cast<uint32_t>(name_length) + 1;
245 // Add the sizes of the links to previous name (\0xff\0).
246 size += (entry_count - 1) * 2;
247
248 int padding = ((size + 7) & (~7)) - size;
249
250 debug_info.size_ = size + padding;
251
252 LogWriteBytes(reinterpret_cast<const char*>(&debug_info), sizeof(debug_info));
253
254 int script_line_offset = script->line_offset();
255 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
256
257 bool is_first = true;
258 for (RelocIterator it(code, RelocInfo::kPositionMask); !it.done();
259 it.next()) {
260 int position = static_cast<int>(it.rinfo()->data());
261 int line_number = Script::GetLineNumber(script, position);
262 // Compute column.
263 int relative_line_number = line_number - script_line_offset;
264 int start =
265 (relative_line_number == 0)
266 ? 0
267 : Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
268 int column_offset = position - start;
269 if (relative_line_number == 0) {
270 // For the case where the code is on the same line as the script tag.
271 column_offset += script->column_offset();
272 }
273
274 PerfJitDebugEntry entry;
275 entry.address_ = reinterpret_cast<uint64_t>(it.rinfo()->pc());
276 entry.line_number_ = line_number;
277 entry.column_ = column_offset;
278 LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry));
279
280 if (is_first) {
281 is_first = false;
282 LogWriteBytes(name_string.get(), name_length + 1);
283 } else {
284 LogWriteBytes("\xff", 2);
285 }
286 }
287 char padding_bytes[] = "\0\0\0\0\0\0\0\0";
288 LogWriteBytes(padding_bytes, padding);
289 }
290
291 void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) {
292 // Code relocation not supported.
293 UNREACHABLE();
294 }
295
296 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) {
297 size_t rv = fwrite(bytes, 1, size, perf_output_handle_);
298 DCHECK(static_cast<size_t>(size) == rv);
299 USE(rv);
300 }
301
302 void PerfJitLogger::LogWriteHeader() {
303 DCHECK(perf_output_handle_ != NULL);
304 PerfJitHeader header;
305
306 header.magic_ = PerfJitHeader::kMagic;
307 header.version_ = PerfJitHeader::kVersion;
308 header.size_ = sizeof(header);
309 header.elf_mach_target_ = GetElfMach();
310 header.reserved_ = 0xdeadbeef;
311 header.process_id_ = base::OS::GetCurrentProcessId();
312 header.time_stamp_ =
313 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0);
314 header.flags_ = 0;
315
316 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header));
317 }
318
319 #endif // V8_OS_LINUX
320 } // namespace internal
321 } // namespace v8
OLDNEW
« no previous file with comments | « src/perf-jit.h ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698