electron/patches/v8/enable_--perf-prof_flag_on_macos.patch
Aman Karmani 3d4a4b9343
feat: add support for --js-flags=--perf-prof on macOS (#46876)
* feat: add support for `--js-flags=--perf-prof` on macOS

allows for profiling of macOS electron apps using samply[1],
which can capture cpu usage for an entire process tree, including
both c/c++ frames and interpreted + jit-compiled JS stack frames

[1] https://github.com/mstange/samply

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2025-05-01 09:46:10 -05:00

465 lines
18 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: yangwenming <yangwenming@bytedance.com>
Date: Wed, 23 Apr 2025 22:14:00 +0800
Subject: Enable --perf-prof flag on MacOS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
MacOS actually can share the implementation of {PerfJitLogger} with
Linux. From the issue 40112126, only Fuzzer tests on Windows ran
into UNREACHABLE/FATAL because of the unimplemented {PerfJitLogger}.
This CL enables the flag --perf-prof on MacOS.
Bug: 403765219
Change-Id: I97871fbcc0cb9890c51ca14fd7a6e65bd0e3c0d2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6385655
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
Auto-Submit: 杨文明 <yangwenming@bytedance.com>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/main@{#99885}
diff --git a/src/compiler/backend/code-generator.cc b/src/compiler/backend/code-generator.cc
index 023cee8098e232b67acbed311c899732854cc01f..ad557facb9d46814273a67136878c9fbdfe6197e 100644
--- a/src/compiler/backend/code-generator.cc
+++ b/src/compiler/backend/code-generator.cc
@@ -435,7 +435,7 @@ void CodeGenerator::AssembleCode() {
}
}
- // The LinuxPerfJitLogger logs code up until here, excluding the safepoint
+ // The PerfJitLogger logs code up until here, excluding the safepoint
// table. Resolve the unwinding info now so it is aware of the same code
// size as reported by perf.
unwinding_info_writer_.Finish(masm()->pc_offset());
diff --git a/src/diagnostics/perf-jit.cc b/src/diagnostics/perf-jit.cc
index 6af13fe8cf29c4ab10fab2107d10de7df8722f10..c509e4220c8e164594665afdea97cc75f13da05c 100644
--- a/src/diagnostics/perf-jit.cc
+++ b/src/diagnostics/perf-jit.cc
@@ -30,8 +30,8 @@
#include "src/common/assert-scope.h"
#include "src/flags/flags.h"
-// Only compile the {LinuxPerfJitLogger} on Linux.
-#if V8_OS_LINUX
+// Only compile the {PerfJitLogger} on Linux & Darwin.
+#if V8_OS_LINUX || V8_OS_DARWIN
#include <fcntl.h>
#include <sys/mman.h>
@@ -118,22 +118,22 @@ struct PerfJitCodeUnwindingInfo : PerfJitBase {
// Followed by size_ - sizeof(PerfJitCodeUnwindingInfo) bytes of data.
};
-const char LinuxPerfJitLogger::kFilenameFormatString[] = "%s/jit-%d.dump";
+const char PerfJitLogger::kFilenameFormatString[] = "%s/jit-%d.dump";
// Extra padding for the PID in the filename
-const int LinuxPerfJitLogger::kFilenameBufferPadding = 16;
+const int PerfJitLogger::kFilenameBufferPadding = 16;
static const char kStringTerminator[] = {'\0'};
// The following static variables are protected by
// GetFileMutex().
-int LinuxPerfJitLogger::process_id_ = 0;
-uint64_t LinuxPerfJitLogger::reference_count_ = 0;
-void* LinuxPerfJitLogger::marker_address_ = nullptr;
-uint64_t LinuxPerfJitLogger::code_index_ = 0;
-FILE* LinuxPerfJitLogger::perf_output_handle_ = nullptr;
+int PerfJitLogger::process_id_ = 0;
+uint64_t PerfJitLogger::reference_count_ = 0;
+void* PerfJitLogger::marker_address_ = nullptr;
+uint64_t PerfJitLogger::code_index_ = 0;
+FILE* PerfJitLogger::perf_output_handle_ = nullptr;
-void LinuxPerfJitLogger::OpenJitDumpFile() {
+void PerfJitLogger::OpenJitDumpFile() {
// Open the perf JIT dump file.
perf_output_handle_ = nullptr;
@@ -153,8 +153,17 @@ void LinuxPerfJitLogger::OpenJitDumpFile() {
if (v8_flags.perf_prof_delete_file)
CHECK_EQ(0, unlink(perf_dump_name.begin()));
+ // On Linux, call OpenMarkerFile so that perf knows about the file path via
+ // an MMAP record.
+ // On macOS, don't call OpenMarkerFile because samply has already detected
+ // the file path during the call to `open` above (it interposes `open` with
+ // a preloaded library), and because the mmap call can be slow.
+#if V8_OS_DARWIN
+ marker_address_ = nullptr;
+#else
marker_address_ = OpenMarkerFile(fd);
if (marker_address_ == nullptr) return;
+#endif
perf_output_handle_ = fdopen(fd, "w+");
if (perf_output_handle_ == nullptr) return;
@@ -162,13 +171,13 @@ void LinuxPerfJitLogger::OpenJitDumpFile() {
setvbuf(perf_output_handle_, nullptr, _IOFBF, kLogBufferSize);
}
-void LinuxPerfJitLogger::CloseJitDumpFile() {
+void PerfJitLogger::CloseJitDumpFile() {
if (perf_output_handle_ == nullptr) return;
base::Fclose(perf_output_handle_);
perf_output_handle_ = nullptr;
}
-void* LinuxPerfJitLogger::OpenMarkerFile(int fd) {
+void* PerfJitLogger::OpenMarkerFile(int fd) {
long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int)
if (page_size == -1) return nullptr;
@@ -180,15 +189,14 @@ void* LinuxPerfJitLogger::OpenMarkerFile(int fd) {
return (marker_address == MAP_FAILED) ? nullptr : marker_address;
}
-void LinuxPerfJitLogger::CloseMarkerFile(void* 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);
}
-LinuxPerfJitLogger::LinuxPerfJitLogger(Isolate* isolate)
- : CodeEventLogger(isolate) {
+PerfJitLogger::PerfJitLogger(Isolate* isolate) : CodeEventLogger(isolate) {
base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
process_id_ = base::OS::GetCurrentProcessId();
@@ -201,7 +209,7 @@ LinuxPerfJitLogger::LinuxPerfJitLogger(Isolate* isolate)
}
}
-LinuxPerfJitLogger::~LinuxPerfJitLogger() {
+PerfJitLogger::~PerfJitLogger() {
base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
reference_count_--;
@@ -211,16 +219,11 @@ LinuxPerfJitLogger::~LinuxPerfJitLogger() {
}
}
-uint64_t LinuxPerfJitLogger::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;
+uint64_t PerfJitLogger::GetTimestamp() {
+ return base::TimeTicks::Now().since_origin().InNanoseconds();
}
-void LinuxPerfJitLogger::LogRecordedBuffer(
+void PerfJitLogger::LogRecordedBuffer(
Tagged<AbstractCode> abstract_code,
MaybeDirectHandle<SharedFunctionInfo> maybe_sfi, const char* name,
size_t length) {
@@ -264,8 +267,8 @@ void LinuxPerfJitLogger::LogRecordedBuffer(
}
#if V8_ENABLE_WEBASSEMBLY
-void LinuxPerfJitLogger::LogRecordedBuffer(const wasm::WasmCode* code,
- const char* name, size_t length) {
+void PerfJitLogger::LogRecordedBuffer(const wasm::WasmCode* code,
+ const char* name, size_t length) {
base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
if (perf_output_handle_ == nullptr) return;
@@ -277,10 +280,9 @@ void LinuxPerfJitLogger::LogRecordedBuffer(const wasm::WasmCode* code,
}
#endif // V8_ENABLE_WEBASSEMBLY
-void LinuxPerfJitLogger::WriteJitCodeLoadEntry(const uint8_t* code_pointer,
- uint32_t code_size,
- const char* name,
- size_t name_length) {
+void PerfJitLogger::WriteJitCodeLoadEntry(const uint8_t* code_pointer,
+ uint32_t code_size, const char* name,
+ size_t name_length) {
PerfJitCodeLoad code_load;
code_load.event_ = PerfJitCodeLoad::kLoad;
code_load.size_ =
@@ -342,8 +344,8 @@ SourcePositionInfo GetSourcePositionInfo(
} // namespace
-void LinuxPerfJitLogger::LogWriteDebugInfo(
- Tagged<Code> code, DirectHandle<SharedFunctionInfo> shared) {
+void PerfJitLogger::LogWriteDebugInfo(Tagged<Code> code,
+ DirectHandle<SharedFunctionInfo> shared) {
// Line ends of all scripts have been initialized prior to this.
DisallowGarbageCollection no_gc;
// The WasmToJS wrapper stubs have source position entries.
@@ -425,7 +427,7 @@ void LinuxPerfJitLogger::LogWriteDebugInfo(
}
#if V8_ENABLE_WEBASSEMBLY
-void LinuxPerfJitLogger::LogWriteDebugInfo(const wasm::WasmCode* code) {
+void PerfJitLogger::LogWriteDebugInfo(const wasm::WasmCode* code) {
if (code->IsAnonymous()) {
return;
}
@@ -497,7 +499,7 @@ void LinuxPerfJitLogger::LogWriteDebugInfo(const wasm::WasmCode* code) {
}
#endif // V8_ENABLE_WEBASSEMBLY
-void LinuxPerfJitLogger::LogWriteUnwindingInfo(Tagged<Code> code) {
+void PerfJitLogger::LogWriteUnwindingInfo(Tagged<Code> code) {
PerfJitCodeUnwindingInfo unwinding_info_header;
unwinding_info_header.event_ = PerfJitCodeLoad::kUnwindingInfo;
unwinding_info_header.time_stamp_ = GetTimestamp();
@@ -532,13 +534,13 @@ void LinuxPerfJitLogger::LogWriteUnwindingInfo(Tagged<Code> code) {
LogWriteBytes(padding_bytes, padding_size);
}
-void LinuxPerfJitLogger::LogWriteBytes(const char* bytes, size_t size) {
+void PerfJitLogger::LogWriteBytes(const char* bytes, size_t size) {
size_t rv = fwrite(bytes, 1, size, perf_output_handle_);
DCHECK_EQ(size, rv);
USE(rv);
}
-void LinuxPerfJitLogger::LogWriteHeader() {
+void PerfJitLogger::LogWriteHeader() {
DCHECK_NOT_NULL(perf_output_handle_);
PerfJitHeader header;
@@ -559,4 +561,4 @@ void LinuxPerfJitLogger::LogWriteHeader() {
} // namespace internal
} // namespace v8
-#endif // V8_OS_LINUX
+#endif // V8_OS_LINUX || V8_OS_DARWIN
diff --git a/src/diagnostics/perf-jit.h b/src/diagnostics/perf-jit.h
index 84f669ca3f98690264e1ee05bfe6842c47bbcbd0..e95c3bb6fe0f445904df9dff3e6fe35735cd7045 100644
--- a/src/diagnostics/perf-jit.h
+++ b/src/diagnostics/perf-jit.h
@@ -30,8 +30,8 @@
#include "include/v8config.h"
-// {LinuxPerfJitLogger} is only implemented on Linux.
-#if V8_OS_LINUX
+// {PerfJitLogger} is only implemented on Linux & Darwin.
+#if V8_OS_LINUX || V8_OS_DARWIN
#include "src/logging/log.h"
@@ -39,10 +39,10 @@ namespace v8 {
namespace internal {
// Linux perf tool logging support.
-class LinuxPerfJitLogger : public CodeEventLogger {
+class PerfJitLogger : public CodeEventLogger {
public:
- explicit LinuxPerfJitLogger(Isolate* isolate);
- ~LinuxPerfJitLogger() override;
+ explicit PerfJitLogger(Isolate* isolate);
+ ~PerfJitLogger() override;
void CodeMoveEvent(Tagged<InstructionStream> from,
Tagged<InstructionStream> to) override {
@@ -143,6 +143,6 @@ class LinuxPerfJitLogger : public CodeEventLogger {
} // namespace internal
} // namespace v8
-#endif // V8_OS_LINUX
+#endif // V8_OS_LINUX || V8_OS_DARWIN
#endif // V8_DIAGNOSTICS_PERF_JIT_H_
diff --git a/src/flags/flag-definitions.h b/src/flags/flag-definitions.h
index dd713090c674585c23f9b9574df7ed258c0cd23e..8c12e97c4e256fb8bc6ef51c7abd6a926df7b008 100644
--- a/src/flags/flag-definitions.h
+++ b/src/flags/flag-definitions.h
@@ -3262,7 +3262,7 @@ DEFINE_IMPLICATION(prof, log_code)
DEFINE_BOOL(ll_prof, false, "Enable low-level linux profiler.")
-#if V8_OS_LINUX
+#if V8_OS_LINUX || V8_OS_DARWIN
#define DEFINE_PERF_PROF_BOOL(nam, cmt) DEFINE_BOOL(nam, false, cmt)
#define DEFINE_PERF_PROF_IMPLICATION DEFINE_IMPLICATION
#else
@@ -3279,7 +3279,7 @@ DEFINE_BOOL(ll_prof, false, "Enable low-level linux profiler.")
#endif
DEFINE_PERF_PROF_BOOL(perf_basic_prof,
- "Enable perf linux profiler (basic support).")
+ "Enable basic support for perf profiler.")
DEFINE_NEG_IMPLICATION(perf_basic_prof, compact_code_space)
DEFINE_STRING(perf_basic_prof_path, DEFAULT_PERF_BASIC_PROF_PATH,
"directory to write perf-<pid>.map symbol file to")
@@ -3288,8 +3288,8 @@ DEFINE_PERF_PROF_BOOL(
"Only report function code ranges to perf (i.e. no stubs).")
DEFINE_PERF_PROF_IMPLICATION(perf_basic_prof_only_functions, perf_basic_prof)
-DEFINE_PERF_PROF_BOOL(
- perf_prof, "Enable perf linux profiler (experimental annotate support).")
+DEFINE_PERF_PROF_BOOL(perf_prof,
+ "Enable experimental annotate support for perf profiler.")
DEFINE_STRING(perf_prof_path, DEFAULT_PERF_PROF_PATH,
"directory to write jit-<pid>.dump symbol file to")
DEFINE_PERF_PROF_BOOL(
diff --git a/src/logging/log.cc b/src/logging/log.cc
index ea07e176391b027287f007dadd44e64db8f62c3d..fe4096d4dadcc314274d2892c6ba1ed25b426b29 100644
--- a/src/logging/log.cc
+++ b/src/logging/log.cc
@@ -350,12 +350,12 @@ void CodeEventLogger::RegExpCodeCreateEvent(DirectHandle<AbstractCode> code,
name_buffer_->get(), name_buffer_->size());
}
-// Linux perf tool logging support.
-#if V8_OS_LINUX
-class LinuxPerfBasicLogger : public CodeEventLogger {
+// Linux & Darwin perf tool logging support.
+#if V8_OS_LINUX || V8_OS_DARWIN
+class PerfBasicLogger : public CodeEventLogger {
public:
- explicit LinuxPerfBasicLogger(Isolate* isolate);
- ~LinuxPerfBasicLogger() override;
+ explicit PerfBasicLogger(Isolate* isolate);
+ ~PerfBasicLogger() override;
void CodeMoveEvent(Tagged<InstructionStream> from,
Tagged<InstructionStream> to) override {}
@@ -388,21 +388,20 @@ class LinuxPerfBasicLogger : public CodeEventLogger {
};
// Extra space for the "perf-%d.map" filename, including the PID.
-const int LinuxPerfBasicLogger::kFilenameBufferPadding = 32;
+const int PerfBasicLogger::kFilenameBufferPadding = 32;
// static
-base::LazyRecursiveMutex& LinuxPerfBasicLogger::GetFileMutex() {
+base::LazyRecursiveMutex& PerfBasicLogger::GetFileMutex() {
static base::LazyRecursiveMutex file_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
return file_mutex;
}
// The following static variables are protected by
-// LinuxPerfBasicLogger::GetFileMutex().
-uint64_t LinuxPerfBasicLogger::reference_count_ = 0;
-FILE* LinuxPerfBasicLogger::perf_output_handle_ = nullptr;
+// PerfBasicLogger::GetFileMutex().
+uint64_t PerfBasicLogger::reference_count_ = 0;
+FILE* PerfBasicLogger::perf_output_handle_ = nullptr;
-LinuxPerfBasicLogger::LinuxPerfBasicLogger(Isolate* isolate)
- : CodeEventLogger(isolate) {
+PerfBasicLogger::PerfBasicLogger(Isolate* isolate) : CodeEventLogger(isolate) {
base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
int process_id_ = base::OS::GetCurrentProcessId();
reference_count_++;
@@ -424,7 +423,7 @@ LinuxPerfBasicLogger::LinuxPerfBasicLogger(Isolate* isolate)
}
}
-LinuxPerfBasicLogger::~LinuxPerfBasicLogger() {
+PerfBasicLogger::~PerfBasicLogger() {
base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
reference_count_--;
@@ -436,9 +435,9 @@ LinuxPerfBasicLogger::~LinuxPerfBasicLogger() {
}
}
-void LinuxPerfBasicLogger::WriteLogRecordedBuffer(uintptr_t address,
- size_t size, const char* name,
- size_t name_length) {
+void PerfBasicLogger::WriteLogRecordedBuffer(uintptr_t address, size_t size,
+ const char* name,
+ size_t name_length) {
// Linux perf expects hex literals without a leading 0x, while some
// implementations of printf might prepend one when using the %p format
// for pointers, leading to wrongly formatted JIT symbols maps. On the other
@@ -456,9 +455,9 @@ void LinuxPerfBasicLogger::WriteLogRecordedBuffer(uintptr_t address,
#endif
}
-void LinuxPerfBasicLogger::LogRecordedBuffer(
- Tagged<AbstractCode> code, MaybeDirectHandle<SharedFunctionInfo>,
- const char* name, size_t length) {
+void PerfBasicLogger::LogRecordedBuffer(Tagged<AbstractCode> code,
+ MaybeDirectHandle<SharedFunctionInfo>,
+ const char* name, size_t length) {
DisallowGarbageCollection no_gc;
PtrComprCageBase cage_base(isolate_);
if (v8_flags.perf_basic_prof_only_functions &&
@@ -472,13 +471,13 @@ void LinuxPerfBasicLogger::LogRecordedBuffer(
}
#if V8_ENABLE_WEBASSEMBLY
-void LinuxPerfBasicLogger::LogRecordedBuffer(const wasm::WasmCode* code,
- const char* name, size_t length) {
+void PerfBasicLogger::LogRecordedBuffer(const wasm::WasmCode* code,
+ const char* name, size_t length) {
WriteLogRecordedBuffer(static_cast<uintptr_t>(code->instruction_start()),
code->instructions().length(), name, length);
}
#endif // V8_ENABLE_WEBASSEMBLY
-#endif // V8_OS_LINUX
+#endif // V8_OS_LINUX || V8_OS_DARWIN
// External LogEventListener
ExternalLogEventListener::ExternalLogEventListener(Isolate* isolate)
@@ -2304,14 +2303,14 @@ bool V8FileLogger::SetUp(Isolate* isolate) {
PrepareLogFileName(log_file_name, isolate, v8_flags.logfile);
log_file_ = std::make_unique<LogFile>(this, log_file_name.str());
-#if V8_OS_LINUX
+#if V8_OS_LINUX || V8_OS_DARWIN
if (v8_flags.perf_basic_prof) {
- perf_basic_logger_ = std::make_unique<LinuxPerfBasicLogger>(isolate);
+ perf_basic_logger_ = std::make_unique<PerfBasicLogger>(isolate);
CHECK(logger()->AddListener(perf_basic_logger_.get()));
}
if (v8_flags.perf_prof) {
- perf_jit_logger_ = std::make_unique<LinuxPerfJitLogger>(isolate);
+ perf_jit_logger_ = std::make_unique<PerfJitLogger>(isolate);
CHECK(logger()->AddListener(perf_jit_logger_.get()));
}
#else
@@ -2457,7 +2456,7 @@ FILE* V8FileLogger::TearDownAndGetLogFile() {
ticker_.reset();
timer_.Stop();
-#if V8_OS_LINUX
+#if V8_OS_LINUX || V8_OS_DARWIN
if (perf_basic_logger_) {
CHECK(logger()->RemoveListener(perf_basic_logger_.get()));
perf_basic_logger_.reset();
diff --git a/src/logging/log.h b/src/logging/log.h
index ec39b1ec097a864b6f7aaf5625fd681d8b2437a9..b8b5c2be526a456e35b393e9ed8dfae74ef00eb1 100644
--- a/src/logging/log.h
+++ b/src/logging/log.h
@@ -64,8 +64,8 @@ class Isolate;
class JitLogger;
class LogFile;
class LowLevelLogger;
-class LinuxPerfBasicLogger;
-class LinuxPerfJitLogger;
+class PerfBasicLogger;
+class PerfJitLogger;
class Profiler;
class SourcePosition;
class Ticker;
@@ -363,9 +363,9 @@ class V8FileLogger : public LogEventListener {
std::atomic<bool> is_logging_;
std::unique_ptr<LogFile> log_file_;
-#if V8_OS_LINUX
- std::unique_ptr<LinuxPerfBasicLogger> perf_basic_logger_;
- std::unique_ptr<LinuxPerfJitLogger> perf_jit_logger_;
+#if V8_OS_LINUX || V8_OS_DARWIN
+ std::unique_ptr<PerfBasicLogger> perf_basic_logger_;
+ std::unique_ptr<PerfJitLogger> perf_jit_logger_;
#endif
std::unique_ptr<LowLevelLogger> ll_logger_;
std::unique_ptr<JitLogger> jit_logger_;