From 48f31bdf206c18232beef5ae3e6777d071f44b3c Mon Sep 17 00:00:00 2001
From: Peter Marshall
Date: Tue, 26 Jun 2018 18:37:43 +0200
Subject: [PATCH] deps: V8: backport 20 CPU profiler commits from upstream
[cpu-profiler] Fix bugs and add tests for JITLineInfoTable
https://chromium.googlesource.com/v8/v8/+/4feb5ce7fd5ef8c933f3f5dff2eca1173f85c1e9
[cpu-profiler] Fix incorrect line number calculation.
https://chromium.googlesource.com/v8/v8/+/ddb2856f39632f9e9f623d3cdb4600e636172031
[cpu-profiler] Use std::unordered_map for hashmaps.
https://chromium.googlesource.com/v8/v8/+/35985ce6abc80b85264fe3b87b246fed5f1806e6
[cpu-profiler] Do not store CodeEntries between profiling sessions.
https://chromium.googlesource.com/v8/v8.git/+/8ec48b2117b8092c4956f1ee11a0c85bec3ba1f8
[cpu-profiler] Remove name_prefix field from CodeEntry
https://chromium.googlesource.com/v8/v8.git/+/6f72af25fe43218b60c68129073ddcddb631566e
[cpu-profiler] Extract rare used fields of CodeEntry to an optional object.
https://chromium.googlesource.com/v8/v8.git/+/fcc1ebb55aab38013855834f556f6e874e0eb8b3
[profiler] Refactoring: decouple StringsStorage from Heap object.
https://chromium.googlesource.com/v8/v8/+/a31320f59c911a277566d6c2fa0b0f2ac83e0748
[cpu-profiler] Add a HandleScope to limit memory consumption.
https://chromium.googlesource.com/v8/v8.git/+/3e9f8a4f635e2d946651d6a4df81378266f32dc9
[cpu-profiler] Lazily create CPU profiler.
https://chromium.googlesource.com/v8/v8/+/1426ea1d6d45be0b4d9476bdb5bf3f27cfe578a0
[cpu-profiler] turn several std::map's into unordered_map's.
https://chromium.googlesource.com/v8/v8/+/3ed5dfb8a3cbc7aa0017bd01c2fdd6227485b8ad
[cpu-profiler] Eagerly delete not used CodeEntry'es
https://chromium.googlesource.com/v8/v8.git/+/c6c28f7a412a88df12055e953630a9e93cc64d49
[cpu-profiler] Move bailout reason into rare_info struct
https://chromium.googlesource.com/v8/v8.git/+/29ea4d1ef5360e71c61ecf8db6a5a0a0c3391fd1
[cpu-profiler] Save space in the SourcePositionTable by using a vector.
https://chromium.googlesource.com/v8/v8.git/+/1cb19f0e0a93adbac8c11bc906f951bd8098722d
[cpu-profiler] Only store deopt inline frames for functions that need it
https://chromium.googlesource.com/v8/v8.git/+/0bfcbdd4726920755e51dab28c18ab93e050819b
[cpu-profiler] Add a new profiling mode with a more detailed call tree.
https://chromium.googlesource.com/v8/v8.git/+/ecae80cdb350dde1e654c531b56f5b6c44dc8c77
[cpu-profiler] Reuse free slots in code_entries_
https://chromium.googlesource.com/v8/v8.git/+/3e1126bf15e62c433c4e9cb21316d182f691c63a
[cpu-profiler] Use instruction start as the key for the CodeMap
https://chromium.googlesource.com/v8/v8.git/+/ba752ea4c50713dff1e94f45a79db3ba968a8d66
[cpu-profiler] Add flag to always generate accurate line info.
https://chromium.googlesource.com/v8/v8/+/56baf56790de439b3f69e887e94beb3b301ed77c
[cpu-profiler] Turn on detailed line info for optimized code
https://chromium.googlesource.com/v8/v8/+/84894ce6d2af7feb9e1f5574409355120887326c
[cpu-profiler] Separate the flags for generating extra line information
https://chromium.googlesource.com/v8/v8/+/30ff6719db441cc7ef220d449970cc169067e256
Backport-PR-URL: https://github.com/nodejs/node/pull/21558
PR-URL: https://github.com/nodejs/node/pull/21558
Reviewed-By: Matteo Collina
Reviewed-By: Myles Borins
Reviewed-By: Yang Guo
Reviewed-By: Rod Vagg
---
deps/v8/include/v8-profiler.h | 17 +
deps/v8/include/v8-version.h | 2 +-
deps/v8/src/api.cc | 21 +-
deps/v8/src/code-events.h | 4 +-
deps/v8/src/compilation-info.cc | 2 +-
deps/v8/src/flag-definitions.h | 3 +
deps/v8/src/heap/mark-compact.cc | 2 +-
deps/v8/src/isolate.cc | 12 +-
deps/v8/src/isolate.h | 4 +-
deps/v8/src/log.cc | 48 +--
deps/v8/src/log.h | 14 +-
deps/v8/src/perf-jit.cc | 2 +-
deps/v8/src/perf-jit.h | 4 +-
deps/v8/src/profiler/cpu-profiler-inl.h | 18 +-
deps/v8/src/profiler/cpu-profiler.cc | 50 +--
deps/v8/src/profiler/cpu-profiler.h | 30 +-
deps/v8/src/profiler/heap-profiler.cc | 4 +-
deps/v8/src/profiler/profile-generator-inl.h | 26 +-
deps/v8/src/profiler/profile-generator.cc | 367 +++++++++++-------
deps/v8/src/profiler/profile-generator.h | 218 +++++++----
deps/v8/src/profiler/profiler-listener.cc | 176 ++++-----
deps/v8/src/profiler/profiler-listener.h | 32 +-
deps/v8/src/profiler/strings-storage.cc | 32 +-
deps/v8/src/profiler/strings-storage.h | 6 +-
deps/v8/src/snapshot/serializer.h | 4 +-
deps/v8/test/cctest/cctest.status | 3 +
deps/v8/test/cctest/test-cpu-profiler.cc | 196 +++++++---
deps/v8/test/cctest/test-log.cc | 2 +-
deps/v8/test/cctest/test-profile-generator.cc | 115 ++++--
29 files changed, 852 insertions(+), 562 deletions(-)
diff --git a/deps/v8/include/v8-profiler.h b/deps/v8/include/v8-profiler.h
index 2363f0514778f0..ba81a8b7d165a1 100644
--- a/deps/v8/include/v8-profiler.h
+++ b/deps/v8/include/v8-profiler.h
@@ -273,6 +273,16 @@ class V8_EXPORT CpuProfile {
void Delete();
};
+enum CpuProfilingMode {
+ // In the resulting CpuProfile tree, intermediate nodes in a stack trace
+ // (from the root to a leaf) will have line numbers that point to the start
+ // line of the function, rather than the line of the callsite of the child.
+ kLeafNodeLineNumbers,
+ // In the resulting CpuProfile tree, nodes are separated based on the line
+ // number of their callsite in their parent.
+ kCallerLineNumbers,
+};
+
/**
* Interface for controlling CPU profiling. Instance of the
* profiler can be created using v8::CpuProfiler::New method.
@@ -309,6 +319,13 @@ class V8_EXPORT CpuProfiler {
* |record_samples| parameter controls whether individual samples should
* be recorded in addition to the aggregated tree.
*/
+ void StartProfiling(Local title, CpuProfilingMode mode,
+ bool record_samples = false);
+ /**
+ * The same as StartProfiling above, but the CpuProfilingMode defaults to
+ * kLeafNodeLineNumbers mode, which was the previous default behavior of the
+ * profiler.
+ */
void StartProfiling(Local title, bool record_samples = false);
/**
diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h
index 890a67c8446d40..f2531abb21f0aa 100644
--- a/deps/v8/include/v8-version.h
+++ b/deps/v8/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 6
#define V8_MINOR_VERSION 2
#define V8_BUILD_NUMBER 414
-#define V8_PATCH_LEVEL 67
+#define V8_PATCH_LEVEL 68
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index b22c75704e0f7f..bc5848e939420a 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -8418,7 +8418,7 @@ HeapProfiler* Isolate::GetHeapProfiler() {
CpuProfiler* Isolate::GetCpuProfiler() {
i::CpuProfiler* cpu_profiler =
- reinterpret_cast(this)->cpu_profiler();
+ reinterpret_cast(this)->EnsureCpuProfiler();
return reinterpret_cast(cpu_profiler);
}
@@ -10138,15 +10138,7 @@ Local CpuProfileNode::GetFunctionName() const {
const i::CodeEntry* entry = node->entry();
i::Handle name =
isolate->factory()->InternalizeUtf8String(entry->name());
- if (!entry->has_name_prefix()) {
- return ToApiHandle(name);
- } else {
- // We do not expect this to fail. Change this if it does.
- i::Handle cons = isolate->factory()->NewConsString(
- isolate->factory()->InternalizeUtf8String(entry->name_prefix()),
- name).ToHandleChecked();
- return ToApiHandle(cons);
- }
+ return ToApiHandle(name);
}
int debug::Coverage::BlockData::StartOffset() const { return block_->start; }
@@ -10237,7 +10229,7 @@ const char* CpuProfileNode::GetScriptResourceNameStr() const {
}
int CpuProfileNode::GetLineNumber() const {
- return reinterpret_cast(this)->entry()->line_number();
+ return reinterpret_cast(this)->line_number();
}
@@ -10370,9 +10362,14 @@ void CpuProfiler::CollectSample() {
void CpuProfiler::StartProfiling(Local title, bool record_samples) {
reinterpret_cast(this)->StartProfiling(
- *Utils::OpenHandle(*title), record_samples);
+ *Utils::OpenHandle(*title), record_samples, kLeafNodeLineNumbers);
}
+void CpuProfiler::StartProfiling(Local title, CpuProfilingMode mode,
+ bool record_samples) {
+ reinterpret_cast(this)->StartProfiling(
+ *Utils::OpenHandle(*title), record_samples, mode);
+}
CpuProfile* CpuProfiler::StopProfiling(Local title) {
return reinterpret_cast(
diff --git a/deps/v8/src/code-events.h b/deps/v8/src/code-events.h
index ca92e2b5e4e624..f26d6327b5cd0d 100644
--- a/deps/v8/src/code-events.h
+++ b/deps/v8/src/code-events.h
@@ -101,7 +101,7 @@ class CodeEventListener {
virtual void GetterCallbackEvent(Name* name, Address entry_point) = 0;
virtual void SetterCallbackEvent(Name* name, Address entry_point) = 0;
virtual void RegExpCodeCreateEvent(AbstractCode* code, String* source) = 0;
- virtual void CodeMoveEvent(AbstractCode* from, Address to) = 0;
+ virtual void CodeMoveEvent(AbstractCode* from, AbstractCode* to) = 0;
virtual void SharedFunctionInfoMoveEvent(Address from, Address to) = 0;
virtual void CodeMovingGCEvent() = 0;
virtual void CodeDisableOptEvent(AbstractCode* code,
@@ -163,7 +163,7 @@ class CodeEventDispatcher {
void RegExpCodeCreateEvent(AbstractCode* code, String* source) {
CODE_EVENT_DISPATCH(RegExpCodeCreateEvent(code, source));
}
- void CodeMoveEvent(AbstractCode* from, Address to) {
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to) {
CODE_EVENT_DISPATCH(CodeMoveEvent(from, to));
}
void SharedFunctionInfoMoveEvent(Address from, Address to) {
diff --git a/deps/v8/src/compilation-info.cc b/deps/v8/src/compilation-info.cc
index f4566d29bdb328..b639def60f2766 100644
--- a/deps/v8/src/compilation-info.cc
+++ b/deps/v8/src/compilation-info.cc
@@ -51,7 +51,7 @@ CompilationInfo::CompilationInfo(Zone* zone, Isolate* isolate,
// Collect source positions for optimized code when profiling or if debugger
// is active, to be able to get more precise source positions at the price of
// more memory consumption.
- if (isolate_->NeedsSourcePositionsForProfiling()) {
+ if (isolate_->NeedsDetailedOptimizedCodeLineInfo()) {
MarkAsSourcePositionsEnabled();
}
}
diff --git a/deps/v8/src/flag-definitions.h b/deps/v8/src/flag-definitions.h
index bcb5a2c982b5a7..7fc25bcc91b66e 100644
--- a/deps/v8/src/flag-definitions.h
+++ b/deps/v8/src/flag-definitions.h
@@ -1082,6 +1082,9 @@ DEFINE_BOOL(log_source_code, false, "Log source code.")
DEFINE_BOOL(prof, false,
"Log statistical profiling information (implies --log-code).")
+DEFINE_BOOL(detailed_line_info, true,
+ "Always generate detailed line information for CPU profiling.")
+
#if defined(ANDROID)
// Phones and tablets have processors that are much slower than desktop
// and laptop computers for which current heuristics are tuned.
diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc
index 194415e94979de..945c95e13622f5 100644
--- a/deps/v8/src/heap/mark-compact.cc
+++ b/deps/v8/src/heap/mark-compact.cc
@@ -1484,7 +1484,7 @@ class ProfilingMigrationObserver final : public MigrationObserver {
int size) final {
if (dest == CODE_SPACE || (dest == OLD_SPACE && dst->IsBytecodeArray())) {
PROFILE(heap_->isolate(),
- CodeMoveEvent(AbstractCode::cast(src), dst->address()));
+ CodeMoveEvent(AbstractCode::cast(src), AbstractCode::cast(dst)));
}
heap_->OnMoveEvent(dst, src, size);
}
diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc
index 02f7d1df64e288..bccd0cb0b880e3 100644
--- a/deps/v8/src/isolate.cc
+++ b/deps/v8/src/isolate.cc
@@ -2697,7 +2697,6 @@ bool Isolate::Init(StartupDeserializer* des) {
call_descriptor_data_ =
new CallInterfaceDescriptorData[CallDescriptors::NUMBER_OF_DESCRIPTORS];
access_compiler_data_ = new AccessCompilerData();
- cpu_profiler_ = new CpuProfiler(this);
heap_profiler_ = new HeapProfiler(heap());
interpreter_ = new interpreter::Interpreter(this);
compiler_dispatcher_ =
@@ -2970,6 +2969,10 @@ bool Isolate::use_optimizer() {
!is_precise_count_code_coverage() && !is_block_count_code_coverage();
}
+bool Isolate::NeedsDetailedOptimizedCodeLineInfo() const {
+ return NeedsSourcePositionsForProfiling() || FLAG_detailed_line_info;
+}
+
bool Isolate::NeedsSourcePositionsForProfiling() const {
return FLAG_trace_deopt || FLAG_trace_turbo || FLAG_trace_turbo_graph ||
FLAG_turbo_profiling || FLAG_perf_prof || is_profiling() ||
@@ -3694,6 +3697,13 @@ void Isolate::PrintWithTimestamp(const char* format, ...) {
va_end(arguments);
}
+CpuProfiler* Isolate::EnsureCpuProfiler() {
+ if (!cpu_profiler_) {
+ cpu_profiler_ = new CpuProfiler(this);
+ }
+ return cpu_profiler_;
+}
+
bool StackLimitCheck::JsHasOverflowed(uintptr_t gap) const {
StackGuard* stack_guard = isolate_->stack_guard();
#ifdef USE_SIMULATOR
diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h
index c3a0727e84a353..a98b6bc0eca4e5 100644
--- a/deps/v8/src/isolate.h
+++ b/deps/v8/src/isolate.h
@@ -1019,6 +1019,8 @@ class Isolate {
bool NeedsSourcePositionsForProfiling() const;
+ bool NeedsDetailedOptimizedCodeLineInfo() const;
+
bool is_best_effort_code_coverage() const {
return code_coverage_mode() == debug::Coverage::kBestEffort;
}
@@ -1449,7 +1451,7 @@ class Isolate {
// TODO(alph): Remove along with the deprecated GetCpuProfiler().
friend v8::CpuProfiler* v8::Isolate::GetCpuProfiler();
- CpuProfiler* cpu_profiler() const { return cpu_profiler_; }
+ CpuProfiler* EnsureCpuProfiler();
base::Atomic32 id_;
EntryStackItem* entry_stack_;
diff --git a/deps/v8/src/log.cc b/deps/v8/src/log.cc
index 0ba024b987189e..591338da9aacb2 100644
--- a/deps/v8/src/log.cc
+++ b/deps/v8/src/log.cc
@@ -22,7 +22,6 @@
#include "src/log-utils.h"
#include "src/macro-assembler.h"
#include "src/perf-jit.h"
-#include "src/profiler/profiler-listener.h"
#include "src/profiler/tick-sample.h"
#include "src/runtime-profiler.h"
#include "src/source-position-table.h"
@@ -218,7 +217,7 @@ class PerfBasicLogger : public CodeEventLogger {
PerfBasicLogger();
~PerfBasicLogger() override;
- void CodeMoveEvent(AbstractCode* from, Address to) override {}
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override {}
void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override {}
@@ -287,7 +286,7 @@ class LowLevelLogger : public CodeEventLogger {
explicit LowLevelLogger(const char* file_name);
~LowLevelLogger() override;
- void CodeMoveEvent(AbstractCode* from, Address to) override;
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override;
void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override {}
void SnapshotPositionEvent(HeapObject* obj, int pos);
@@ -393,11 +392,10 @@ void LowLevelLogger::LogRecordedBuffer(AbstractCode* code, SharedFunctionInfo*,
code->instruction_size());
}
-void LowLevelLogger::CodeMoveEvent(AbstractCode* from, Address to) {
+void LowLevelLogger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) {
CodeMoveStruct event;
event.from_address = from->instruction_start();
- size_t header_size = from->instruction_start() - from->address();
- event.to_address = to + header_size;
+ event.to_address = to->instruction_start();
LogWriteStruct(event);
}
@@ -419,7 +417,7 @@ class JitLogger : public CodeEventLogger {
public:
explicit JitLogger(JitCodeEventHandler code_event_handler);
- void CodeMoveEvent(AbstractCode* from, Address to) override;
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override;
void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override {}
void AddCodeLinePosInfoEvent(void* jit_handler_data, int pc_offset,
@@ -460,19 +458,14 @@ void JitLogger::LogRecordedBuffer(AbstractCode* code,
code_event_handler_(&event);
}
-void JitLogger::CodeMoveEvent(AbstractCode* from, Address to) {
+void JitLogger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) {
base::LockGuard guard(&logger_mutex_);
JitCodeEvent event;
event.type = JitCodeEvent::CODE_MOVED;
- event.code_start = from->instruction_start();
+ event.code_start = reinterpret_cast(from->instruction_start());
event.code_len = from->instruction_size();
-
- // Calculate the header size.
- const size_t header_size = from->instruction_start() - from->address();
-
- // Calculate the new start address of the instructions.
- event.new_code_start = to + header_size;
+ event.new_code_start = reinterpret_cast(to->instruction_start());
code_event_handler_(&event);
}
@@ -739,7 +732,6 @@ Logger::Logger(Isolate* isolate)
perf_jit_logger_(NULL),
ll_logger_(NULL),
jit_logger_(NULL),
- listeners_(5),
is_initialized_(false) {}
Logger::~Logger() {
@@ -1297,9 +1289,10 @@ void Logger::RegExpCodeCreateEvent(AbstractCode* code, String* source) {
msg.WriteToLogFile();
}
-void Logger::CodeMoveEvent(AbstractCode* from, Address to) {
+void Logger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) {
if (!is_logging_code_events()) return;
- MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(), to);
+ MoveEventInternal(CodeEventListener::CODE_MOVE_EVENT, from->address(),
+ to->address());
}
void Logger::CodeLinePosInfoRecordEvent(AbstractCode* code,
@@ -1876,8 +1869,6 @@ bool Logger::SetUp(Isolate* isolate) {
profiler_->Engage();
}
- profiler_listener_.reset();
-
if (is_logging_) {
addCodeEventListener(this);
}
@@ -1905,19 +1896,6 @@ void Logger::SetCodeEventHandler(uint32_t options,
}
}
-void Logger::SetUpProfilerListener() {
- if (!is_initialized_) return;
- if (profiler_listener_.get() == nullptr) {
- profiler_listener_.reset(new ProfilerListener(isolate_));
- }
- addCodeEventListener(profiler_listener_.get());
-}
-
-void Logger::TearDownProfilerListener() {
- if (profiler_listener_->HasObservers()) return;
- removeCodeEventListener(profiler_listener_.get());
-}
-
sampler::Sampler* Logger::sampler() {
return ticker_;
}
@@ -1961,10 +1939,6 @@ FILE* Logger::TearDown() {
jit_logger_ = NULL;
}
- if (profiler_listener_.get() != nullptr) {
- removeCodeEventListener(profiler_listener_.get());
- }
-
return log_->Close();
}
diff --git a/deps/v8/src/log.h b/deps/v8/src/log.h
index 3e4d385527b6d0..931227a1453c2e 100644
--- a/deps/v8/src/log.h
+++ b/deps/v8/src/log.h
@@ -74,7 +74,6 @@ class LowLevelLogger;
class PerfBasicLogger;
class PerfJitLogger;
class Profiler;
-class ProfilerListener;
class RuntimeCallTimer;
class Ticker;
@@ -102,16 +101,8 @@ class Logger : public CodeEventListener {
void SetCodeEventHandler(uint32_t options,
JitCodeEventHandler event_handler);
- // Sets up ProfilerListener.
- void SetUpProfilerListener();
-
- // Tear down ProfilerListener if it has no observers.
- void TearDownProfilerListener();
-
sampler::Sampler* sampler();
- ProfilerListener* profiler_listener() { return profiler_listener_.get(); }
-
// Frees resources acquired in SetUp.
// When a temporary file is used for the log, returns its stream descriptor,
// leaving the file open.
@@ -177,7 +168,7 @@ class Logger : public CodeEventListener {
// Emits a code create event for a RegExp.
void RegExpCodeCreateEvent(AbstractCode* code, String* source);
// Emits a code move event.
- void CodeMoveEvent(AbstractCode* from, Address to);
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to);
// Emits a code line info record event.
void CodeLinePosInfoRecordEvent(AbstractCode* code,
ByteArray* source_position_table);
@@ -316,8 +307,6 @@ class Logger : public CodeEventListener {
PerfJitLogger* perf_jit_logger_;
LowLevelLogger* ll_logger_;
JitLogger* jit_logger_;
- std::unique_ptr profiler_listener_;
- List listeners_;
std::set logged_source_code_;
uint32_t next_source_info_id_ = 0;
@@ -400,7 +389,6 @@ class CodeEventLogger : public CodeEventListener {
NameBuffer* name_buffer_;
};
-
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/perf-jit.cc b/deps/v8/src/perf-jit.cc
index 46597a968588c4..5ca1c2ba917a49 100644
--- a/deps/v8/src/perf-jit.cc
+++ b/deps/v8/src/perf-jit.cc
@@ -376,7 +376,7 @@ void PerfJitLogger::LogWriteUnwindingInfo(Code* code) {
LogWriteBytes(padding_bytes, static_cast(padding_size));
}
-void PerfJitLogger::CodeMoveEvent(AbstractCode* from, Address to) {
+void PerfJitLogger::CodeMoveEvent(AbstractCode* from, AbstractCode* to) {
// Code relocation not supported.
UNREACHABLE();
}
diff --git a/deps/v8/src/perf-jit.h b/deps/v8/src/perf-jit.h
index 2b0b4831e0c43d..f68595f29ea6ff 100644
--- a/deps/v8/src/perf-jit.h
+++ b/deps/v8/src/perf-jit.h
@@ -41,7 +41,7 @@ class PerfJitLogger : public CodeEventLogger {
PerfJitLogger();
virtual ~PerfJitLogger();
- void CodeMoveEvent(AbstractCode* from, Address to) override;
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override;
void CodeDisableOptEvent(AbstractCode* code,
SharedFunctionInfo* shared) override {}
@@ -113,7 +113,7 @@ class PerfJitLogger : public CodeEventLogger {
// PerfJitLogger is only implemented on Linux
class PerfJitLogger : public CodeEventLogger {
public:
- void CodeMoveEvent(AbstractCode* from, Address to) override {
+ void CodeMoveEvent(AbstractCode* from, AbstractCode* to) override {
UNIMPLEMENTED();
}
diff --git a/deps/v8/src/profiler/cpu-profiler-inl.h b/deps/v8/src/profiler/cpu-profiler-inl.h
index 440c6a1cce189b..2beb6f5aab2a94 100644
--- a/deps/v8/src/profiler/cpu-profiler-inl.h
+++ b/deps/v8/src/profiler/cpu-profiler-inl.h
@@ -16,31 +16,35 @@ namespace v8 {
namespace internal {
void CodeCreateEventRecord::UpdateCodeMap(CodeMap* code_map) {
- code_map->AddCode(start, entry, size);
+ code_map->AddCode(instruction_start, entry, instruction_size);
}
void CodeMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
- code_map->MoveCode(from, to);
+ code_map->MoveCode(from_instruction_start, to_instruction_start);
}
void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
- CodeEntry* entry = code_map->FindEntry(start);
- if (entry != NULL) {
+ CodeEntry* entry = code_map->FindEntry(instruction_start);
+ if (entry != nullptr) {
entry->set_bailout_reason(bailout_reason);
}
}
void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
- CodeEntry* entry = code_map->FindEntry(start);
- if (entry != NULL) entry->set_deopt_info(deopt_reason, deopt_id);
+ CodeEntry* entry = code_map->FindEntry(instruction_start);
+ if (entry == nullptr) return;
+ std::vector frames_vector(
+ deopt_frames, deopt_frames + deopt_frame_count);
+ entry->set_deopt_info(deopt_reason, deopt_id, std::move(frames_vector));
+ delete[] deopt_frames;
}
void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) {
- CodeEntry* entry = code_map->FindEntry(start);
+ CodeEntry* entry = code_map->FindEntry(instruction_start);
if (!entry) {
// Code objects for builtins should already have been added to the map but
// some of them have been filtered out by CpuProfiler.
diff --git a/deps/v8/src/profiler/cpu-profiler.cc b/deps/v8/src/profiler/cpu-profiler.cc
index 80d488f12c527f..69021cee344eb2 100644
--- a/deps/v8/src/profiler/cpu-profiler.cc
+++ b/deps/v8/src/profiler/cpu-profiler.cc
@@ -4,6 +4,12 @@
#include "src/profiler/cpu-profiler.h"
+#include
+#include
+
+#include "src/base/lazy-instance.h"
+#include "src/base/platform/mutex.h"
+#include "src/base/template-utils.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
#include "src/frames-inl.h"
@@ -275,20 +281,19 @@ void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
void CpuProfiler::ResetProfiles() {
profiles_.reset(new CpuProfilesCollection(isolate_));
profiles_->set_cpu_profiler(this);
+ profiler_listener_.reset();
+ generator_.reset();
}
void CpuProfiler::CreateEntriesForRuntimeCallStats() {
- static_entries_.clear();
RuntimeCallStats* rcs = isolate_->counters()->runtime_call_stats();
CodeMap* code_map = generator_->code_map();
for (int i = 0; i < RuntimeCallStats::counters_count; ++i) {
RuntimeCallCounter* counter = &(rcs->*(RuntimeCallStats::counters[i]));
DCHECK(counter->name());
- std::unique_ptr entry(
- new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
- CodeEntry::kEmptyNamePrefix, "native V8Runtime"));
- code_map->AddCode(reinterpret_cast(counter), entry.get(), 1);
- static_entries_.push_back(std::move(entry));
+ auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
+ "native V8Runtime");
+ code_map->AddCode(reinterpret_cast(counter), entry, 1);
}
}
@@ -298,20 +303,20 @@ void CpuProfiler::CollectSample() {
}
}
-void CpuProfiler::StartProfiling(const char* title, bool record_samples) {
- if (profiles_->StartProfiling(title, record_samples)) {
+void CpuProfiler::StartProfiling(const char* title, bool record_samples,
+ ProfilingMode mode) {
+ if (profiles_->StartProfiling(title, record_samples, mode)) {
TRACE_EVENT0("v8", "CpuProfiler::StartProfiling");
StartProcessorIfNotStarted();
}
}
-
-void CpuProfiler::StartProfiling(String* title, bool record_samples) {
- StartProfiling(profiles_->GetName(title), record_samples);
+void CpuProfiler::StartProfiling(String* title, bool record_samples,
+ ProfilingMode mode) {
+ StartProfiling(profiles_->GetName(title), record_samples, mode);
isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler);
}
-
void CpuProfiler::StartProcessorIfNotStarted() {
if (processor_) {
processor_->AddCurrentStack(isolate_);
@@ -321,13 +326,17 @@ void CpuProfiler::StartProcessorIfNotStarted() {
// Disable logging when using the new implementation.
saved_is_logging_ = logger->is_logging_;
logger->is_logging_ = false;
- generator_.reset(new ProfileGenerator(profiles_.get()));
+ if (!generator_) {
+ generator_.reset(new ProfileGenerator(profiles_.get()));
+ CreateEntriesForRuntimeCallStats();
+ }
processor_.reset(new ProfilerEventsProcessor(isolate_, generator_.get(),
sampling_interval_));
- CreateEntriesForRuntimeCallStats();
- logger->SetUpProfilerListener();
- ProfilerListener* profiler_listener = logger->profiler_listener();
- profiler_listener->AddObserver(this);
+ if (!profiler_listener_) {
+ profiler_listener_.reset(new ProfilerListener(isolate_, this));
+ }
+ logger->addCodeEventListener(profiler_listener_.get());
+
is_profiling_ = true;
isolate_->set_is_profiling(true);
// Enumerate stuff we already have in the heap.
@@ -362,12 +371,9 @@ void CpuProfiler::StopProcessor() {
Logger* logger = isolate_->logger();
is_profiling_ = false;
isolate_->set_is_profiling(false);
- ProfilerListener* profiler_listener = logger->profiler_listener();
- profiler_listener->RemoveObserver(this);
+ logger->removeCodeEventListener(profiler_listener_.get());
processor_->StopSynchronously();
- logger->TearDownProfilerListener();
processor_.reset();
- generator_.reset();
logger->is_logging_ = saved_is_logging_;
}
@@ -379,7 +385,7 @@ void CpuProfiler::LogBuiltins() {
CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN);
ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_;
Builtins::Name id = static_cast(i);
- rec->start = builtins->builtin(id)->address();
+ rec->instruction_start = builtins->builtin(id)->instruction_start();
rec->builtin_id = id;
processor_->Enqueue(evt_rec);
}
diff --git a/deps/v8/src/profiler/cpu-profiler.h b/deps/v8/src/profiler/cpu-profiler.h
index 5fd7fa14da1cab..2672c1b8961cf2 100644
--- a/deps/v8/src/profiler/cpu-profiler.h
+++ b/deps/v8/src/profiler/cpu-profiler.h
@@ -53,9 +53,9 @@ class CodeEventRecord {
class CodeCreateEventRecord : public CodeEventRecord {
public:
- Address start;
+ Address instruction_start;
CodeEntry* entry;
- unsigned size;
+ unsigned instruction_size;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
@@ -63,8 +63,8 @@ class CodeCreateEventRecord : public CodeEventRecord {
class CodeMoveEventRecord : public CodeEventRecord {
public:
- Address from;
- Address to;
+ Address from_instruction_start;
+ Address to_instruction_start;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
@@ -72,7 +72,7 @@ class CodeMoveEventRecord : public CodeEventRecord {
class CodeDisableOptEventRecord : public CodeEventRecord {
public:
- Address start;
+ Address instruction_start;
const char* bailout_reason;
INLINE(void UpdateCodeMap(CodeMap* code_map));
@@ -81,11 +81,13 @@ class CodeDisableOptEventRecord : public CodeEventRecord {
class CodeDeoptEventRecord : public CodeEventRecord {
public:
- Address start;
+ Address instruction_start;
const char* deopt_reason;
int deopt_id;
void* pc;
int fp_to_sp_delta;
+ CpuProfileDeoptFrame* deopt_frames;
+ int deopt_frame_count;
INLINE(void UpdateCodeMap(CodeMap* code_map));
};
@@ -93,7 +95,7 @@ class CodeDeoptEventRecord : public CodeEventRecord {
class ReportBuiltinEventRecord : public CodeEventRecord {
public:
- Address start;
+ Address instruction_start;
Builtins::Name builtin_id;
INLINE(void UpdateCodeMap(CodeMap* code_map));
@@ -195,10 +197,13 @@ class CpuProfiler : public CodeEventObserver {
~CpuProfiler() override;
+ typedef v8::CpuProfilingMode ProfilingMode;
+
void set_sampling_interval(base::TimeDelta value);
void CollectSample();
- void StartProfiling(const char* title, bool record_samples = false);
- void StartProfiling(String* title, bool record_samples);
+ void StartProfiling(const char* title, bool record_samples = false,
+ ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
+ void StartProfiling(String* title, bool record_samples, ProfilingMode mode);
CpuProfile* StopProfiling(const char* title);
CpuProfile* StopProfiling(String* title);
int GetProfilesCount();
@@ -214,6 +219,10 @@ class CpuProfiler : public CodeEventObserver {
ProfilerEventsProcessor* processor() const { return processor_.get(); }
Isolate* isolate() const { return isolate_; }
+ ProfilerListener* profiler_listener_for_test() {
+ return profiler_listener_.get();
+ }
+
private:
void StartProcessorIfNotStarted();
void StopProcessorIfLastProfile(const char* title);
@@ -227,7 +236,7 @@ class CpuProfiler : public CodeEventObserver {
std::unique_ptr profiles_;
std::unique_ptr generator_;
std::unique_ptr processor_;
- std::vector> static_entries_;
+ std::unique_ptr profiler_listener_;
bool saved_is_logging_;
bool is_profiling_;
@@ -237,5 +246,4 @@ class CpuProfiler : public CodeEventObserver {
} // namespace internal
} // namespace v8
-
#endif // V8_PROFILER_CPU_PROFILER_H_
diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc
index 4706b914e7ac40..f587adda497daf 100644
--- a/deps/v8/src/profiler/heap-profiler.cc
+++ b/deps/v8/src/profiler/heap-profiler.cc
@@ -16,7 +16,7 @@ namespace internal {
HeapProfiler::HeapProfiler(Heap* heap)
: ids_(new HeapObjectsMap(heap)),
- names_(new StringsStorage(heap)),
+ names_(new StringsStorage(heap->HashSeed())),
is_tracking_object_moves_(false),
get_retainer_infos_callback_(nullptr) {}
@@ -34,7 +34,7 @@ HeapProfiler::~HeapProfiler() {
void HeapProfiler::DeleteAllSnapshots() {
snapshots_.Iterate(DeleteHeapSnapshot);
snapshots_.Clear();
- names_.reset(new StringsStorage(heap()));
+ names_.reset(new StringsStorage(heap()->HashSeed()));
}
diff --git a/deps/v8/src/profiler/profile-generator-inl.h b/deps/v8/src/profiler/profile-generator-inl.h
index 5a7017ad490767..31652ba9f98e83 100644
--- a/deps/v8/src/profiler/profile-generator-inl.h
+++ b/deps/v8/src/profiler/profile-generator-inl.h
@@ -11,33 +11,35 @@ namespace v8 {
namespace internal {
CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
- const char* name_prefix, const char* resource_name,
- int line_number, int column_number,
- JITLineInfoTable* line_info, Address instruction_start)
+ const char* resource_name, int line_number,
+ int column_number,
+ std::unique_ptr line_info,
+ Address instruction_start)
: bit_field_(TagField::encode(tag) |
BuiltinIdField::encode(Builtins::builtin_count)),
- name_prefix_(name_prefix),
name_(name),
resource_name_(resource_name),
line_number_(line_number),
column_number_(column_number),
script_id_(v8::UnboundScript::kNoScriptId),
position_(0),
- bailout_reason_(kEmptyBailoutReason),
- deopt_reason_(kNoDeoptReason),
- deopt_id_(kNoDeoptimizationId),
- line_info_(line_info),
+ line_info_(std::move(line_info)),
instruction_start_(instruction_start) {}
+inline CodeEntry* ProfileGenerator::FindEntry(Address address) {
+ CodeEntry* entry = code_map_.FindEntry(address);
+ if (entry) entry->mark_used();
+ return entry;
+}
+
ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry,
- ProfileNode* parent)
+ ProfileNode* parent, int line_number)
: tree_(tree),
entry_(entry),
self_ticks_(0),
- children_(CodeEntriesMatch),
+ line_number_(line_number),
parent_(parent),
- id_(tree->next_node_id()),
- line_ticks_(LineTickMatch) {
+ id_(tree->next_node_id()) {
tree_->EnqueueNode(this);
}
diff --git a/deps/v8/src/profiler/profile-generator.cc b/deps/v8/src/profiler/profile-generator.cc
index 029b6826ec25fa..c01904b77801b1 100644
--- a/deps/v8/src/profiler/profile-generator.cc
+++ b/deps/v8/src/profiler/profile-generator.cc
@@ -18,33 +18,30 @@
namespace v8 {
namespace internal {
-
-JITLineInfoTable::JITLineInfoTable() {}
-
-
-JITLineInfoTable::~JITLineInfoTable() {}
-
-
-void JITLineInfoTable::SetPosition(int pc_offset, int line) {
- DCHECK(pc_offset >= 0);
- DCHECK(line > 0); // The 1-based number of the source line.
- if (GetSourceLineNumber(pc_offset) != line) {
- pc_offset_map_.insert(std::make_pair(pc_offset, line));
+void SourcePositionTable::SetPosition(int pc_offset, int line) {
+ DCHECK_GE(pc_offset, 0);
+ DCHECK_GT(line, 0); // The 1-based number of the source line.
+ // Check that we are inserting in ascending order, so that the vector remains
+ // sorted.
+ DCHECK(pc_offsets_to_lines_.empty() ||
+ pc_offsets_to_lines_.back().pc_offset < pc_offset);
+ if (pc_offsets_to_lines_.empty() ||
+ pc_offsets_to_lines_.back().line_number != line) {
+ pc_offsets_to_lines_.push_back({pc_offset, line});
}
}
-
-int JITLineInfoTable::GetSourceLineNumber(int pc_offset) const {
- PcOffsetMap::const_iterator it = pc_offset_map_.lower_bound(pc_offset);
- if (it == pc_offset_map_.end()) {
- if (pc_offset_map_.empty()) return v8::CpuProfileNode::kNoLineNumberInfo;
- return (--pc_offset_map_.end())->second;
+int SourcePositionTable::GetSourceLineNumber(int pc_offset) const {
+ if (pc_offsets_to_lines_.empty()) {
+ return v8::CpuProfileNode::kNoLineNumberInfo;
}
- return it->second;
+ auto it =
+ std::upper_bound(pc_offsets_to_lines_.begin(), pc_offsets_to_lines_.end(),
+ PCOffsetAndLineNumber{pc_offset, 0});
+ if (it != pc_offsets_to_lines_.begin()) --it;
+ return it->line_number;
}
-
-const char* const CodeEntry::kEmptyNamePrefix = "";
const char* const CodeEntry::kEmptyResourceName = "";
const char* const CodeEntry::kEmptyBailoutReason = "";
const char* const CodeEntry::kNoDeoptReason = "";
@@ -85,24 +82,12 @@ CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() {
CodeEntry::kUnresolvedFunctionName);
}
-CodeEntry::~CodeEntry() {
- delete line_info_;
- for (auto location : inline_locations_) {
- for (auto entry : location.second) {
- delete entry;
- }
- }
-}
-
-
uint32_t CodeEntry::GetHash() const {
uint32_t hash = ComputeIntegerHash(tag());
if (script_id_ != v8::UnboundScript::kNoScriptId) {
hash ^= ComputeIntegerHash(static_cast(script_id_));
hash ^= ComputeIntegerHash(static_cast(position_));
} else {
- hash ^= ComputeIntegerHash(
- static_cast(reinterpret_cast(name_prefix_)));
hash ^= ComputeIntegerHash(
static_cast(reinterpret_cast(name_)));
hash ^= ComputeIntegerHash(
@@ -112,14 +97,12 @@ uint32_t CodeEntry::GetHash() const {
return hash;
}
-
-bool CodeEntry::IsSameFunctionAs(CodeEntry* entry) const {
+bool CodeEntry::IsSameFunctionAs(const CodeEntry* entry) const {
if (this == entry) return true;
if (script_id_ != v8::UnboundScript::kNoScriptId) {
return script_id_ == entry->script_id_ && position_ == entry->position_;
}
- return name_prefix_ == entry->name_prefix_ && name_ == entry->name_ &&
- resource_name_ == entry->resource_name_ &&
+ return name_ == entry->name_ && resource_name_ == entry->resource_name_ &&
line_number_ == entry->line_number_;
}
@@ -131,30 +114,31 @@ void CodeEntry::SetBuiltinId(Builtins::Name id) {
int CodeEntry::GetSourceLine(int pc_offset) const {
- if (line_info_ && !line_info_->empty()) {
- return line_info_->GetSourceLineNumber(pc_offset);
- }
+ if (line_info_) return line_info_->GetSourceLineNumber(pc_offset);
return v8::CpuProfileNode::kNoLineNumberInfo;
}
-void CodeEntry::AddInlineStack(int pc_offset,
- std::vector inline_stack) {
- inline_locations_.insert(std::make_pair(pc_offset, std::move(inline_stack)));
+void CodeEntry::AddInlineStack(
+ int pc_offset, std::vector> inline_stack) {
+ EnsureRareData()->inline_locations_.insert(
+ std::make_pair(pc_offset, std::move(inline_stack)));
}
-const std::vector* CodeEntry::GetInlineStack(int pc_offset) const {
- auto it = inline_locations_.find(pc_offset);
- return it != inline_locations_.end() ? &it->second : NULL;
+const std::vector>* CodeEntry::GetInlineStack(
+ int pc_offset) const {
+ if (!rare_data_) return nullptr;
+ auto it = rare_data_->inline_locations_.find(pc_offset);
+ return it != rare_data_->inline_locations_.end() ? &it->second : nullptr;
}
-void CodeEntry::AddDeoptInlinedFrames(
- int deopt_id, std::vector inlined_frames) {
- deopt_inlined_frames_.insert(
- std::make_pair(deopt_id, std::move(inlined_frames)));
-}
-
-bool CodeEntry::HasDeoptInlinedFramesFor(int deopt_id) const {
- return deopt_inlined_frames_.find(deopt_id) != deopt_inlined_frames_.end();
+void CodeEntry::set_deopt_info(
+ const char* deopt_reason, int deopt_id,
+ std::vector inlined_frames) {
+ DCHECK(!has_deopt_info());
+ RareData* rare_data = EnsureRareData();
+ rare_data->deopt_reason_ = deopt_reason;
+ rare_data->deopt_id_ = deopt_id;
+ rare_data->deopt_inlined_frames_ = std::move(inlined_frames);
}
void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) {
@@ -162,49 +146,53 @@ void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) {
Script* script = Script::cast(shared->script());
set_script_id(script->id());
set_position(shared->start_position());
- set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason()));
+ if (shared->optimization_disabled()) {
+ set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason()));
+ }
}
CpuProfileDeoptInfo CodeEntry::GetDeoptInfo() {
DCHECK(has_deopt_info());
CpuProfileDeoptInfo info;
- info.deopt_reason = deopt_reason_;
- DCHECK_NE(kNoDeoptimizationId, deopt_id_);
- if (deopt_inlined_frames_.find(deopt_id_) == deopt_inlined_frames_.end()) {
+ info.deopt_reason = rare_data_->deopt_reason_;
+ DCHECK_NE(kNoDeoptimizationId, rare_data_->deopt_id_);
+ if (rare_data_->deopt_inlined_frames_.empty()) {
info.stack.push_back(CpuProfileDeoptFrame(
{script_id_, static_cast(std::max(0, position()))}));
} else {
- info.stack = deopt_inlined_frames_[deopt_id_];
+ info.stack = rare_data_->deopt_inlined_frames_;
}
return info;
}
+CodeEntry::RareData* CodeEntry::EnsureRareData() {
+ if (!rare_data_) {
+ rare_data_.reset(new RareData());
+ }
+ return rare_data_.get();
+}
void ProfileNode::CollectDeoptInfo(CodeEntry* entry) {
deopt_infos_.push_back(entry->GetDeoptInfo());
entry->clear_deopt_info();
}
-
-ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
- base::HashMap::Entry* map_entry =
- children_.Lookup(entry, CodeEntryHash(entry));
- return map_entry != NULL ?
- reinterpret_cast(map_entry->value) : NULL;
+ProfileNode* ProfileNode::FindChild(CodeEntry* entry, int line_number) {
+ auto map_entry = children_.find({entry, line_number});
+ return map_entry != children_.end() ? map_entry->second : nullptr;
}
-
-ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
- base::HashMap::Entry* map_entry =
- children_.LookupOrInsert(entry, CodeEntryHash(entry));
- ProfileNode* node = reinterpret_cast(map_entry->value);
- if (!node) {
- node = new ProfileNode(tree_, entry, this);
- map_entry->value = node;
+ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry, int line_number) {
+ auto map_entry = children_.find({entry, line_number});
+ if (map_entry == children_.end()) {
+ ProfileNode* node = new ProfileNode(tree_, entry, this, line_number);
+ children_[{entry, line_number}] = node;
children_list_.push_back(node);
+ return node;
+ } else {
+ return map_entry->second;
}
- return node;
}
@@ -212,10 +200,12 @@ void ProfileNode::IncrementLineTicks(int src_line) {
if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return;
// Increment a hit counter of a certain source line.
// Add a new source line if not found.
- base::HashMap::Entry* e =
- line_ticks_.LookupOrInsert(reinterpret_cast(src_line), src_line);
- DCHECK(e);
- e->value = reinterpret_cast(reinterpret_cast(e->value) + 1);
+ auto map_entry = line_ticks_.find(src_line);
+ if (map_entry == line_ticks_.end()) {
+ line_ticks_[src_line] = 1;
+ } else {
+ line_ticks_[src_line]++;
+ }
}
@@ -223,19 +213,16 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
unsigned int length) const {
if (entries == NULL || length == 0) return false;
- unsigned line_count = line_ticks_.occupancy();
+ unsigned line_count = static_cast(line_ticks_.size());
if (line_count == 0) return true;
if (length < line_count) return false;
v8::CpuProfileNode::LineTick* entry = entries;
- for (base::HashMap::Entry *p = line_ticks_.Start(); p != NULL;
- p = line_ticks_.Next(p), entry++) {
- entry->line =
- static_cast(reinterpret_cast(p->key));
- entry->hit_count =
- static_cast(reinterpret_cast(p->value));
+ for (auto p = line_ticks_.begin(); p != line_ticks_.end(); p++, entry++) {
+ entry->line = p->first;
+ entry->hit_count = p->second;
}
return true;
@@ -243,9 +230,9 @@ bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries,
void ProfileNode::Print(int indent) {
- base::OS::Print("%5u %*s %s%s %d #%d", self_ticks_, indent, "",
- entry_->name_prefix(), entry_->name(), entry_->script_id(),
- id());
+ int line_number = line_number_ != 0 ? line_number_ : entry_->line_number();
+ base::OS::Print("%5u %*s %s:%d %d #%d", self_ticks_, indent, "",
+ entry_->name(), line_number, entry_->script_id(), id());
if (entry_->resource_name()[0] != '\0')
base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
base::OS::Print("\n");
@@ -268,9 +255,8 @@ void ProfileNode::Print(int indent) {
base::OS::Print("%*s bailed out due to '%s'\n", indent + 10, "",
bailout_reason);
}
- for (base::HashMap::Entry* p = children_.Start(); p != NULL;
- p = children_.Next(p)) {
- reinterpret_cast(p->value)->Print(indent + 2);
+ for (auto child : children_) {
+ child.second->Print(indent + 2);
}
}
@@ -291,8 +277,7 @@ ProfileTree::ProfileTree(Isolate* isolate)
next_node_id_(1),
root_(new ProfileNode(this, &root_entry_, nullptr)),
isolate_(isolate),
- next_function_id_(1),
- function_ids_(ProfileNode::CodeEntriesMatch) {}
+ next_function_id_(1) {}
ProfileTree::~ProfileTree() {
DeleteNodesCallback cb;
@@ -302,12 +287,11 @@ ProfileTree::~ProfileTree() {
unsigned ProfileTree::GetFunctionId(const ProfileNode* node) {
CodeEntry* code_entry = node->entry();
- base::HashMap::Entry* entry =
- function_ids_.LookupOrInsert(code_entry, code_entry->GetHash());
- if (!entry->value) {
- entry->value = reinterpret_cast(next_function_id_++);
+ auto map_entry = function_ids_.find(code_entry);
+ if (map_entry == function_ids_.end()) {
+ return function_ids_[code_entry] = next_function_id_++;
}
- return static_cast(reinterpret_cast(entry->value));
+ return function_ids_[code_entry];
}
ProfileNode* ProfileTree::AddPathFromEnd(const std::vector& path,
@@ -317,7 +301,33 @@ ProfileNode* ProfileTree::AddPathFromEnd(const std::vector& path,
for (auto it = path.rbegin(); it != path.rend(); ++it) {
if (*it == NULL) continue;
last_entry = *it;
- node = node->FindOrAddChild(*it);
+ node = node->FindOrAddChild(*it, v8::CpuProfileNode::kNoLineNumberInfo);
+ }
+ if (last_entry && last_entry->has_deopt_info()) {
+ node->CollectDeoptInfo(last_entry);
+ }
+ if (update_stats) {
+ node->IncrementSelfTicks();
+ if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) {
+ node->IncrementLineTicks(src_line);
+ }
+ }
+ return node;
+}
+
+ProfileNode* ProfileTree::AddPathFromEnd(const ProfileStackTrace& path,
+ int src_line, bool update_stats,
+ ProfilingMode mode) {
+ ProfileNode* node = root_;
+ CodeEntry* last_entry = nullptr;
+ int parent_line_number = v8::CpuProfileNode::kNoLineNumberInfo;
+ for (auto it = path.rbegin(); it != path.rend(); ++it) {
+ if ((*it).code_entry == nullptr) continue;
+ last_entry = (*it).code_entry;
+ node = node->FindOrAddChild((*it).code_entry, parent_line_number);
+ parent_line_number = mode == ProfilingMode::kCallerLineNumbers
+ ? (*it).line_number
+ : v8::CpuProfileNode::kNoLineNumberInfo;
}
if (last_entry && last_entry->has_deopt_info()) {
node->CollectDeoptInfo(last_entry);
@@ -384,9 +394,10 @@ void ProfileTree::TraverseDepthFirst(Callback* callback) {
using v8::tracing::TracedValue;
CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
- bool record_samples)
+ bool record_samples, ProfilingMode mode)
: title_(title),
record_samples_(record_samples),
+ mode_(mode),
start_time_(base::TimeTicks::HighResolutionNow()),
top_down_(profiler->isolate()),
profiler_(profiler),
@@ -399,14 +410,16 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
}
void CpuProfile::AddPath(base::TimeTicks timestamp,
- const std::vector& path, int src_line,
+ const ProfileStackTrace& path, int src_line,
bool update_stats) {
ProfileNode* top_frame_node =
- top_down_.AddPathFromEnd(path, src_line, update_stats);
+ top_down_.AddPathFromEnd(path, src_line, update_stats, mode_);
+
if (record_samples_ && !timestamp.IsNull()) {
timestamps_.Add(timestamp);
samples_.Add(top_frame_node);
}
+
const int kSamplesFlushCount = 100;
const int kNodesFlushCount = 10;
if (samples_.length() - streaming_next_sample_ >= kSamplesFlushCount ||
@@ -502,19 +515,40 @@ void CpuProfile::Print() {
top_down_.Print();
}
+CodeMap::CodeMap() = default;
+
+CodeMap::~CodeMap() {
+ // First clean the free list as it's otherwise impossible to tell
+ // the slot type.
+ unsigned free_slot = free_list_head_;
+ while (free_slot != kNoFreeSlot) {
+ unsigned next_slot = code_entries_[free_slot].next_free_slot;
+ code_entries_[free_slot].entry = nullptr;
+ free_slot = next_slot;
+ }
+ for (auto slot : code_entries_) delete slot.entry;
+}
+
void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
- DeleteAllCoveredCode(addr, addr + size);
- code_map_.insert({addr, CodeEntryInfo(entry, size)});
+ ClearCodesInRange(addr, addr + size);
+ unsigned index = AddCodeEntry(addr, entry);
+ code_map_.emplace(addr, CodeEntryMapInfo{index, size});
+ DCHECK(entry->instruction_start() == kNullAddress ||
+ addr == entry->instruction_start());
}
-void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
+void CodeMap::ClearCodesInRange(Address start, Address end) {
auto left = code_map_.upper_bound(start);
if (left != code_map_.begin()) {
--left;
if (left->first + left->second.size <= start) ++left;
}
auto right = left;
- while (right != code_map_.end() && right->first < end) ++right;
+ for (; right != code_map_.end() && right->first < end; ++right) {
+ if (!entry(right->second.index)->used()) {
+ DeleteCodeEntry(right->second.index);
+ }
+ }
code_map_.erase(left, right);
}
@@ -522,28 +556,56 @@ CodeEntry* CodeMap::FindEntry(Address addr) {
auto it = code_map_.upper_bound(addr);
if (it == code_map_.begin()) return nullptr;
--it;
- Address end_address = it->first + it->second.size;
- return addr < end_address ? it->second.entry : nullptr;
+ Address start_address = it->first;
+ Address end_address = start_address + it->second.size;
+ CodeEntry* ret = addr < end_address ? entry(it->second.index) : nullptr;
+ if (ret && ret->instruction_start() != nullptr) {
+ DCHECK_EQ(start_address, ret->instruction_start());
+ DCHECK(addr >= start_address && addr < end_address);
+ }
+ return ret;
}
void CodeMap::MoveCode(Address from, Address to) {
if (from == to) return;
auto it = code_map_.find(from);
if (it == code_map_.end()) return;
- CodeEntryInfo info = it->second;
+ CodeEntryMapInfo info = it->second;
code_map_.erase(it);
- AddCode(to, info.entry, info.size);
+ DCHECK(from + info.size <= to || to + info.size <= from);
+ ClearCodesInRange(to, to + info.size);
+ code_map_.emplace(to, info);
+
+ CodeEntry* entry = code_entries_[info.index].entry;
+ entry->set_instruction_start(to);
+}
+
+unsigned CodeMap::AddCodeEntry(Address start, CodeEntry* entry) {
+ if (free_list_head_ == kNoFreeSlot) {
+ code_entries_.push_back(CodeEntrySlotInfo{entry});
+ return static_cast(code_entries_.size()) - 1;
+ }
+ unsigned index = free_list_head_;
+ free_list_head_ = code_entries_[index].next_free_slot;
+ code_entries_[index].entry = entry;
+ return index;
+}
+
+void CodeMap::DeleteCodeEntry(unsigned index) {
+ delete code_entries_[index].entry;
+ code_entries_[index].next_free_slot = free_list_head_;
+ free_list_head_ = index;
}
void CodeMap::Print() {
- for (auto it = code_map_.begin(); it != code_map_.end(); ++it) {
- base::OS::Print("%p %5d %s\n", static_cast(it->first),
- it->second.size, it->second.entry->name());
+ for (const auto& pair : code_map_) {
+ base::OS::Print("%p %5d %s\n", reinterpret_cast(pair.first),
+ pair.second.size, entry(pair.second.index)->name());
}
}
CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate)
- : resource_names_(isolate->heap()),
+ : resource_names_(isolate->heap()->HashSeed()),
profiler_(nullptr),
current_profiles_semaphore_(1) {}
@@ -559,7 +621,8 @@ CpuProfilesCollection::~CpuProfilesCollection() {
bool CpuProfilesCollection::StartProfiling(const char* title,
- bool record_samples) {
+ bool record_samples,
+ ProfilingMode mode) {
current_profiles_semaphore_.Wait();
if (current_profiles_.length() >= kMaxSimultaneousProfiles) {
current_profiles_semaphore_.Signal();
@@ -573,7 +636,7 @@ bool CpuProfilesCollection::StartProfiling(const char* title,
return true;
}
}
- current_profiles_.Add(new CpuProfile(profiler_, title, record_samples));
+ current_profiles_.Add(new CpuProfile(profiler_, title, record_samples, mode));
current_profiles_semaphore_.Signal();
return true;
}
@@ -619,8 +682,8 @@ void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
}
void CpuProfilesCollection::AddPathToCurrentProfiles(
- base::TimeTicks timestamp, const std::vector& path,
- int src_line, bool update_stats) {
+ base::TimeTicks timestamp, const ProfileStackTrace& path, int src_line,
+ bool update_stats) {
// As starting / stopping profiles is rare relatively to this
// method, we don't bother minimizing the duration of lock holding,
// e.g. copying contents of the list to a local vector.
@@ -635,46 +698,52 @@ ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
: profiles_(profiles) {}
void ProfileGenerator::RecordTickSample(const TickSample& sample) {
- std::vector entries;
+ ProfileStackTrace stack_trace;
// Conservatively reserve space for stack frames + pc + function + vm-state.
// There could in fact be more of them because of inlined entries.
- entries.reserve(sample.frames_count + 3);
+ stack_trace.reserve(sample.frames_count + 3);
// The ProfileNode knows nothing about all versions of generated code for
// the same JS function. The line number information associated with
// the latest version of generated code is used to find a source line number
// for a JS function. Then, the detected source line is passed to
// ProfileNode to increase the tick count for this source line.
- int src_line = v8::CpuProfileNode::kNoLineNumberInfo;
+ const int no_line_info = v8::CpuProfileNode::kNoLineNumberInfo;
+ int src_line = no_line_info;
bool src_line_not_found = true;
if (sample.pc != nullptr) {
if (sample.has_external_callback && sample.state == EXTERNAL) {
// Don't use PC when in external callback code, as it can point
- // inside callback's code, and we will erroneously report
+ // inside a callback's code, and we will erroneously report
// that a callback calls itself.
- entries.push_back(FindEntry(sample.external_callback_entry));
+ stack_trace.push_back(
+ {FindEntry(reinterpret_cast(sample.external_callback_entry)),
+ no_line_info});
} else {
- CodeEntry* pc_entry = FindEntry(sample.pc);
- // If there is no pc_entry we're likely in native code.
- // Find out, if top of stack was pointing inside a JS function
- // meaning that we have encountered a frameless invocation.
+ Address attributed_pc = reinterpret_cast(sample.pc);
+ CodeEntry* pc_entry = FindEntry(attributed_pc);
+ // If there is no pc_entry, we're likely in native code. Find out if the
+ // top of the stack (the return address) was pointing inside a JS
+ // function, meaning that we have encountered a frameless invocation.
if (!pc_entry && !sample.has_external_callback) {
- pc_entry = FindEntry(sample.tos);
+ attributed_pc = reinterpret_cast(sample.tos);
+ pc_entry = FindEntry(attributed_pc);
}
// If pc is in the function code before it set up stack frame or after the
- // frame was destroyed SafeStackFrameIterator incorrectly thinks that
- // ebp contains return address of the current function and skips caller's
- // frame. Check for this case and just skip such samples.
+ // frame was destroyed, SafeStackFrameIterator incorrectly thinks that
+ // ebp contains the return address of the current function and skips the
+ // caller's frame. Check for this case and just skip such samples.
if (pc_entry) {
- int pc_offset = static_cast(reinterpret_cast(sample.pc) -
- pc_entry->instruction_start());
+ int pc_offset =
+ static_cast(attributed_pc - pc_entry->instruction_start());
+ DCHECK_GE(pc_offset, 0);
src_line = pc_entry->GetSourceLine(pc_offset);
if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) {
src_line = pc_entry->line_number();
}
src_line_not_found = false;
- entries.push_back(pc_entry);
+ stack_trace.push_back({pc_entry, src_line});
if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply ||
pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) {
@@ -685,7 +754,8 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
// former case we don't so we simply replace the frame with
// 'unresolved' entry.
if (!sample.has_external_callback) {
- entries.push_back(CodeEntry::unresolved_entry());
+ stack_trace.push_back(
+ {CodeEntry::unresolved_entry(), no_line_info});
}
}
}
@@ -694,15 +764,21 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
for (unsigned i = 0; i < sample.frames_count; ++i) {
Address stack_pos = reinterpret_cast(sample.stack[i]);
CodeEntry* entry = FindEntry(stack_pos);
+ int line_number = no_line_info;
if (entry) {
// Find out if the entry has an inlining stack associated.
int pc_offset =
static_cast(stack_pos - entry->instruction_start());
- const std::vector* inline_stack =
+ DCHECK_GE(pc_offset, 0);
+ const std::vector>* inline_stack =
entry->GetInlineStack(pc_offset);
if (inline_stack) {
- entries.insert(entries.end(), inline_stack->rbegin(),
- inline_stack->rend());
+ std::transform(
+ inline_stack->rbegin(), inline_stack->rend(),
+ std::back_inserter(stack_trace),
+ [=](const std::unique_ptr& ptr) {
+ return CodeEntryAndLineNumber{ptr.get(), no_line_info};
+ });
}
// Skip unresolved frames (e.g. internal frame) and get source line of
// the first JS caller.
@@ -713,33 +789,30 @@ void ProfileGenerator::RecordTickSample(const TickSample& sample) {
}
src_line_not_found = false;
}
+ line_number = entry->GetSourceLine(pc_offset);
}
- entries.push_back(entry);
+ stack_trace.push_back({entry, line_number});
}
}
if (FLAG_prof_browser_mode) {
bool no_symbolized_entries = true;
- for (auto e : entries) {
- if (e != NULL) {
+ for (auto e : stack_trace) {
+ if (e.code_entry != nullptr) {
no_symbolized_entries = false;
break;
}
}
// If no frames were symbolized, put the VM state entry in.
if (no_symbolized_entries) {
- entries.push_back(EntryForVMState(sample.state));
+ stack_trace.push_back({EntryForVMState(sample.state), no_line_info});
}
}
- profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line,
+ profiles_->AddPathToCurrentProfiles(sample.timestamp, stack_trace, src_line,
sample.update_stats);
}
-CodeEntry* ProfileGenerator::FindEntry(void* address) {
- return code_map_.FindEntry(reinterpret_cast(address));
-}
-
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
diff --git a/deps/v8/src/profiler/profile-generator.h b/deps/v8/src/profiler/profile-generator.h
index ddd34b00a47e4b..f5b8ef39f26e67 100644
--- a/deps/v8/src/profiler/profile-generator.h
+++ b/deps/v8/src/profiler/profile-generator.h
@@ -5,9 +5,16 @@
#ifndef V8_PROFILER_PROFILE_GENERATOR_H_
#define V8_PROFILER_PROFILE_GENERATOR_H_
+#include
+#include
#include