diff options
Diffstat (limited to 'deps/v8/src/perf-jit.cc')
-rw-r--r-- | deps/v8/src/perf-jit.cc | 457 |
1 files changed, 0 insertions, 457 deletions
diff --git a/deps/v8/src/perf-jit.cc b/deps/v8/src/perf-jit.cc deleted file mode 100644 index c30047abb3..0000000000 --- a/deps/v8/src/perf-jit.cc +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2016 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "src/perf-jit.h" - -#include <memory> - -#include "src/assembler.h" -#include "src/eh-frame.h" -#include "src/objects-inl.h" -#include "src/ostreams.h" -#include "src/snapshot/embedded-data.h" -#include "src/source-position-table.h" -#include "src/wasm/wasm-code-manager.h" - -#if V8_OS_LINUX -#include <fcntl.h> -#include <sys/mman.h> -#undef MAP_TYPE // jumbo: conflicts with v8::internal::InstanceType::MAP_TYPE -#include <unistd.h> -#endif // V8_OS_LINUX - -namespace v8 { -namespace internal { - -#if V8_OS_LINUX - -struct PerfJitHeader { - uint32_t magic_; - uint32_t version_; - uint32_t size_; - uint32_t elf_mach_target_; - uint32_t reserved_; - uint32_t process_id_; - uint64_t time_stamp_; - uint64_t flags_; - - static const uint32_t kMagic = 0x4A695444; - static const uint32_t kVersion = 1; -}; - -struct PerfJitBase { - enum PerfJitEvent { - kLoad = 0, - kMove = 1, - kDebugInfo = 2, - kClose = 3, - kUnwindingInfo = 4 - }; - - uint32_t event_; - uint32_t size_; - uint64_t time_stamp_; -}; - -struct PerfJitCodeLoad : PerfJitBase { - uint32_t process_id_; - uint32_t thread_id_; - uint64_t vma_; - uint64_t code_address_; - uint64_t code_size_; - uint64_t code_id_; -}; - -struct PerfJitDebugEntry { - uint64_t address_; - int line_number_; - int column_; - // Followed by null-terminated name or \0xFF\0 if same as previous. -}; - -struct PerfJitCodeDebugInfo : PerfJitBase { - uint64_t address_; - uint64_t entry_count_; - // Followed by entry_count_ instances of PerfJitDebugEntry. -}; - -struct PerfJitCodeUnwindingInfo : PerfJitBase { - uint64_t unwinding_size_; - uint64_t eh_frame_hdr_size_; - uint64_t mapped_size_; - // Followed by size_ - sizeof(PerfJitCodeUnwindingInfo) bytes of data. -}; - -const char PerfJitLogger::kFilenameFormatString[] = "./jit-%d.dump"; - -// Extra padding for the PID in the filename -const int PerfJitLogger::kFilenameBufferPadding = 16; - -base::LazyRecursiveMutex PerfJitLogger::file_mutex_; -// The following static variables are protected by PerfJitLogger::file_mutex_. -uint64_t PerfJitLogger::reference_count_ = 0; -void* PerfJitLogger::marker_address_ = nullptr; -uint64_t PerfJitLogger::code_index_ = 0; -FILE* PerfJitLogger::perf_output_handle_ = nullptr; - -void PerfJitLogger::OpenJitDumpFile() { - // Open the perf JIT dump file. - perf_output_handle_ = nullptr; - - int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; - ScopedVector<char> perf_dump_name(bufferSize); - int size = SNPrintF(perf_dump_name, kFilenameFormatString, - base::OS::GetCurrentProcessId()); - CHECK_NE(size, -1); - - int fd = open(perf_dump_name.start(), O_CREAT | O_TRUNC | O_RDWR, 0666); - if (fd == -1) return; - - marker_address_ = OpenMarkerFile(fd); - if (marker_address_ == nullptr) return; - - perf_output_handle_ = fdopen(fd, "w+"); - if (perf_output_handle_ == nullptr) return; - - setvbuf(perf_output_handle_, nullptr, _IOFBF, kLogBufferSize); -} - -void PerfJitLogger::CloseJitDumpFile() { - if (perf_output_handle_ == nullptr) return; - fclose(perf_output_handle_); - perf_output_handle_ = nullptr; -} - -void* PerfJitLogger::OpenMarkerFile(int fd) { - long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int) - if (page_size == -1) return nullptr; - - // Mmap the file so that there is a mmap record in the perf_data file. - // - // The map must be PROT_EXEC to ensure it is not ignored by perf record. - void* marker_address = - mmap(nullptr, page_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0); - return (marker_address == MAP_FAILED) ? nullptr : marker_address; -} - -void PerfJitLogger::CloseMarkerFile(void* marker_address) { - if (marker_address == nullptr) return; - long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int) - if (page_size == -1) return; - munmap(marker_address, page_size); -} - -PerfJitLogger::PerfJitLogger(Isolate* isolate) : CodeEventLogger(isolate) { - base::LockGuard<base::RecursiveMutex> guard_file(file_mutex_.Pointer()); - - reference_count_++; - // If this is the first logger, open the file and write the header. - if (reference_count_ == 1) { - OpenJitDumpFile(); - if (perf_output_handle_ == nullptr) return; - LogWriteHeader(); - } -} - -PerfJitLogger::~PerfJitLogger() { - base::LockGuard<base::RecursiveMutex> guard_file(file_mutex_.Pointer()); - - reference_count_--; - // If this was the last logger, close the file. - if (reference_count_ == 0) { - CloseJitDumpFile(); - } -} - -uint64_t PerfJitLogger::GetTimestamp() { - struct timespec ts; - int result = clock_gettime(CLOCK_MONOTONIC, &ts); - DCHECK_EQ(0, result); - USE(result); - static const uint64_t kNsecPerSec = 1000000000; - return (ts.tv_sec * kNsecPerSec) + ts.tv_nsec; -} - -void PerfJitLogger::LogRecordedBuffer(AbstractCode abstract_code, - SharedFunctionInfo shared, - const char* name, int length) { - if (FLAG_perf_basic_prof_only_functions && - (abstract_code->kind() != AbstractCode::INTERPRETED_FUNCTION && - abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION)) { - return; - } - - base::LockGuard<base::RecursiveMutex> guard_file(file_mutex_.Pointer()); - - if (perf_output_handle_ == nullptr) return; - - // We only support non-interpreted functions. - if (!abstract_code->IsCode()) return; - Code code = abstract_code->GetCode(); - DCHECK(code->raw_instruction_start() == code->address() + Code::kHeaderSize); - - // Debug info has to be emitted first. - if (FLAG_perf_prof && !shared.is_null()) { - // TODO(herhut): This currently breaks for js2wasm/wasm2js functions. - if (code->kind() != Code::JS_TO_WASM_FUNCTION && - code->kind() != Code::WASM_TO_JS_FUNCTION) { - LogWriteDebugInfo(code, shared); - } - } - - const char* code_name = name; - uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->InstructionStart()); - - // Code generated by Turbofan will have the safepoint table directly after - // instructions. There is no need to record the safepoint table itself. - uint32_t code_size = code->ExecutableInstructionSize(); - - // Unwinding info comes right after debug info. - if (FLAG_perf_prof_unwinding_info) LogWriteUnwindingInfo(code); - - WriteJitCodeLoadEntry(code_pointer, code_size, code_name, length); -} - -void PerfJitLogger::LogRecordedBuffer(const wasm::WasmCode* code, - const char* name, int length) { - base::LockGuard<base::RecursiveMutex> guard_file(file_mutex_.Pointer()); - - if (perf_output_handle_ == nullptr) return; - - WriteJitCodeLoadEntry(code->instructions().start(), - code->instructions().length(), name, length); -} - -void PerfJitLogger::WriteJitCodeLoadEntry(const uint8_t* code_pointer, - uint32_t code_size, const char* name, - int name_length) { - static const char string_terminator[] = "\0"; - - PerfJitCodeLoad code_load; - code_load.event_ = PerfJitCodeLoad::kLoad; - code_load.size_ = sizeof(code_load) + name_length + 1 + code_size; - code_load.time_stamp_ = GetTimestamp(); - code_load.process_id_ = - static_cast<uint32_t>(base::OS::GetCurrentProcessId()); - code_load.thread_id_ = static_cast<uint32_t>(base::OS::GetCurrentThreadId()); - code_load.vma_ = reinterpret_cast<uint64_t>(code_pointer); - code_load.code_address_ = reinterpret_cast<uint64_t>(code_pointer); - code_load.code_size_ = code_size; - code_load.code_id_ = code_index_; - - code_index_++; - - LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load)); - LogWriteBytes(name, name_length); - LogWriteBytes(string_terminator, 1); - LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size); -} - -namespace { - -constexpr char kUnknownScriptNameString[] = "<unknown>"; -constexpr size_t kUnknownScriptNameStringLen = - arraysize(kUnknownScriptNameString) - 1; - -size_t GetScriptNameLength(const SourcePositionInfo& info) { - if (!info.script.is_null()) { - Object name_or_url = info.script->GetNameOrSourceURL(); - if (name_or_url->IsString()) { - String str = String::cast(name_or_url); - if (str->IsOneByteRepresentation()) return str->length(); - int length; - str->ToCString(DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length); - return static_cast<size_t>(length); - } - } - return kUnknownScriptNameStringLen; -} - -Vector<const char> GetScriptName(const SourcePositionInfo& info, - std::unique_ptr<char[]>* storage, - const DisallowHeapAllocation& no_gc) { - if (!info.script.is_null()) { - Object name_or_url = info.script->GetNameOrSourceURL(); - if (name_or_url->IsSeqOneByteString()) { - SeqOneByteString str = SeqOneByteString::cast(name_or_url); - return {reinterpret_cast<char*>(str->GetChars(no_gc)), - static_cast<size_t>(str->length())}; - } else if (name_or_url->IsString()) { - int length; - *storage = - String::cast(name_or_url) - ->ToCString(DISALLOW_NULLS, FAST_STRING_TRAVERSAL, &length); - return {storage->get(), static_cast<size_t>(length)}; - } - } - return {kUnknownScriptNameString, kUnknownScriptNameStringLen}; -} - -SourcePositionInfo GetSourcePositionInfo(Handle<Code> code, - Handle<SharedFunctionInfo> function, - SourcePosition pos) { - if (code->is_turbofanned()) { - DisallowHeapAllocation disallow; - return pos.InliningStack(code)[0]; - } else { - return SourcePositionInfo(pos, function); - } -} - -} // namespace - -void PerfJitLogger::LogWriteDebugInfo(Code code, SharedFunctionInfo shared) { - // Compute the entry count and get the name of the script. - uint32_t entry_count = 0; - for (SourcePositionTableIterator iterator(code->SourcePositionTable()); - !iterator.done(); iterator.Advance()) { - entry_count++; - } - if (entry_count == 0) return; - // The WasmToJS wrapper stubs have source position entries. - if (!shared->HasSourceCode()) return; - Isolate* isolate = shared->GetIsolate(); - Handle<Script> script(Script::cast(shared->script()), isolate); - - PerfJitCodeDebugInfo debug_info; - - debug_info.event_ = PerfJitCodeLoad::kDebugInfo; - debug_info.time_stamp_ = GetTimestamp(); - debug_info.address_ = code->InstructionStart(); - debug_info.entry_count_ = entry_count; - - uint32_t size = sizeof(debug_info); - // Add the sizes of fixed parts of entries. - size += entry_count * sizeof(PerfJitDebugEntry); - // Add the size of the name after each entry. - - Handle<Code> code_handle(code, isolate); - Handle<SharedFunctionInfo> function_handle(shared, isolate); - for (SourcePositionTableIterator iterator(code->SourcePositionTable()); - !iterator.done(); iterator.Advance()) { - SourcePositionInfo info(GetSourcePositionInfo(code_handle, function_handle, - iterator.source_position())); - size += GetScriptNameLength(info) + 1; - } - - int padding = ((size + 7) & (~7)) - size; - debug_info.size_ = size + padding; - LogWriteBytes(reinterpret_cast<const char*>(&debug_info), sizeof(debug_info)); - - Address code_start = code->InstructionStart(); - - for (SourcePositionTableIterator iterator(code->SourcePositionTable()); - !iterator.done(); iterator.Advance()) { - SourcePositionInfo info(GetSourcePositionInfo(code_handle, function_handle, - iterator.source_position())); - PerfJitDebugEntry entry; - // The entry point of the function will be placed straight after the ELF - // header when processed by "perf inject". Adjust the position addresses - // accordingly. - entry.address_ = code_start + iterator.code_offset() + kElfHeaderSize; - entry.line_number_ = info.line + 1; - entry.column_ = info.column + 1; - LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry)); - // The extracted name may point into heap-objects, thus disallow GC. - DisallowHeapAllocation no_gc; - std::unique_ptr<char[]> name_storage; - Vector<const char> name_string = GetScriptName(info, &name_storage, no_gc); - LogWriteBytes(name_string.start(), - static_cast<uint32_t>(name_string.size()) + 1); - } - char padding_bytes[8] = {0}; - LogWriteBytes(padding_bytes, padding); -} - -void PerfJitLogger::LogWriteUnwindingInfo(Code code) { - PerfJitCodeUnwindingInfo unwinding_info_header; - unwinding_info_header.event_ = PerfJitCodeLoad::kUnwindingInfo; - unwinding_info_header.time_stamp_ = GetTimestamp(); - unwinding_info_header.eh_frame_hdr_size_ = EhFrameConstants::kEhFrameHdrSize; - - if (code->has_unwinding_info()) { - unwinding_info_header.unwinding_size_ = code->unwinding_info_size(); - unwinding_info_header.mapped_size_ = unwinding_info_header.unwinding_size_; - } else { - unwinding_info_header.unwinding_size_ = EhFrameConstants::kEhFrameHdrSize; - unwinding_info_header.mapped_size_ = 0; - } - - int content_size = static_cast<int>(sizeof(unwinding_info_header) + - unwinding_info_header.unwinding_size_); - int padding_size = RoundUp(content_size, 8) - content_size; - unwinding_info_header.size_ = content_size + padding_size; - - LogWriteBytes(reinterpret_cast<const char*>(&unwinding_info_header), - sizeof(unwinding_info_header)); - - if (code->has_unwinding_info()) { - LogWriteBytes(reinterpret_cast<const char*>(code->unwinding_info_start()), - code->unwinding_info_size()); - } else { - OFStream perf_output_stream(perf_output_handle_); - EhFrameWriter::WriteEmptyEhFrame(perf_output_stream); - } - - char padding_bytes[] = "\0\0\0\0\0\0\0\0"; - DCHECK_LT(padding_size, static_cast<int>(sizeof(padding_bytes))); - LogWriteBytes(padding_bytes, static_cast<int>(padding_size)); -} - -void PerfJitLogger::CodeMoveEvent(AbstractCode from, AbstractCode to) { - // We may receive a CodeMove event if a BytecodeArray object moves. Otherwise - // code relocation is not supported. - CHECK(from->IsBytecodeArray()); -} - -void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { - size_t rv = fwrite(bytes, 1, size, perf_output_handle_); - DCHECK(static_cast<size_t>(size) == rv); - USE(rv); -} - -void PerfJitLogger::LogWriteHeader() { - DCHECK_NOT_NULL(perf_output_handle_); - PerfJitHeader header; - - header.magic_ = PerfJitHeader::kMagic; - header.version_ = PerfJitHeader::kVersion; - header.size_ = sizeof(header); - header.elf_mach_target_ = GetElfMach(); - header.reserved_ = 0xDEADBEEF; - header.process_id_ = base::OS::GetCurrentProcessId(); - header.time_stamp_ = - static_cast<uint64_t>(V8::GetCurrentPlatform()->CurrentClockTimeMillis() * - base::Time::kMicrosecondsPerMillisecond); - header.flags_ = 0; - - LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header)); -} - -#endif // V8_OS_LINUX -} // namespace internal -} // namespace v8 |