summaryrefslogtreecommitdiff
path: root/deps/v8/src/perf-jit.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/perf-jit.cc')
-rw-r--r--deps/v8/src/perf-jit.cc457
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