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 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
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/eh-frame.h" |
31 #include "src/objects-inl.h" | 32 #include "src/objects-inl.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_unwinding_info) 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 if (code->has_unwinding_info()) { |
| 332 unwinding_info_header.unwinding_size_ = code->unwinding_info_size(); |
| 333 unwinding_info_header.mapped_size_ = unwinding_info_header.unwinding_size_; |
| 334 } else { |
| 335 unwinding_info_header.unwinding_size_ = EhFrameHdr::kRecordSize; |
| 336 unwinding_info_header.mapped_size_ = 0; |
| 337 } |
| 338 |
| 339 int content_size = static_cast<int>(sizeof(unwinding_info_header) + |
| 340 unwinding_info_header.unwinding_size_); |
| 341 int padding_size = RoundUp(content_size, 8) - content_size; |
| 342 unwinding_info_header.size_ = content_size + padding_size; |
| 343 |
| 344 LogWriteBytes(reinterpret_cast<const char*>(&unwinding_info_header), |
| 345 sizeof(unwinding_info_header)); |
| 346 |
| 347 if (code->has_unwinding_info()) { |
| 348 // The last EhFrameHdr::kRecordSize bytes were a placeholder for the header. |
| 349 // Discard them and write the actual eh_frame_hdr (below). |
| 350 DCHECK_GE(code->unwinding_info_size(), EhFrameHdr::kRecordSize); |
| 351 LogWriteBytes(reinterpret_cast<const char*>(code->unwinding_info_start()), |
| 352 code->unwinding_info_size() - EhFrameHdr::kRecordSize); |
| 353 } |
| 354 |
| 355 LogWriteBytes(reinterpret_cast<const char*>(&eh_frame_hdr), |
| 356 EhFrameHdr::kRecordSize); |
| 357 |
| 358 char padding_bytes[] = "\0\0\0\0\0\0\0\0"; |
| 359 DCHECK_LT(padding_size, sizeof(padding_bytes)); |
| 360 LogWriteBytes(padding_bytes, padding_size); |
| 361 } |
| 362 |
306 void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) { | 363 void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) { |
307 // Code relocation not supported. | 364 // Code relocation not supported. |
308 UNREACHABLE(); | 365 UNREACHABLE(); |
309 } | 366 } |
310 | 367 |
311 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { | 368 void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { |
312 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); | 369 size_t rv = fwrite(bytes, 1, size, perf_output_handle_); |
313 DCHECK(static_cast<size_t>(size) == rv); | 370 DCHECK(static_cast<size_t>(size) == rv); |
314 USE(rv); | 371 USE(rv); |
315 } | 372 } |
(...skipping 11 matching lines...) Expand all Loading... |
327 header.time_stamp_ = | 384 header.time_stamp_ = |
328 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); | 385 static_cast<uint64_t>(base::OS::TimeCurrentMillis() * 1000.0); |
329 header.flags_ = 0; | 386 header.flags_ = 0; |
330 | 387 |
331 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); | 388 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); |
332 } | 389 } |
333 | 390 |
334 #endif // V8_OS_LINUX | 391 #endif // V8_OS_LINUX |
335 } // namespace internal | 392 } // namespace internal |
336 } // namespace v8 | 393 } // namespace v8 |
OLD | NEW |