| 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 |