OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 11 matching lines...) Expand all Loading... | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "src/perf-jit.h" | 28 #include "src/perf-jit.h" |
29 | 29 |
30 #include "src/assembler.h" | 30 #include "src/assembler.h" |
31 #include "src/objects-inl.h" | 31 #include "src/objects-inl.h" |
32 #include "src/unwinding-info.h" | |
32 | 33 |
33 #if V8_OS_LINUX | 34 #if V8_OS_LINUX |
34 #include <fcntl.h> | 35 #include <fcntl.h> |
35 #include <sys/mman.h> | 36 #include <sys/mman.h> |
36 #include <unistd.h> | 37 #include <unistd.h> |
37 #endif // V8_OS_LINUX | 38 #endif // V8_OS_LINUX |
38 | 39 |
39 namespace v8 { | 40 namespace v8 { |
40 namespace internal { | 41 namespace internal { |
41 | 42 |
42 #if V8_OS_LINUX | 43 #if V8_OS_LINUX |
43 | 44 |
44 struct PerfJitHeader { | 45 struct PerfJitHeader { |
45 uint32_t magic_; | 46 uint32_t magic_; |
46 uint32_t version_; | 47 uint32_t version_; |
47 uint32_t size_; | 48 uint32_t size_; |
48 uint32_t elf_mach_target_; | 49 uint32_t elf_mach_target_; |
49 uint32_t reserved_; | 50 uint32_t reserved_; |
50 uint32_t process_id_; | 51 uint32_t process_id_; |
51 uint64_t time_stamp_; | 52 uint64_t time_stamp_; |
52 uint64_t flags_; | 53 uint64_t flags_; |
53 | 54 |
54 static const uint32_t kMagic = 0x4A695444; | 55 static const uint32_t kMagic = 0x4A695444; |
55 static const uint32_t kVersion = 1; | 56 static const uint32_t kVersion = 1; |
56 }; | 57 }; |
57 | 58 |
58 struct PerfJitBase { | 59 struct PerfJitBase { |
59 enum PerfJitEvent { kLoad = 0, kMove = 1, kDebugInfo = 2, kClose = 3 }; | 60 enum PerfJitEvent { |
61 kLoad = 0, | |
62 kMove = 1, | |
63 kDebugInfo = 2, | |
64 kClose = 3, | |
65 kUnwindingInfo = 4 | |
66 }; | |
60 | 67 |
61 uint32_t event_; | 68 uint32_t event_; |
62 uint32_t size_; | 69 uint32_t size_; |
63 uint64_t time_stamp_; | 70 uint64_t time_stamp_; |
64 }; | 71 }; |
65 | 72 |
66 struct PerfJitCodeLoad : PerfJitBase { | 73 struct PerfJitCodeLoad : PerfJitBase { |
67 uint32_t process_id_; | 74 uint32_t process_id_; |
68 uint32_t thread_id_; | 75 uint32_t thread_id_; |
69 uint64_t vma_; | 76 uint64_t vma_; |
70 uint64_t code_address_; | 77 uint64_t code_address_; |
71 uint64_t code_size_; | 78 uint64_t code_size_; |
72 uint64_t code_id_; | 79 uint64_t code_id_; |
73 }; | 80 }; |
74 | 81 |
75 struct PerfJitDebugEntry { | 82 struct PerfJitDebugEntry { |
76 uint64_t address_; | 83 uint64_t address_; |
77 int line_number_; | 84 int line_number_; |
78 int column_; | 85 int column_; |
79 // Followed by null-terminated name or \0xff\0 if same as previous. | 86 // Followed by null-terminated name or \0xff\0 if same as previous. |
80 }; | 87 }; |
81 | 88 |
82 struct PerfJitCodeDebugInfo : PerfJitBase { | 89 struct PerfJitCodeDebugInfo : PerfJitBase { |
83 uint64_t address_; | 90 uint64_t address_; |
84 uint64_t entry_count_; | 91 uint64_t entry_count_; |
85 // Followed by entry_count_ instances of PerfJitDebugEntry. | 92 // Followed by entry_count_ instances of PerfJitDebugEntry. |
86 }; | 93 }; |
87 | 94 |
95 struct PerfJitCodeUnwindingInfo : PerfJitBase { | |
96 uint64_t unwinding_size_; | |
97 uint64_t eh_frame_hdr_size_; | |
98 uint64_t mapped_size_; | |
99 // Followed by size_ - sizeof(PerfJitCodeUnwindingInfo) bytes of data. | |
100 }; | |
101 | |
88 const char PerfJitLogger::kFilenameFormatString[] = "./jit-%d.dump"; | 102 const char PerfJitLogger::kFilenameFormatString[] = "./jit-%d.dump"; |
89 | 103 |
90 // Extra padding for the PID in the filename | 104 // Extra padding for the PID in the filename |
91 const int PerfJitLogger::kFilenameBufferPadding = 16; | 105 const int PerfJitLogger::kFilenameBufferPadding = 16; |
92 | 106 |
93 base::LazyRecursiveMutex PerfJitLogger::file_mutex_; | 107 base::LazyRecursiveMutex PerfJitLogger::file_mutex_; |
94 // The following static variables are protected by PerfJitLogger::file_mutex_. | 108 // The following static variables are protected by PerfJitLogger::file_mutex_. |
95 uint64_t PerfJitLogger::reference_count_ = 0; | 109 uint64_t PerfJitLogger::reference_count_ = 0; |
96 void* PerfJitLogger::marker_address_ = nullptr; | 110 void* PerfJitLogger::marker_address_ = nullptr; |
97 uint64_t PerfJitLogger::code_index_ = 0; | 111 uint64_t PerfJitLogger::code_index_ = 0; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
197 // Debug info has to be emitted first. | 211 // Debug info has to be emitted first. |
198 if (FLAG_perf_prof_debug_info && shared != nullptr) { | 212 if (FLAG_perf_prof_debug_info && shared != nullptr) { |
199 LogWriteDebugInfo(code, shared); | 213 LogWriteDebugInfo(code, shared); |
200 } | 214 } |
201 | 215 |
202 const char* code_name = name; | 216 const char* code_name = name; |
203 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start()); | 217 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start()); |
204 uint32_t code_size = code->is_crankshafted() ? code->safepoint_table_offset() | 218 uint32_t code_size = code->is_crankshafted() ? code->safepoint_table_offset() |
205 : code->instruction_size(); | 219 : code->instruction_size(); |
206 | 220 |
221 // Unwinding info comes right after debug info. | |
222 if (FLAG_perf_prof) LogWriteUnwindingInfo(code); | |
223 | |
207 static const char string_terminator[] = "\0"; | 224 static const char string_terminator[] = "\0"; |
208 | 225 |
209 PerfJitCodeLoad code_load; | 226 PerfJitCodeLoad code_load; |
210 code_load.event_ = PerfJitCodeLoad::kLoad; | 227 code_load.event_ = PerfJitCodeLoad::kLoad; |
211 code_load.size_ = sizeof(code_load) + length + 1 + code_size; | 228 code_load.size_ = sizeof(code_load) + length + 1 + code_size; |
212 code_load.time_stamp_ = GetTimestamp(); | 229 code_load.time_stamp_ = GetTimestamp(); |
213 code_load.process_id_ = | 230 code_load.process_id_ = |
214 static_cast<uint32_t>(base::OS::GetCurrentProcessId()); | 231 static_cast<uint32_t>(base::OS::GetCurrentProcessId()); |
215 code_load.thread_id_ = static_cast<uint32_t>(base::OS::GetCurrentThreadId()); | 232 code_load.thread_id_ = static_cast<uint32_t>(base::OS::GetCurrentThreadId()); |
216 code_load.vma_ = 0x0; // Our addresses are absolute. | 233 code_load.vma_ = 0x0; // Our addresses are absolute. |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
296 entry.address_ = reinterpret_cast<uint64_t>(it.rinfo()->pc()); | 313 entry.address_ = reinterpret_cast<uint64_t>(it.rinfo()->pc()); |
297 entry.line_number_ = line_number; | 314 entry.line_number_ = line_number; |
298 entry.column_ = column_offset; | 315 entry.column_ = column_offset; |
299 LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry)); | 316 LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry)); |
300 LogWriteBytes(name_string.get(), name_length + 1); | 317 LogWriteBytes(name_string.get(), name_length + 1); |
301 } | 318 } |
302 char padding_bytes[] = "\0\0\0\0\0\0\0\0"; | 319 char padding_bytes[] = "\0\0\0\0\0\0\0\0"; |
303 LogWriteBytes(padding_bytes, padding); | 320 LogWriteBytes(padding_bytes, padding); |
304 } | 321 } |
305 | 322 |
323 void PerfJitLogger::LogWriteUnwindingInfo(Code* code) { | |
324 EhFrameHdr eh_frame_hdr(code); | |
325 | |
326 PerfJitCodeUnwindingInfo unwinding_info_header; | |
327 unwinding_info_header.event_ = PerfJitCodeLoad::kUnwindingInfo; | |
328 unwinding_info_header.time_stamp_ = GetTimestamp(); | |
329 unwinding_info_header.eh_frame_hdr_size_ = EhFrameHdr::kRecordSize; | |
330 | |
331 int unwinding_info_size; | |
rmcilroy
2016/06/21 13:47:44
nit - just use the field rather than having an ext
Stefano Sanfilippo
2016/06/23 15:23:44
Done.
| |
332 if (code->has_unwinding_info()) { | |
333 unwinding_info_size = code->unwinding_info_size(); | |
334 unwinding_info_header.mapped_size_ = unwinding_info_size; | |
335 } else { | |
336 unwinding_info_size = EhFrameHdr::kRecordSize; | |
337 unwinding_info_header.mapped_size_ = 0; | |
338 } | |
339 unwinding_info_header.unwinding_size_ = unwinding_info_size; | |
340 | |
341 int content_size = sizeof(unwinding_info_header) + unwinding_info_size; | |
342 int padding_size = ((content_size + 7) & (~7)) - content_size; | |
rmcilroy
2016/06/21 13:47:44
Don't use literals for '7'. Can you use RoundUp he
Stefano Sanfilippo
2016/06/23 15:23:44
Done.
| |
343 unwinding_info_header.size_ = content_size + padding_size; | |
344 | |
345 LogWriteBytes(reinterpret_cast<const char*>(&unwinding_info_header), | |
346 sizeof(unwinding_info_header)); | |
347 | |
348 if (code->has_unwinding_info()) { | |
349 PatchProcedureBoundariesInEhFrame(code); | |
rmcilroy
2016/06/21 13:47:44
You don't have any code which actually writes to t
Stefano Sanfilippo
2016/06/23 15:23:44
Agreed. Done.
| |
350 | |
351 // The last EhFrameHdr::kRecordSize bytes were a placeholder for the header. | |
352 // Discard them and write the actual eh_frame_hdr (below). | |
353 DCHECK_GE(code->unwinding_info_size(), EhFrameHdr::kRecordSize); | |
354 LogWriteBytes(reinterpret_cast<const char*>(code->unwinding_info_start()), | |
355 code->unwinding_info_size() - EhFrameHdr::kRecordSize); | |
356 } | |
357 | |
358 LogWriteBytes(reinterpret_cast<const char*>(&eh_frame_hdr), | |
359 EhFrameHdr::kRecordSize); | |
360 | |
361 char padding_bytes[] = "\0\0\0\0\0\0\0\0"; | |
362 LogWriteBytes(padding_bytes, padding_size); | |
363 } | |
364 | |
306 void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) { | 365 void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) { |
307 // Code relocation not supported. | 366 // Code relocation not supported. |
308 UNREACHABLE(); | 367 UNREACHABLE(); |
309 } | 368 } |
310 | 369 |
311 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { | 370 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { |
312 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); | 371 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); |
313 DCHECK(static_cast<size_t>(size) == rv); | 372 DCHECK(static_cast<size_t>(size) == rv); |
314 USE(rv); | 373 USE(rv); |
315 } | 374 } |
(...skipping 11 matching lines...) Expand all Loading... | |
327 header.time_stamp_ = | 386 header.time_stamp_ = |
328 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); | 387 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); |
329 header.flags_ = 0; | 388 header.flags_ = 0; |
330 | 389 |
331 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); | 390 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); |
332 } | 391 } |
333 | 392 |
334 #endif // V8_OS_LINUX | 393 #endif // V8_OS_LINUX |
335 } // namespace internal | 394 } // namespace internal |
336 } // namespace v8 | 395 } // namespace v8 |
OLD | NEW |