From: jarin@chromium.org Date: Tue, 1 Jul 2014 12:20:21 +0000 (+0000) Subject: Reland "Linux perf tool support update + refactoring." X-Git-Tag: upstream/4.7.83~8453 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2b7580c2d487aee5a8739e830c3f18002af0197b;p=platform%2Fupstream%2Fv8.git Reland "Linux perf tool support update + refactoring." This relands r22098. BUG= R=yangguo@chromium.org Review URL: https://codereview.chromium.org/368433006 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22118 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/BUILD.gn b/BUILD.gn index 18e5ef2..1bdd52a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -678,6 +678,8 @@ source_set("v8_base") { "src/ostreams.h", "src/parser.cc", "src/parser.h", + "src/perf-jit.cc", + "src/perf-jit.h", "src/preparse-data-format.h", "src/preparse-data.cc", "src/preparse-data.h", diff --git a/build/android.gypi b/build/android.gypi index 098109e..5355646 100644 --- a/build/android.gypi +++ b/build/android.gypi @@ -280,6 +280,9 @@ '-Wl,-O1', '-Wl,--as-needed', ], + 'libraries': [ + '-lrt', + ], }], ], # target_conditions }, # target_defaults diff --git a/src/base/platform/platform-posix.cc b/src/base/platform/platform-posix.cc index 8454213..b49e7bf 100644 --- a/src/base/platform/platform-posix.cc +++ b/src/base/platform/platform-posix.cc @@ -20,9 +20,9 @@ #include #include #include +#include #include #include - #if defined(__linux__) #include // NOLINT, for prctl #endif @@ -318,6 +318,15 @@ int OS::GetCurrentProcessId() { } +int OS::GetCurrentThreadId() { +#if defined(ANDROID) + return static_cast(syscall(__NR_gettid)); +#else + return static_cast(syscall(SYS_gettid)); +#endif // defined(ANDROID) +} + + // ---------------------------------------------------------------------------- // POSIX date/time support. // diff --git a/src/base/platform/platform-win32.cc b/src/base/platform/platform-win32.cc index b4f934e..4b4f2be 100644 --- a/src/base/platform/platform-win32.cc +++ b/src/base/platform/platform-win32.cc @@ -517,6 +517,11 @@ int OS::GetCurrentProcessId() { } +int OS::GetCurrentThreadId() { + return static_cast(::GetCurrentThreadId()); +} + + // ---------------------------------------------------------------------------- // Win32 console output. // diff --git a/src/base/platform/platform.h b/src/base/platform/platform.h index b00581e..052e468 100644 --- a/src/base/platform/platform.h +++ b/src/base/platform/platform.h @@ -307,6 +307,8 @@ class OS { static int GetCurrentProcessId(); + static int GetCurrentThreadId(); + private: static const int msPerSecond = 1000; diff --git a/src/flag-definitions.h b/src/flag-definitions.h index d7341e6..9e617a3 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -786,8 +786,10 @@ DEFINE_bool(logfile_per_isolate, true, "Separate log files for each isolate.") DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.") DEFINE_bool(perf_basic_prof, false, "Enable perf linux profiler (basic support).") +DEFINE_neg_implication(perf_basic_prof, compact_code_space) DEFINE_bool(perf_jit_prof, false, "Enable perf linux profiler (experimental annotate support).") +DEFINE_neg_implication(perf_jit_prof, compact_code_space) DEFINE_string(gc_fake_mmap, "/tmp/__v8_gc__", "Specify the name of the file for fake gc mmap used in ll_prof") DEFINE_bool(log_internal_timer_events, false, "Time internal events.") diff --git a/src/isolate.cc b/src/isolate.cc index 1592667..70353ee 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -1954,12 +1954,6 @@ bool Isolate::Init(Deserializer* des) { LOG(this, LogCompiledFunctions()); } - // If we are profiling with the Linux perf tool, we need to disable - // code relocation. - if (FLAG_perf_jit_prof || FLAG_perf_basic_prof) { - FLAG_compact_code_space = false; - } - CHECK_EQ(static_cast(OFFSET_OF(Isolate, embedder_data_)), Internals::kIsolateEmbedderDataOffset); CHECK_EQ(static_cast(OFFSET_OF(Isolate, heap_.roots_)), diff --git a/src/log.cc b/src/log.cc index 6d88a53..b410ab8 100644 --- a/src/log.cc +++ b/src/log.cc @@ -15,6 +15,7 @@ #include "src/log.h" #include "src/log-utils.h" #include "src/macro-assembler.h" +#include "src/perf-jit.h" #include "src/runtime-profiler.h" #include "src/serialize.h" #include "src/string-stream.h" @@ -289,172 +290,6 @@ void PerfBasicLogger::LogRecordedBuffer(Code* code, } -// Linux perf tool logging support -class PerfJitLogger : public CodeEventLogger { - public: - PerfJitLogger(); - virtual ~PerfJitLogger(); - - virtual void CodeMoveEvent(Address from, Address to) { } - virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } - virtual void CodeDeleteEvent(Address from) { } - - private: - virtual void LogRecordedBuffer(Code* code, - SharedFunctionInfo* shared, - const char* name, - int length); - - // Extension added to V8 log file name to get the low-level log name. - static const char kFilenameFormatString[]; - static const int kFilenameBufferPadding; - - // File buffer size of the low-level log. We don't use the default to - // minimize the associated overhead. - static const int kLogBufferSize = 2 * MB; - - void LogWriteBytes(const char* bytes, int size); - void LogWriteHeader(); - - static const uint32_t kJitHeaderMagic = 0x4F74496A; - static const uint32_t kJitHeaderVersion = 0x2; - static const uint32_t kElfMachIA32 = 3; - static const uint32_t kElfMachX64 = 62; - static const uint32_t kElfMachARM = 40; - static const uint32_t kElfMachMIPS = 10; - static const uint32_t kElfMachX87 = 3; - - struct jitheader { - uint32_t magic; - uint32_t version; - uint32_t total_size; - uint32_t elf_mach; - uint32_t pad1; - uint32_t pid; - uint64_t timestamp; - }; - - enum jit_record_type { - JIT_CODE_LOAD = 0 - // JIT_CODE_UNLOAD = 1, - // JIT_CODE_CLOSE = 2, - // JIT_CODE_DEBUG_INFO = 3, - // JIT_CODE_PAGE_MAP = 4, - // JIT_CODE_MAX = 5 - }; - - struct jr_code_load { - uint32_t id; - uint32_t total_size; - uint64_t timestamp; - uint64_t vma; - uint64_t code_addr; - uint32_t code_size; - uint32_t align; - }; - - uint32_t GetElfMach() { -#if V8_TARGET_ARCH_IA32 - return kElfMachIA32; -#elif V8_TARGET_ARCH_X64 - return kElfMachX64; -#elif V8_TARGET_ARCH_ARM - return kElfMachARM; -#elif V8_TARGET_ARCH_MIPS - return kElfMachMIPS; -#elif V8_TARGET_ARCH_X87 - return kElfMachX87; -#else - UNIMPLEMENTED(); - return 0; -#endif - } - - FILE* perf_output_handle_; -}; - -const char PerfJitLogger::kFilenameFormatString[] = "/tmp/jit-%d.dump"; - -// Extra padding for the PID in the filename -const int PerfJitLogger::kFilenameBufferPadding = 16; - -PerfJitLogger::PerfJitLogger() - : perf_output_handle_(NULL) { - // Open the perf JIT dump file. - int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; - ScopedVector perf_dump_name(bufferSize); - int size = SNPrintF( - perf_dump_name, - kFilenameFormatString, - base::OS::GetCurrentProcessId()); - CHECK_NE(size, -1); - perf_output_handle_ = - base::OS::FOpen(perf_dump_name.start(), base::OS::LogFileOpenMode); - CHECK_NE(perf_output_handle_, NULL); - setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); - - LogWriteHeader(); -} - - -PerfJitLogger::~PerfJitLogger() { - fclose(perf_output_handle_); - perf_output_handle_ = NULL; -} - - -void PerfJitLogger::LogRecordedBuffer(Code* code, - SharedFunctionInfo*, - const char* name, - int length) { - ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); - ASSERT(perf_output_handle_ != NULL); - - const char* code_name = name; - uint8_t* code_pointer = reinterpret_cast(code->instruction_start()); - uint32_t code_size = code->instruction_size(); - - static const char string_terminator[] = "\0"; - - jr_code_load code_load; - code_load.id = JIT_CODE_LOAD; - code_load.total_size = sizeof(code_load) + length + 1 + code_size; - code_load.timestamp = - static_cast(base::OS::TimeCurrentMillis() * 1000.0); - code_load.vma = 0x0; // Our addresses are absolute. - code_load.code_addr = reinterpret_cast(code->instruction_start()); - code_load.code_size = code_size; - code_load.align = 0; - - LogWriteBytes(reinterpret_cast(&code_load), sizeof(code_load)); - LogWriteBytes(code_name, length); - LogWriteBytes(string_terminator, 1); - LogWriteBytes(reinterpret_cast(code_pointer), code_size); -} - - -void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { - size_t rv = fwrite(bytes, 1, size, perf_output_handle_); - ASSERT(static_cast(size) == rv); - USE(rv); -} - - -void PerfJitLogger::LogWriteHeader() { - ASSERT(perf_output_handle_ != NULL); - jitheader header; - header.magic = kJitHeaderMagic; - header.version = kJitHeaderVersion; - header.total_size = sizeof(jitheader); - header.pad1 = 0xdeadbeef; - header.elf_mach = GetElfMach(); - header.pid = base::OS::GetCurrentProcessId(); - header.timestamp = - static_cast(base::OS::TimeCurrentMillis() * 1000.0); - LogWriteBytes(reinterpret_cast(&header), sizeof(header)); -} - - // Low-level logging support. #define LL_LOG(Call) if (ll_logger_) ll_logger_->Call; diff --git a/src/perf-jit.cc b/src/perf-jit.cc new file mode 100644 index 0000000..4ed36d1 --- /dev/null +++ b/src/perf-jit.cc @@ -0,0 +1,169 @@ +// Copyright 2014 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. + +#ifdef __linux__ +#include +#include "src/third_party/kernel/tools/perf/util/jitdump.h" +#endif + +#include "src/perf-jit.h" + + +namespace v8 { +namespace internal { + +#ifdef __linux__ + +const char PerfJitLogger::kFilenameFormatString[] = "perfjit-%d.dump"; + +// Timestamp module name +const char PerfJitLogger::kTraceClockDevice[] = "/dev/trace_clock"; + +// Extra padding for the PID in the filename +const int PerfJitLogger::kFilenameBufferPadding = 16; + + +static clockid_t get_clockid(int fd) { + return ((~(clockid_t) (fd) << 3) | 3); +} + + +PerfJitLogger::PerfJitLogger() + : perf_output_handle_(NULL), + code_index_(0) { + // Open the perf JIT dump file. + int bufferSize = sizeof(kFilenameFormatString) + kFilenameBufferPadding; + ScopedVector perf_dump_name(bufferSize); + int size = SNPrintF( + perf_dump_name, + kFilenameFormatString, + base::OS::GetCurrentProcessId()); + CHECK_NE(size, -1); + perf_output_handle_ = base::OS::FOpen(perf_dump_name.start(), + base::OS::LogFileOpenMode); + CHECK_NE(perf_output_handle_, NULL); + setvbuf(perf_output_handle_, NULL, _IOFBF, kLogBufferSize); + clock_fd_ = open(kTraceClockDevice, O_RDONLY); + if (clock_fd_ == -1) { + FATAL("Could not get perf timestamp clock"); + } + clock_id_ = get_clockid(clock_fd_); + if (kClockInvalid == clock_id_) { + FATAL("Could not get perf timestamp clock"); + } + + LogWriteHeader(); +} + + +PerfJitLogger::~PerfJitLogger() { + fclose(perf_output_handle_); + close(clock_fd_); + perf_output_handle_ = NULL; +} + + +uint64_t PerfJitLogger::GetTimestamp() { + struct timespec ts; + + clock_gettime(clock_id_, &ts); + return ((uint64_t) ts.tv_sec * kNsecPerSec) + ts.tv_nsec; +} + + +void PerfJitLogger::LogRecordedBuffer(Code* code, + SharedFunctionInfo*, + const char* name, + int length) { + ASSERT(code->instruction_start() == code->address() + Code::kHeaderSize); + ASSERT(perf_output_handle_ != NULL); + + const char* code_name = name; + uint8_t* code_pointer = reinterpret_cast(code->instruction_start()); + uint32_t code_size = code->instruction_size(); + + static const char string_terminator[] = "\0"; + + jr_code_load code_load; + code_load.p.id = JIT_CODE_LOAD; + code_load.p.total_size = sizeof(code_load) + length + 1 + code_size; + code_load.p.timestamp = GetTimestamp(); + code_load.pid = static_cast(base::OS::GetCurrentProcessId()); + code_load.tid = static_cast(base::OS::GetCurrentThreadId()); + code_load.vma = 0x0; // Our addresses are absolute. + code_load.code_addr = reinterpret_cast(code_pointer); + code_load.code_size = code_size; + code_load.code_index = code_index_; + + code_index_++; + + LogWriteBytes(reinterpret_cast(&code_load), sizeof(code_load)); + LogWriteBytes(code_name, length); + LogWriteBytes(string_terminator, 1); + LogWriteBytes(reinterpret_cast(code_pointer), code_size); +} + + +void PerfJitLogger::CodeMoveEvent(Address from, Address to) { + // Code relocation not supported. + UNREACHABLE(); +} + + +void PerfJitLogger::CodeDeleteEvent(Address from) { + // V8 does not send notification on code unload +} + + +void PerfJitLogger::SnapshotPositionEvent(Address addr, int pos) { +} + + +void PerfJitLogger::LogWriteBytes(const char* bytes, int size) { + size_t rv = fwrite(bytes, 1, size, perf_output_handle_); + ASSERT(static_cast(size) == rv); + USE(rv); +} + + +void PerfJitLogger::LogWriteHeader() { + ASSERT(perf_output_handle_ != NULL); + jitheader header; + header.magic = JITHEADER_MAGIC; + header.version = JITHEADER_VERSION; + header.total_size = sizeof(jitheader); + header.pad1 = 0xdeadbeef; + header.elf_mach = GetElfMach(); + header.pid = base::OS::GetCurrentProcessId(); + header.timestamp = + static_cast(base::OS::TimeCurrentMillis() * 1000.0); + LogWriteBytes(reinterpret_cast(&header), sizeof(header)); +} + +#endif // defined(__linux__) + +} } // namespace v8::internal diff --git a/src/perf-jit.h b/src/perf-jit.h new file mode 100644 index 0000000..b0d1e84 --- /dev/null +++ b/src/perf-jit.h @@ -0,0 +1,129 @@ +// Copyright 2014 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. + +#ifndef V8_PERF_JIT_H_ +#define V8_PERF_JIT_H_ + +#include "src/v8.h" + +namespace v8 { +namespace internal { + +#ifdef __linux__ + +// Linux perf tool logging support +class PerfJitLogger : public CodeEventLogger { + public: + PerfJitLogger(); + virtual ~PerfJitLogger(); + + virtual void CodeMoveEvent(Address from, Address to); + virtual void CodeDeleteEvent(Address from); + virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { } + virtual void SnapshotPositionEvent(Address addr, int pos); + + private: + uint64_t GetTimestamp(); + virtual void LogRecordedBuffer(Code* code, + SharedFunctionInfo* shared, + const char* name, + int length); + + // Extension added to V8 log file name to get the low-level log name. + static const char kFilenameFormatString[]; + static const int kFilenameBufferPadding; + + static const char kTraceClockDevice[]; + static const int kClockInvalid = -1; + static const uint64_t kNsecPerSec = 1000000000; + + // File buffer size of the low-level log. We don't use the default to + // minimize the associated overhead. + static const int kLogBufferSize = 2 * MB; + + void LogWriteBytes(const char* bytes, int size); + void LogWriteHeader(); + + static const uint32_t kElfMachIA32 = 3; + static const uint32_t kElfMachX64 = 62; + static const uint32_t kElfMachARM = 40; + static const uint32_t kElfMachMIPS = 10; + + uint32_t GetElfMach() { +#if V8_TARGET_ARCH_IA32 + return kElfMachIA32; +#elif V8_TARGET_ARCH_X64 + return kElfMachX64; +#elif V8_TARGET_ARCH_ARM + return kElfMachARM; +#elif V8_TARGET_ARCH_MIPS + return kElfMachMIPS; +#else + UNIMPLEMENTED(); + return 0; +#endif + } + + FILE* perf_output_handle_; + int clock_fd_; + int clock_id_; + uint64_t code_index_; +}; + +#else + +// PerfJitLogger is only implemented on Linux +class PerfJitLogger : public CodeEventLogger { + public: + virtual void CodeMoveEvent(Address from, Address to) { + UNIMPLEMENTED(); + } + + virtual void CodeDeleteEvent(Address from) { + UNIMPLEMENTED(); + } + + virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) { + UNIMPLEMENTED(); + } + + virtual void SnapshotPositionEvent(Address addr, int pos) { + UNIMPLEMENTED(); + } + + virtual void LogRecordedBuffer(Code* code, + SharedFunctionInfo* shared, + const char* name, + int length) { + UNIMPLEMENTED(); + } +}; + +#endif // defined(__linux__) + +} } // namespace v8::internal +#endif diff --git a/src/third_party/kernel/tools/perf/util/jitdump.h b/src/third_party/kernel/tools/perf/util/jitdump.h new file mode 100644 index 0000000..1b82fc2 --- /dev/null +++ b/src/third_party/kernel/tools/perf/util/jitdump.h @@ -0,0 +1,85 @@ +#ifndef JITDUMP_H +#define JITDUMP_H + +#include +#include +#include + +/* JiTD */ +#define JITHEADER_MAGIC 0x4A695444 +#define JITHEADER_MAGIC_SW 0x4454694A + +#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7) + +#define JITHEADER_VERSION 1 + +struct jitheader { + uint32_t magic; /* characters "jItD" */ + uint32_t version; /* header version */ + uint32_t total_size; /* total size of header */ + uint32_t elf_mach; /* elf mach target */ + uint32_t pad1; /* reserved */ + uint32_t pid; /* JIT process id */ + uint64_t timestamp; /* timestamp */ +}; + +enum jit_record_type { + JIT_CODE_LOAD = 0, + JIT_CODE_MOVE = 1, + JIT_CODE_DEBUG_INFO = 2, + JIT_CODE_CLOSE = 3, + + JIT_CODE_MAX +}; + +/* record prefix (mandatory in each record) */ +struct jr_prefix { + uint32_t id; + uint32_t total_size; + uint64_t timestamp; +}; + +struct jr_code_load { + struct jr_prefix p; + + uint32_t pid; + uint32_t tid; + uint64_t vma; + uint64_t code_addr; + uint64_t code_size; + uint64_t code_index; +}; + +struct jr_code_close { + struct jr_prefix p; +}; + +struct jr_code_move { + struct jr_prefix p; + + uint32_t pid; + uint32_t tid; + uint64_t vma; + uint64_t old_code_addr; + uint64_t new_code_addr; + uint64_t code_size; + uint64_t code_index; +}; + +struct jr_code_debug_info { + struct jr_prefix p; + + uint64_t code_addr; + uint64_t nr_entry; +}; + +union jr_entry { + struct jr_code_debug_info info; + struct jr_code_close close; + struct jr_code_load load; + struct jr_code_move move; + struct jr_prefix prefix; +}; + +#endif /* !JITDUMP_H */ + diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index c455c1f..f907a16 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -577,6 +577,8 @@ '../../src/ostreams.h', '../../src/parser.cc', '../../src/parser.h', + '../../src/perf-jit.cc', + '../../src/perf-jit.h', '../../src/preparse-data-format.h', '../../src/preparse-data.cc', '../../src/preparse-data.h',