[profiler] Surface VM & Embedder State
Add APIs to surface VMState and new EmbedderState to CpuProfile samples. EmbedderState: * An EmbedderState is defined as a value uint8_t and a v8::context used for filtering. * EmbedderStates are stack allocated by the embedder, construction and destruction set/unset the state to the isolate thread local top. * A v8::context is used to filter states that are added to a CpuProfile, if the CpuProfile do not have a ContextFilter set or if contexts do not match, state defaults to Empty. * v8:StateTag is already propagated all the way to a Sample, simply add an API to surface it. VMState: Change-Id: I7eed08907360b99b0ad20ddcff59c95c7076c85e Bug: chromium:1263871 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3188072 Auto-Submit: Corentin Pescheloche <cpescheloche@fb.com> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#78250}
This commit is contained in:
parent
e947712e2c
commit
2d087f237e
@ -445,6 +445,7 @@ filegroup(
|
|||||||
"include/v8-date.h",
|
"include/v8-date.h",
|
||||||
"include/v8-debug.h",
|
"include/v8-debug.h",
|
||||||
"include/v8-embedder-heap.h",
|
"include/v8-embedder-heap.h",
|
||||||
|
"include/v8-embedder-state-scope.h,
|
||||||
"include/v8-exception.h",
|
"include/v8-exception.h",
|
||||||
"include/v8-extension.h",
|
"include/v8-extension.h",
|
||||||
"include/v8-external.h",
|
"include/v8-external.h",
|
||||||
@ -1214,6 +1215,8 @@ filegroup(
|
|||||||
"src/execution/arguments.h",
|
"src/execution/arguments.h",
|
||||||
"src/execution/encoded-c-signature.cc",
|
"src/execution/encoded-c-signature.cc",
|
||||||
"src/execution/encoded-c-signature.h",
|
"src/execution/encoded-c-signature.h",
|
||||||
|
"src/execution/embedder-state.h",
|
||||||
|
"src/execution/embedder-state.cc",
|
||||||
"src/execution/execution.cc",
|
"src/execution/execution.cc",
|
||||||
"src/execution/execution.h",
|
"src/execution/execution.h",
|
||||||
"src/execution/frame-constants.h",
|
"src/execution/frame-constants.h",
|
||||||
|
3
BUILD.gn
3
BUILD.gn
@ -2487,6 +2487,7 @@ v8_header_set("v8_headers") {
|
|||||||
"include/v8-date.h",
|
"include/v8-date.h",
|
||||||
"include/v8-debug.h",
|
"include/v8-debug.h",
|
||||||
"include/v8-embedder-heap.h",
|
"include/v8-embedder-heap.h",
|
||||||
|
"include/v8-embedder-state-scope.h",
|
||||||
"include/v8-exception.h",
|
"include/v8-exception.h",
|
||||||
"include/v8-extension.h",
|
"include/v8-extension.h",
|
||||||
"include/v8-external.h",
|
"include/v8-external.h",
|
||||||
@ -2864,6 +2865,7 @@ v8_header_set("v8_internal_headers") {
|
|||||||
"src/diagnostics/unwinder.h",
|
"src/diagnostics/unwinder.h",
|
||||||
"src/execution/arguments-inl.h",
|
"src/execution/arguments-inl.h",
|
||||||
"src/execution/arguments.h",
|
"src/execution/arguments.h",
|
||||||
|
"src/execution/embedder-state.h",
|
||||||
"src/execution/encoded-c-signature.h",
|
"src/execution/encoded-c-signature.h",
|
||||||
"src/execution/execution.h",
|
"src/execution/execution.h",
|
||||||
"src/execution/frame-constants.h",
|
"src/execution/frame-constants.h",
|
||||||
@ -4079,6 +4081,7 @@ v8_source_set("v8_base_without_compiler") {
|
|||||||
"src/diagnostics/perf-jit.cc",
|
"src/diagnostics/perf-jit.cc",
|
||||||
"src/diagnostics/unwinder.cc",
|
"src/diagnostics/unwinder.cc",
|
||||||
"src/execution/arguments.cc",
|
"src/execution/arguments.cc",
|
||||||
|
"src/execution/embedder-state.cc",
|
||||||
"src/execution/encoded-c-signature.cc",
|
"src/execution/encoded-c-signature.cc",
|
||||||
"src/execution/execution.cc",
|
"src/execution/execution.cc",
|
||||||
"src/execution/frames.cc",
|
"src/execution/frames.cc",
|
||||||
|
48
include/v8-embedder-state-scope.h
Normal file
48
include/v8-embedder-state-scope.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_
|
||||||
|
#define INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "v8-context.h" // NOLINT(build/include_directory)
|
||||||
|
#include "v8-internal.h" // NOLINT(build/include_directory)
|
||||||
|
#include "v8-local-handle.h" // NOLINT(build/include_directory)
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
class EmbedderState;
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// A StateTag represents a possible state of the embedder.
|
||||||
|
enum class EmbedderStateTag : uint8_t {
|
||||||
|
EMPTY = 0,
|
||||||
|
// embedder can define any state in between
|
||||||
|
OTHER = UINT8_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
// A stack-allocated class that manages an embedder state on the isolate.
|
||||||
|
// After an EmbedderState scope has been created, a new embedder state will be
|
||||||
|
// pushed on the isolate stack.
|
||||||
|
class V8_EXPORT EmbedderStateScope {
|
||||||
|
public:
|
||||||
|
EmbedderStateScope(Isolate* isolate, Local<v8::Context> context,
|
||||||
|
EmbedderStateTag tag);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Declaring operator new and delete as deleted is not spec compliant.
|
||||||
|
// Therefore declare them private instead to disable dynamic alloc
|
||||||
|
void* operator new(size_t size);
|
||||||
|
void* operator new[](size_t size);
|
||||||
|
void operator delete(void*, size_t);
|
||||||
|
void operator delete[](void*, size_t);
|
||||||
|
|
||||||
|
std::unique_ptr<internal::EmbedderState> embedder_state_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
|
#endif // INCLUDE_V8_EMBEDDER_STATE_SCOPE_H_
|
@ -20,9 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
|
|
||||||
|
enum class EmbedderStateTag : uint8_t;
|
||||||
class HeapGraphNode;
|
class HeapGraphNode;
|
||||||
struct HeapStatsUpdate;
|
struct HeapStatsUpdate;
|
||||||
class Object;
|
class Object;
|
||||||
|
enum StateTag : int;
|
||||||
|
|
||||||
using NativeObject = void*;
|
using NativeObject = void*;
|
||||||
using SnapshotObjectId = uint32_t;
|
using SnapshotObjectId = uint32_t;
|
||||||
@ -210,6 +212,16 @@ class V8_EXPORT CpuProfile {
|
|||||||
*/
|
*/
|
||||||
int64_t GetStartTime() const;
|
int64_t GetStartTime() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns state of the vm when sample was captured.
|
||||||
|
*/
|
||||||
|
StateTag GetSampleState(int index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns state of the embedder when sample was captured.
|
||||||
|
*/
|
||||||
|
EmbedderStateTag GetSampleEmbedderState(int index) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns time when the profile recording was stopped (in microseconds)
|
* Returns time when the profile recording was stopped (in microseconds)
|
||||||
* since some unspecified starting point.
|
* since some unspecified starting point.
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "v8config.h" // NOLINT(build/include_directory)
|
#include "v8-embedder-state-scope.h" // NOLINT(build/include_directory)
|
||||||
|
#include "v8config.h" // NOLINT(build/include_directory)
|
||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
// Holds the callee saved registers needed for the stack unwinder. It is the
|
// Holds the callee saved registers needed for the stack unwinder. It is the
|
||||||
@ -32,7 +33,7 @@ struct V8_EXPORT RegisterState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// A StateTag represents a possible state of the VM.
|
// A StateTag represents a possible state of the VM.
|
||||||
enum StateTag {
|
enum StateTag : int {
|
||||||
JS,
|
JS,
|
||||||
GC,
|
GC,
|
||||||
PARSER,
|
PARSER,
|
||||||
@ -46,11 +47,13 @@ enum StateTag {
|
|||||||
|
|
||||||
// The output structure filled up by GetStackSample API function.
|
// The output structure filled up by GetStackSample API function.
|
||||||
struct SampleInfo {
|
struct SampleInfo {
|
||||||
size_t frames_count; // Number of frames collected.
|
size_t frames_count; // Number of frames collected.
|
||||||
StateTag vm_state; // Current VM state.
|
void* external_callback_entry; // External callback address if VM is
|
||||||
void* external_callback_entry; // External callback address if VM is
|
// executing an external callback.
|
||||||
// executing an external callback.
|
void* context; // Incumbent native context address.
|
||||||
void* context; // Incumbent native context address.
|
void* embedder_context; // Native context address for embedder state
|
||||||
|
StateTag vm_state; // Current VM state.
|
||||||
|
EmbedderStateTag embedder_state; // Current Embedder state
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemoryRange {
|
struct MemoryRange {
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "include/v8-callbacks.h"
|
#include "include/v8-callbacks.h"
|
||||||
#include "include/v8-cppgc.h"
|
#include "include/v8-cppgc.h"
|
||||||
#include "include/v8-date.h"
|
#include "include/v8-date.h"
|
||||||
|
#include "include/v8-embedder-state-scope.h"
|
||||||
#include "include/v8-extension.h"
|
#include "include/v8-extension.h"
|
||||||
#include "include/v8-fast-api-calls.h"
|
#include "include/v8-fast-api-calls.h"
|
||||||
#include "include/v8-function.h"
|
#include "include/v8-function.h"
|
||||||
@ -46,6 +47,7 @@
|
|||||||
#include "src/debug/liveedit.h"
|
#include "src/debug/liveedit.h"
|
||||||
#include "src/deoptimizer/deoptimizer.h"
|
#include "src/deoptimizer/deoptimizer.h"
|
||||||
#include "src/diagnostics/gdb-jit.h"
|
#include "src/diagnostics/gdb-jit.h"
|
||||||
|
#include "src/execution/embedder-state.h"
|
||||||
#include "src/execution/execution.h"
|
#include "src/execution/execution.h"
|
||||||
#include "src/execution/frames-inl.h"
|
#include "src/execution/frames-inl.h"
|
||||||
#include "src/execution/isolate-inl.h"
|
#include "src/execution/isolate-inl.h"
|
||||||
@ -9863,6 +9865,16 @@ int64_t CpuProfile::GetSampleTimestamp(int index) const {
|
|||||||
return profile->sample(index).timestamp.since_origin().InMicroseconds();
|
return profile->sample(index).timestamp.since_origin().InMicroseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StateTag CpuProfile::GetSampleState(int index) const {
|
||||||
|
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
|
||||||
|
return profile->sample(index).state_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmbedderStateTag CpuProfile::GetSampleEmbedderState(int index) const {
|
||||||
|
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
|
||||||
|
return profile->sample(index).embedder_state_tag;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t CpuProfile::GetStartTime() const {
|
int64_t CpuProfile::GetStartTime() const {
|
||||||
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
|
const i::CpuProfile* profile = reinterpret_cast<const i::CpuProfile*>(this);
|
||||||
return profile->start_time().since_origin().InMicroseconds();
|
return profile->start_time().since_origin().InMicroseconds();
|
||||||
@ -10331,6 +10343,11 @@ void EmbedderHeapTracer::ResetHandleInNonTracingGC(
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmbedderStateScope::EmbedderStateScope(Isolate* isolate,
|
||||||
|
Local<v8::Context> context,
|
||||||
|
EmbedderStateTag tag)
|
||||||
|
: embedder_state_(new internal::EmbedderState(isolate, context, tag)) {}
|
||||||
|
|
||||||
void TracedReferenceBase::CheckValue() const {
|
void TracedReferenceBase::CheckValue() const {
|
||||||
#ifdef V8_HOST_ARCH_64_BIT
|
#ifdef V8_HOST_ARCH_64_BIT
|
||||||
if (!val_) return;
|
if (!val_) return;
|
||||||
|
45
src/execution/embedder-state.cc
Normal file
45
src/execution/embedder-state.cc
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "src/execution/embedder-state.h"
|
||||||
|
|
||||||
|
#include "src/api/api-inl.h"
|
||||||
|
#include "src/base/logging.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
EmbedderState::EmbedderState(v8::Isolate* isolate, Local<v8::Context> context,
|
||||||
|
EmbedderStateTag tag)
|
||||||
|
: isolate_(reinterpret_cast<i::Isolate*>(isolate)),
|
||||||
|
tag_(tag),
|
||||||
|
previous_embedder_state_(isolate_->current_embedder_state()) {
|
||||||
|
if (!context.IsEmpty()) {
|
||||||
|
native_context_address_ =
|
||||||
|
v8::Utils::OpenHandle(*context)->native_context().address();
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_NE(this, isolate_->current_embedder_state());
|
||||||
|
isolate_->set_current_embedder_state(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmbedderState::~EmbedderState() {
|
||||||
|
DCHECK_EQ(this, isolate_->current_embedder_state());
|
||||||
|
isolate_->set_current_embedder_state(previous_embedder_state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmbedderState::OnMoveEvent(Address from, Address to) {
|
||||||
|
EmbedderState* state = this;
|
||||||
|
do {
|
||||||
|
if (state->native_context_address_ == from) {
|
||||||
|
native_context_address_ = to;
|
||||||
|
}
|
||||||
|
state = state->previous_embedder_state_;
|
||||||
|
} while (state != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
} // namespace v8
|
39
src/execution/embedder-state.h
Normal file
39
src/execution/embedder-state.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef V8_EXECUTION_EMBEDDER_STATE_H_
|
||||||
|
#define V8_EXECUTION_EMBEDDER_STATE_H_
|
||||||
|
|
||||||
|
#include "include/v8-local-handle.h"
|
||||||
|
#include "src/execution/isolate.h"
|
||||||
|
|
||||||
|
namespace v8 {
|
||||||
|
|
||||||
|
enum class EmbedderStateTag : uint8_t;
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
class V8_EXPORT_PRIVATE EmbedderState {
|
||||||
|
public:
|
||||||
|
EmbedderState(v8::Isolate* isolate, Local<v8::Context> context,
|
||||||
|
EmbedderStateTag tag);
|
||||||
|
|
||||||
|
~EmbedderState();
|
||||||
|
|
||||||
|
EmbedderStateTag GetState() const { return tag_; }
|
||||||
|
|
||||||
|
Address native_context_address() const { return native_context_address_; }
|
||||||
|
|
||||||
|
void OnMoveEvent(Address from, Address to);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Isolate* isolate_;
|
||||||
|
EmbedderStateTag tag_;
|
||||||
|
Address native_context_address_ = kNullAddress;
|
||||||
|
EmbedderState* previous_embedder_state_;
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
} // namespace v8
|
||||||
|
|
||||||
|
#endif // V8_EXECUTION_EMBEDDER_STATE_H_
|
@ -65,6 +65,8 @@ class V8Inspector;
|
|||||||
|
|
||||||
namespace v8 {
|
namespace v8 {
|
||||||
|
|
||||||
|
class EmbedderState;
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class RandomNumberGenerator;
|
class RandomNumberGenerator;
|
||||||
} // namespace base
|
} // namespace base
|
||||||
@ -1300,6 +1302,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
|||||||
THREAD_LOCAL_TOP_ACCESSOR(ExternalCallbackScope*, external_callback_scope)
|
THREAD_LOCAL_TOP_ACCESSOR(ExternalCallbackScope*, external_callback_scope)
|
||||||
|
|
||||||
THREAD_LOCAL_TOP_ACCESSOR(StateTag, current_vm_state)
|
THREAD_LOCAL_TOP_ACCESSOR(StateTag, current_vm_state)
|
||||||
|
THREAD_LOCAL_TOP_ACCESSOR(EmbedderState*, current_embedder_state)
|
||||||
|
|
||||||
void SetData(uint32_t slot, void* data) {
|
void SetData(uint32_t slot, void* data) {
|
||||||
DCHECK_LT(slot, Internals::kNumIsolateDataSlots);
|
DCHECK_LT(slot, Internals::kNumIsolateDataSlots);
|
||||||
|
@ -31,6 +31,7 @@ void ThreadLocalTop::Clear() {
|
|||||||
js_entry_sp_ = kNullAddress;
|
js_entry_sp_ = kNullAddress;
|
||||||
external_callback_scope_ = nullptr;
|
external_callback_scope_ = nullptr;
|
||||||
current_vm_state_ = EXTERNAL;
|
current_vm_state_ = EXTERNAL;
|
||||||
|
current_embedder_state_ = nullptr;
|
||||||
failed_access_check_callback_ = nullptr;
|
failed_access_check_callback_ = nullptr;
|
||||||
thread_in_wasm_flag_address_ = kNullAddress;
|
thread_in_wasm_flag_address_ = kNullAddress;
|
||||||
#ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING
|
#ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING
|
||||||
|
@ -23,6 +23,7 @@ class TryCatch;
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
class EmbedderState;
|
||||||
class ExternalCallbackScope;
|
class ExternalCallbackScope;
|
||||||
class Isolate;
|
class Isolate;
|
||||||
class PromiseOnStack;
|
class PromiseOnStack;
|
||||||
@ -34,9 +35,9 @@ class ThreadLocalTop {
|
|||||||
// refactor this to really consist of just Addresses and 32-bit
|
// refactor this to really consist of just Addresses and 32-bit
|
||||||
// integer fields.
|
// integer fields.
|
||||||
#ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING
|
#ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING
|
||||||
static constexpr uint32_t kSizeInBytes = 25 * kSystemPointerSize;
|
static constexpr uint32_t kSizeInBytes = 26 * kSystemPointerSize;
|
||||||
#else
|
#else
|
||||||
static constexpr uint32_t kSizeInBytes = 24 * kSystemPointerSize;
|
static constexpr uint32_t kSizeInBytes = 25 * kSystemPointerSize;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Does early low-level initialization that does not depend on the
|
// Does early low-level initialization that does not depend on the
|
||||||
@ -151,6 +152,7 @@ class ThreadLocalTop {
|
|||||||
// The external callback we're currently in.
|
// The external callback we're currently in.
|
||||||
ExternalCallbackScope* external_callback_scope_;
|
ExternalCallbackScope* external_callback_scope_;
|
||||||
StateTag current_vm_state_;
|
StateTag current_vm_state_;
|
||||||
|
EmbedderState* current_embedder_state_;
|
||||||
|
|
||||||
// Call back function to report unsafe JS accesses.
|
// Call back function to report unsafe JS accesses.
|
||||||
v8::FailedAccessCheckCallback failed_access_check_callback_;
|
v8::FailedAccessCheckCallback failed_access_check_callback_;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
|
#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
|
||||||
#include "src/debug/debug.h"
|
#include "src/debug/debug.h"
|
||||||
#include "src/deoptimizer/deoptimizer.h"
|
#include "src/deoptimizer/deoptimizer.h"
|
||||||
|
#include "src/execution/embedder-state.h"
|
||||||
#include "src/execution/isolate-utils-inl.h"
|
#include "src/execution/isolate-utils-inl.h"
|
||||||
#include "src/execution/microtask-queue.h"
|
#include "src/execution/microtask-queue.h"
|
||||||
#include "src/execution/runtime-profiler.h"
|
#include "src/execution/runtime-profiler.h"
|
||||||
@ -3323,6 +3324,10 @@ void Heap::OnMoveEvent(HeapObject target, HeapObject source,
|
|||||||
LOG_CODE_EVENT(isolate_, SharedFunctionInfoMoveEvent(source.address(),
|
LOG_CODE_EVENT(isolate_, SharedFunctionInfoMoveEvent(source.address(),
|
||||||
target.address()));
|
target.address()));
|
||||||
} else if (target.IsNativeContext()) {
|
} else if (target.IsNativeContext()) {
|
||||||
|
if (isolate_->current_embedder_state() != nullptr) {
|
||||||
|
isolate_->current_embedder_state()->OnMoveEvent(source.address(),
|
||||||
|
target.address());
|
||||||
|
}
|
||||||
PROFILE(isolate_,
|
PROFILE(isolate_,
|
||||||
NativeContextMoveEvent(source.address(), target.address()));
|
NativeContextMoveEvent(source.address(), target.address()));
|
||||||
}
|
}
|
||||||
|
@ -230,12 +230,15 @@ void ProfilerEventsProcessor::CodeEventHandler(
|
|||||||
|
|
||||||
void SamplingEventsProcessor::SymbolizeAndAddToProfiles(
|
void SamplingEventsProcessor::SymbolizeAndAddToProfiles(
|
||||||
const TickSampleEventRecord* record) {
|
const TickSampleEventRecord* record) {
|
||||||
|
const TickSample& tick_sample = record->sample;
|
||||||
Symbolizer::SymbolizedSample symbolized =
|
Symbolizer::SymbolizedSample symbolized =
|
||||||
symbolizer_->SymbolizeTickSample(record->sample);
|
symbolizer_->SymbolizeTickSample(tick_sample);
|
||||||
profiles_->AddPathToCurrentProfiles(
|
profiles_->AddPathToCurrentProfiles(
|
||||||
record->sample.timestamp, symbolized.stack_trace, symbolized.src_line,
|
tick_sample.timestamp, symbolized.stack_trace, symbolized.src_line,
|
||||||
record->sample.update_stats_, record->sample.sampling_interval_,
|
tick_sample.update_stats_, tick_sample.sampling_interval_,
|
||||||
reinterpret_cast<Address>(record->sample.context));
|
tick_sample.state, tick_sample.embedder_state,
|
||||||
|
reinterpret_cast<Address>(tick_sample.context),
|
||||||
|
reinterpret_cast<Address>(tick_sample.embedder_context));
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilerEventsProcessor::SampleProcessingResult
|
ProfilerEventsProcessor::SampleProcessingResult
|
||||||
|
@ -620,7 +620,9 @@ bool CpuProfile::CheckSubsample(base::TimeDelta source_sampling_interval) {
|
|||||||
|
|
||||||
void CpuProfile::AddPath(base::TimeTicks timestamp,
|
void CpuProfile::AddPath(base::TimeTicks timestamp,
|
||||||
const ProfileStackTrace& path, int src_line,
|
const ProfileStackTrace& path, int src_line,
|
||||||
bool update_stats, base::TimeDelta sampling_interval) {
|
bool update_stats, base::TimeDelta sampling_interval,
|
||||||
|
StateTag state_tag,
|
||||||
|
EmbedderStateTag embedder_state_tag) {
|
||||||
if (!CheckSubsample(sampling_interval)) return;
|
if (!CheckSubsample(sampling_interval)) return;
|
||||||
|
|
||||||
ProfileNode* top_frame_node =
|
ProfileNode* top_frame_node =
|
||||||
@ -632,7 +634,8 @@ void CpuProfile::AddPath(base::TimeTicks timestamp,
|
|||||||
samples_.size() < options_.max_samples());
|
samples_.size() < options_.max_samples());
|
||||||
|
|
||||||
if (should_record_sample) {
|
if (should_record_sample) {
|
||||||
samples_.push_back({top_frame_node, timestamp, src_line});
|
samples_.push_back(
|
||||||
|
{top_frame_node, timestamp, src_line, state_tag, embedder_state_tag});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!should_record_sample && delegate_ != nullptr) {
|
if (!should_record_sample && delegate_ != nullptr) {
|
||||||
@ -988,19 +991,26 @@ base::TimeDelta CpuProfilesCollection::GetCommonSamplingInterval() const {
|
|||||||
|
|
||||||
void CpuProfilesCollection::AddPathToCurrentProfiles(
|
void CpuProfilesCollection::AddPathToCurrentProfiles(
|
||||||
base::TimeTicks timestamp, const ProfileStackTrace& path, int src_line,
|
base::TimeTicks timestamp, const ProfileStackTrace& path, int src_line,
|
||||||
bool update_stats, base::TimeDelta sampling_interval,
|
bool update_stats, base::TimeDelta sampling_interval, StateTag state,
|
||||||
Address native_context_address) {
|
EmbedderStateTag embedder_state_tag, Address native_context_address,
|
||||||
|
Address embedder_native_context_address) {
|
||||||
// As starting / stopping profiles is rare relatively to this
|
// As starting / stopping profiles is rare relatively to this
|
||||||
// method, we don't bother minimizing the duration of lock holding,
|
// method, we don't bother minimizing the duration of lock holding,
|
||||||
// e.g. copying contents of the list to a local vector.
|
// e.g. copying contents of the list to a local vector.
|
||||||
current_profiles_semaphore_.Wait();
|
current_profiles_semaphore_.Wait();
|
||||||
const ProfileStackTrace empty_path;
|
const ProfileStackTrace empty_path;
|
||||||
for (const std::unique_ptr<CpuProfile>& profile : current_profiles_) {
|
for (const std::unique_ptr<CpuProfile>& profile : current_profiles_) {
|
||||||
|
ContextFilter& context_filter = profile->context_filter();
|
||||||
// If the context filter check failed, omit the contents of the stack.
|
// If the context filter check failed, omit the contents of the stack.
|
||||||
bool accepts_context =
|
bool accepts_context = context_filter.Accept(native_context_address);
|
||||||
profile->context_filter().Accept(native_context_address);
|
bool accepts_embedder_context =
|
||||||
|
context_filter.native_context_address() != kNullAddress &&
|
||||||
|
context_filter.native_context_address() ==
|
||||||
|
embedder_native_context_address;
|
||||||
profile->AddPath(timestamp, accepts_context ? path : empty_path, src_line,
|
profile->AddPath(timestamp, accepts_context ? path : empty_path, src_line,
|
||||||
update_stats, sampling_interval);
|
update_stats, sampling_interval, state,
|
||||||
|
accepts_embedder_context ? embedder_state_tag
|
||||||
|
: EmbedderStateTag::EMPTY);
|
||||||
}
|
}
|
||||||
current_profiles_semaphore_.Signal();
|
current_profiles_semaphore_.Signal();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "include/v8-profiler.h"
|
#include "include/v8-profiler.h"
|
||||||
#include "src/base/platform/time.h"
|
#include "src/base/platform/time.h"
|
||||||
#include "src/builtins/builtins.h"
|
#include "src/builtins/builtins.h"
|
||||||
|
#include "src/execution/vm-state.h"
|
||||||
#include "src/logging/code-events.h"
|
#include "src/logging/code-events.h"
|
||||||
#include "src/profiler/strings-storage.h"
|
#include "src/profiler/strings-storage.h"
|
||||||
#include "src/utils/allocation.h"
|
#include "src/utils/allocation.h"
|
||||||
@ -405,6 +406,8 @@ class CpuProfile {
|
|||||||
ProfileNode* node;
|
ProfileNode* node;
|
||||||
base::TimeTicks timestamp;
|
base::TimeTicks timestamp;
|
||||||
int line;
|
int line;
|
||||||
|
StateTag state_tag;
|
||||||
|
EmbedderStateTag embedder_state_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
V8_EXPORT_PRIVATE CpuProfile(
|
V8_EXPORT_PRIVATE CpuProfile(
|
||||||
@ -419,7 +422,8 @@ class CpuProfile {
|
|||||||
// Add pc -> ... -> main() call path to the profile.
|
// Add pc -> ... -> main() call path to the profile.
|
||||||
void AddPath(base::TimeTicks timestamp, const ProfileStackTrace& path,
|
void AddPath(base::TimeTicks timestamp, const ProfileStackTrace& path,
|
||||||
int src_line, bool update_stats,
|
int src_line, bool update_stats,
|
||||||
base::TimeDelta sampling_interval);
|
base::TimeDelta sampling_interval, StateTag state,
|
||||||
|
EmbedderStateTag embedder_state);
|
||||||
void FinishProfile();
|
void FinishProfile();
|
||||||
|
|
||||||
const char* title() const { return title_; }
|
const char* title() const { return title_; }
|
||||||
@ -554,11 +558,12 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
|
|||||||
base::TimeDelta GetCommonSamplingInterval() const;
|
base::TimeDelta GetCommonSamplingInterval() const;
|
||||||
|
|
||||||
// Called from profile generator thread.
|
// Called from profile generator thread.
|
||||||
void AddPathToCurrentProfiles(base::TimeTicks timestamp,
|
void AddPathToCurrentProfiles(
|
||||||
const ProfileStackTrace& path, int src_line,
|
base::TimeTicks timestamp, const ProfileStackTrace& path, int src_line,
|
||||||
bool update_stats,
|
bool update_stats, base::TimeDelta sampling_interval, StateTag state,
|
||||||
base::TimeDelta sampling_interval,
|
EmbedderStateTag embedder_state_tag,
|
||||||
Address native_context_address = kNullAddress);
|
Address native_context_address = kNullAddress,
|
||||||
|
Address native_embedder_context_address = kNullAddress);
|
||||||
|
|
||||||
// Called from profile generator thread.
|
// Called from profile generator thread.
|
||||||
void UpdateNativeContextAddressForCurrentProfiles(Address from, Address to);
|
void UpdateNativeContextAddressForCurrentProfiles(Address from, Address to);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "include/v8-profiler.h"
|
#include "include/v8-profiler.h"
|
||||||
#include "src/base/sanitizer/asan.h"
|
#include "src/base/sanitizer/asan.h"
|
||||||
#include "src/base/sanitizer/msan.h"
|
#include "src/base/sanitizer/msan.h"
|
||||||
|
#include "src/execution/embedder-state.h"
|
||||||
#include "src/execution/frames-inl.h"
|
#include "src/execution/frames-inl.h"
|
||||||
#include "src/execution/simulator.h"
|
#include "src/execution/simulator.h"
|
||||||
#include "src/execution/vm-state-inl.h"
|
#include "src/execution/vm-state-inl.h"
|
||||||
@ -178,6 +179,8 @@ DISABLE_ASAN void TickSample::Init(Isolate* v8_isolate,
|
|||||||
frames_count = static_cast<unsigned>(info.frames_count);
|
frames_count = static_cast<unsigned>(info.frames_count);
|
||||||
has_external_callback = info.external_callback_entry != nullptr;
|
has_external_callback = info.external_callback_entry != nullptr;
|
||||||
context = info.context;
|
context = info.context;
|
||||||
|
embedder_context = info.embedder_context;
|
||||||
|
embedder_state = info.embedder_state;
|
||||||
if (has_external_callback) {
|
if (has_external_callback) {
|
||||||
external_callback_entry = info.external_callback_entry;
|
external_callback_entry = info.external_callback_entry;
|
||||||
} else if (frames_count) {
|
} else if (frames_count) {
|
||||||
@ -210,6 +213,14 @@ bool TickSample::GetStackSample(Isolate* v8_isolate, RegisterState* regs,
|
|||||||
sample_info->frames_count = 0;
|
sample_info->frames_count = 0;
|
||||||
sample_info->vm_state = isolate->current_vm_state();
|
sample_info->vm_state = isolate->current_vm_state();
|
||||||
sample_info->external_callback_entry = nullptr;
|
sample_info->external_callback_entry = nullptr;
|
||||||
|
sample_info->embedder_state = EmbedderStateTag::EMPTY;
|
||||||
|
|
||||||
|
EmbedderState* embedder_state = isolate->current_embedder_state();
|
||||||
|
if (embedder_state != nullptr) {
|
||||||
|
sample_info->embedder_context =
|
||||||
|
reinterpret_cast<void*>(embedder_state->native_context_address());
|
||||||
|
sample_info->embedder_state = embedder_state->GetState();
|
||||||
|
}
|
||||||
sample_info->context = nullptr;
|
sample_info->context = nullptr;
|
||||||
if (sample_info->vm_state == GC) return true;
|
if (sample_info->vm_state == GC) return true;
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ struct V8_EXPORT TickSample {
|
|||||||
|
|
||||||
TickSample()
|
TickSample()
|
||||||
: state(OTHER),
|
: state(OTHER),
|
||||||
|
embedder_state(EmbedderStateTag::EMPTY),
|
||||||
pc(nullptr),
|
pc(nullptr),
|
||||||
external_callback_entry(nullptr),
|
external_callback_entry(nullptr),
|
||||||
frames_count(0),
|
frames_count(0),
|
||||||
@ -82,6 +83,7 @@ struct V8_EXPORT TickSample {
|
|||||||
void print() const;
|
void print() const;
|
||||||
|
|
||||||
StateTag state; // The state of the VM.
|
StateTag state; // The state of the VM.
|
||||||
|
EmbedderStateTag embedder_state;
|
||||||
void* pc; // Instruction pointer.
|
void* pc; // Instruction pointer.
|
||||||
union {
|
union {
|
||||||
void* tos; // Top stack value (*sp).
|
void* tos; // Top stack value (*sp).
|
||||||
@ -91,6 +93,7 @@ struct V8_EXPORT TickSample {
|
|||||||
static const unsigned kMaxFramesCount = (1 << kMaxFramesCountLog2) - 1;
|
static const unsigned kMaxFramesCount = (1 << kMaxFramesCountLog2) - 1;
|
||||||
void* stack[kMaxFramesCount]; // Call stack.
|
void* stack[kMaxFramesCount]; // Call stack.
|
||||||
void* context = nullptr; // Address of the incumbent native context.
|
void* context = nullptr; // Address of the incumbent native context.
|
||||||
|
void* embedder_context = nullptr; // Address of the embedder native context.
|
||||||
unsigned frames_count : kMaxFramesCountLog2; // Number of captured frames.
|
unsigned frames_count : kMaxFramesCountLog2; // Number of captured frames.
|
||||||
bool has_external_callback : 1;
|
bool has_external_callback : 1;
|
||||||
bool update_stats_ : 1; // Whether the sample should update aggregated stats.
|
bool update_stats_ : 1; // Whether the sample should update aggregated stats.
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "src/codegen/compilation-cache.h"
|
#include "src/codegen/compilation-cache.h"
|
||||||
#include "src/codegen/source-position-table.h"
|
#include "src/codegen/source-position-table.h"
|
||||||
#include "src/deoptimizer/deoptimizer.h"
|
#include "src/deoptimizer/deoptimizer.h"
|
||||||
|
#include "src/execution/embedder-state.h"
|
||||||
#include "src/heap/spaces.h"
|
#include "src/heap/spaces.h"
|
||||||
#include "src/init/v8.h"
|
#include "src/init/v8.h"
|
||||||
#include "src/libplatform/default-platform.h"
|
#include "src/libplatform/default-platform.h"
|
||||||
@ -3922,6 +3923,216 @@ TEST(ContextIsolation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that embedder states from other contexts aren't recorded
|
||||||
|
TEST(EmbedderContextIsolation) {
|
||||||
|
i::FLAG_allow_natives_syntax = true;
|
||||||
|
LocalContext execution_env;
|
||||||
|
i::HandleScope scope(CcTest::i_isolate());
|
||||||
|
|
||||||
|
v8::Isolate* isolate = execution_env.local()->GetIsolate();
|
||||||
|
|
||||||
|
// Install CollectSample callback for more deterministic sampling.
|
||||||
|
v8::Local<v8::FunctionTemplate> func_template =
|
||||||
|
v8::FunctionTemplate::New(isolate, CallCollectSample);
|
||||||
|
v8::Local<v8::Function> func =
|
||||||
|
func_template->GetFunction(execution_env.local()).ToLocalChecked();
|
||||||
|
func->SetName(v8_str("CallCollectSample"));
|
||||||
|
execution_env->Global()
|
||||||
|
->Set(execution_env.local(), v8_str("CallCollectSample"), func)
|
||||||
|
.FromJust();
|
||||||
|
|
||||||
|
v8::Local<v8::Context> diff_context = v8::Context::New(isolate);
|
||||||
|
{
|
||||||
|
CHECK_NULL(CcTest::i_isolate()->current_embedder_state());
|
||||||
|
// prepare other embedder state
|
||||||
|
EmbedderStateScope scope(isolate, diff_context, EmbedderStateTag::OTHER);
|
||||||
|
CHECK_EQ(CcTest::i_isolate()->current_embedder_state()->GetState(),
|
||||||
|
EmbedderStateTag::OTHER);
|
||||||
|
|
||||||
|
ProfilerHelper helper(execution_env.local());
|
||||||
|
CompileRun(R"(
|
||||||
|
function optimized() {
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
function unoptimized() {
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
// Test optimized functions
|
||||||
|
%PrepareFunctionForOptimization(optimized);
|
||||||
|
optimized();
|
||||||
|
optimized();
|
||||||
|
%OptimizeFunctionOnNextCall(optimized);
|
||||||
|
optimized();
|
||||||
|
|
||||||
|
// Test unoptimized functions
|
||||||
|
%NeverOptimizeFunction(unoptimized);
|
||||||
|
unoptimized();
|
||||||
|
|
||||||
|
// Test callback
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
v8::Local<v8::Function> function =
|
||||||
|
GetFunction(execution_env.local(), "start");
|
||||||
|
|
||||||
|
v8::CpuProfile* profile = helper.Run(
|
||||||
|
function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||||
|
v8::CpuProfilingOptions::kNoSampleLimit, execution_env.local());
|
||||||
|
for (int i = 0; i < profile->GetSamplesCount(); i++) {
|
||||||
|
CHECK_EQ(profile->GetSampleEmbedderState(i), EmbedderStateTag::EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_NULL(CcTest::i_isolate()->current_embedder_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that embedder states from same context are recorded
|
||||||
|
TEST(EmbedderStatePropagate) {
|
||||||
|
i::FLAG_allow_natives_syntax = true;
|
||||||
|
LocalContext execution_env;
|
||||||
|
i::HandleScope scope(CcTest::i_isolate());
|
||||||
|
|
||||||
|
v8::Isolate* isolate = execution_env.local()->GetIsolate();
|
||||||
|
|
||||||
|
// Install CollectSample callback for more deterministic sampling.
|
||||||
|
v8::Local<v8::FunctionTemplate> func_template =
|
||||||
|
v8::FunctionTemplate::New(isolate, CallCollectSample);
|
||||||
|
v8::Local<v8::Function> func =
|
||||||
|
func_template->GetFunction(execution_env.local()).ToLocalChecked();
|
||||||
|
func->SetName(v8_str("CallCollectSample"));
|
||||||
|
execution_env->Global()
|
||||||
|
->Set(execution_env.local(), v8_str("CallCollectSample"), func)
|
||||||
|
.FromJust();
|
||||||
|
|
||||||
|
{
|
||||||
|
// prepare embedder state
|
||||||
|
EmbedderState embedderState(isolate, execution_env.local(),
|
||||||
|
EmbedderStateTag::OTHER);
|
||||||
|
CHECK_EQ(CcTest::i_isolate()->current_embedder_state(), &embedderState);
|
||||||
|
|
||||||
|
ProfilerHelper helper(execution_env.local());
|
||||||
|
CompileRun(R"(
|
||||||
|
function optimized() {
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
function unoptimized() {
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
// Test optimized functions
|
||||||
|
%PrepareFunctionForOptimization(optimized);
|
||||||
|
optimized();
|
||||||
|
optimized();
|
||||||
|
%OptimizeFunctionOnNextCall(optimized);
|
||||||
|
optimized();
|
||||||
|
|
||||||
|
// Test unoptimized functions
|
||||||
|
%NeverOptimizeFunction(unoptimized);
|
||||||
|
unoptimized();
|
||||||
|
|
||||||
|
// Test callback
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
v8::Local<v8::Function> function =
|
||||||
|
GetFunction(execution_env.local(), "start");
|
||||||
|
|
||||||
|
v8::CpuProfile* profile = helper.Run(
|
||||||
|
function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||||
|
v8::CpuProfilingOptions::kNoSampleLimit, execution_env.local());
|
||||||
|
|
||||||
|
for (int i = 0; i < profile->GetSamplesCount(); i++) {
|
||||||
|
CHECK_EQ(profile->GetSampleEmbedderState(i), EmbedderStateTag::OTHER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_NULL(CcTest::i_isolate()->current_embedder_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that embedder states from same context are recorded
|
||||||
|
// even after native context move
|
||||||
|
TEST(EmbedderStatePropagateNativeContextMove) {
|
||||||
|
// Reusing context addresses will cause this test to fail.
|
||||||
|
if (i::FLAG_gc_global || i::FLAG_stress_compaction ||
|
||||||
|
i::FLAG_stress_incremental_marking || i::FLAG_enable_third_party_heap) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i::FLAG_allow_natives_syntax = true;
|
||||||
|
i::FLAG_manual_evacuation_candidates_selection = true;
|
||||||
|
LocalContext execution_env;
|
||||||
|
i::HandleScope scope(CcTest::i_isolate());
|
||||||
|
|
||||||
|
v8::Isolate* isolate = execution_env.local()->GetIsolate();
|
||||||
|
|
||||||
|
// Install CollectSample callback for more deterministic sampling.
|
||||||
|
v8::Local<v8::FunctionTemplate> func_template =
|
||||||
|
v8::FunctionTemplate::New(isolate, CallCollectSample);
|
||||||
|
v8::Local<v8::Function> func =
|
||||||
|
func_template->GetFunction(execution_env.local()).ToLocalChecked();
|
||||||
|
func->SetName(v8_str("CallCollectSample"));
|
||||||
|
execution_env->Global()
|
||||||
|
->Set(execution_env.local(), v8_str("CallCollectSample"), func)
|
||||||
|
.FromJust();
|
||||||
|
|
||||||
|
{
|
||||||
|
// prepare embedder state
|
||||||
|
EmbedderState embedderState(isolate, execution_env.local(),
|
||||||
|
EmbedderStateTag::OTHER);
|
||||||
|
CHECK_EQ(CcTest::i_isolate()->current_embedder_state(), &embedderState);
|
||||||
|
|
||||||
|
i::Address initial_address =
|
||||||
|
reinterpret_cast<i::Address>(CcTest::i_isolate()
|
||||||
|
->current_embedder_state()
|
||||||
|
->native_context_address());
|
||||||
|
|
||||||
|
// Install a function that triggers the native context to be moved.
|
||||||
|
v8::Local<v8::FunctionTemplate> move_func_template =
|
||||||
|
v8::FunctionTemplate::New(
|
||||||
|
execution_env.local()->GetIsolate(),
|
||||||
|
[](const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||||
|
i::Isolate* isolate =
|
||||||
|
reinterpret_cast<i::Isolate*>(info.GetIsolate());
|
||||||
|
i::heap::ForceEvacuationCandidate(
|
||||||
|
i::Page::FromHeapObject(isolate->raw_native_context()));
|
||||||
|
CcTest::CollectAllGarbage();
|
||||||
|
});
|
||||||
|
v8::Local<v8::Function> move_func =
|
||||||
|
move_func_template->GetFunction(execution_env.local()).ToLocalChecked();
|
||||||
|
move_func->SetName(v8_str("ForceNativeContextMove"));
|
||||||
|
execution_env->Global()
|
||||||
|
->Set(execution_env.local(), v8_str("ForceNativeContextMove"),
|
||||||
|
move_func)
|
||||||
|
.FromJust();
|
||||||
|
|
||||||
|
ProfilerHelper helper(execution_env.local());
|
||||||
|
CompileRun(R"(
|
||||||
|
function start() {
|
||||||
|
ForceNativeContextMove();
|
||||||
|
CallCollectSample();
|
||||||
|
}
|
||||||
|
)");
|
||||||
|
v8::Local<v8::Function> function =
|
||||||
|
GetFunction(execution_env.local(), "start");
|
||||||
|
|
||||||
|
v8::CpuProfile* profile = helper.Run(
|
||||||
|
function, nullptr, 0, 0, 0, v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||||
|
v8::CpuProfilingOptions::kNoSampleLimit, execution_env.local());
|
||||||
|
|
||||||
|
for (int i = 0; i < profile->GetSamplesCount(); i++) {
|
||||||
|
CHECK_EQ(profile->GetSampleEmbedderState(i), EmbedderStateTag::OTHER);
|
||||||
|
}
|
||||||
|
i::Address new_address =
|
||||||
|
reinterpret_cast<i::Address>(CcTest::i_isolate()
|
||||||
|
->current_embedder_state()
|
||||||
|
->native_context_address());
|
||||||
|
CHECK_NE(initial_address, new_address);
|
||||||
|
}
|
||||||
|
CHECK_NULL(CcTest::i_isolate()->current_embedder_state());
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that when a native context that's being filtered is moved, we continue
|
// Tests that when a native context that's being filtered is moved, we continue
|
||||||
// to track its execution.
|
// to track its execution.
|
||||||
TEST(ContextFilterMovedNativeContext) {
|
TEST(ContextFilterMovedNativeContext) {
|
||||||
|
@ -482,9 +482,9 @@ TEST(SampleIds) {
|
|||||||
sample1.stack[0] = ToPointer(0x1510);
|
sample1.stack[0] = ToPointer(0x1510);
|
||||||
sample1.frames_count = 1;
|
sample1.frames_count = 1;
|
||||||
auto symbolized = symbolizer.SymbolizeTickSample(sample1);
|
auto symbolized = symbolizer.SymbolizeTickSample(sample1);
|
||||||
profiles.AddPathToCurrentProfiles(sample1.timestamp, symbolized.stack_trace,
|
profiles.AddPathToCurrentProfiles(
|
||||||
symbolized.src_line, true,
|
sample1.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||||
base::TimeDelta());
|
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||||
|
|
||||||
TickSample sample2;
|
TickSample sample2;
|
||||||
sample2.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
sample2.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
||||||
@ -494,9 +494,9 @@ TEST(SampleIds) {
|
|||||||
sample2.stack[2] = ToPointer(0x1620);
|
sample2.stack[2] = ToPointer(0x1620);
|
||||||
sample2.frames_count = 3;
|
sample2.frames_count = 3;
|
||||||
symbolized = symbolizer.SymbolizeTickSample(sample2);
|
symbolized = symbolizer.SymbolizeTickSample(sample2);
|
||||||
profiles.AddPathToCurrentProfiles(sample2.timestamp, symbolized.stack_trace,
|
profiles.AddPathToCurrentProfiles(
|
||||||
symbolized.src_line, true,
|
sample2.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||||
base::TimeDelta());
|
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||||
|
|
||||||
TickSample sample3;
|
TickSample sample3;
|
||||||
sample3.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
sample3.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
||||||
@ -505,9 +505,9 @@ TEST(SampleIds) {
|
|||||||
sample3.stack[1] = ToPointer(0x1610);
|
sample3.stack[1] = ToPointer(0x1610);
|
||||||
sample3.frames_count = 2;
|
sample3.frames_count = 2;
|
||||||
symbolized = symbolizer.SymbolizeTickSample(sample3);
|
symbolized = symbolizer.SymbolizeTickSample(sample3);
|
||||||
profiles.AddPathToCurrentProfiles(sample3.timestamp, symbolized.stack_trace,
|
profiles.AddPathToCurrentProfiles(
|
||||||
symbolized.src_line, true,
|
sample3.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||||
base::TimeDelta());
|
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||||
|
|
||||||
CpuProfile* profile = profiles.StopProfiling("");
|
CpuProfile* profile = profiles.StopProfiling("");
|
||||||
unsigned nodeId = 1;
|
unsigned nodeId = 1;
|
||||||
@ -603,9 +603,9 @@ TEST(MaxSamplesCallback) {
|
|||||||
sample1.stack[0] = ToPointer(0x1510);
|
sample1.stack[0] = ToPointer(0x1510);
|
||||||
sample1.frames_count = 1;
|
sample1.frames_count = 1;
|
||||||
auto symbolized = symbolizer.SymbolizeTickSample(sample1);
|
auto symbolized = symbolizer.SymbolizeTickSample(sample1);
|
||||||
profiles.AddPathToCurrentProfiles(sample1.timestamp, symbolized.stack_trace,
|
profiles.AddPathToCurrentProfiles(
|
||||||
symbolized.src_line, true,
|
sample1.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||||
base::TimeDelta());
|
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||||
CHECK_EQ(0, mock_platform->posted_count());
|
CHECK_EQ(0, mock_platform->posted_count());
|
||||||
TickSample sample2;
|
TickSample sample2;
|
||||||
sample2.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
sample2.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
||||||
@ -613,18 +613,18 @@ TEST(MaxSamplesCallback) {
|
|||||||
sample2.stack[0] = ToPointer(0x1780);
|
sample2.stack[0] = ToPointer(0x1780);
|
||||||
sample2.frames_count = 2;
|
sample2.frames_count = 2;
|
||||||
symbolized = symbolizer.SymbolizeTickSample(sample2);
|
symbolized = symbolizer.SymbolizeTickSample(sample2);
|
||||||
profiles.AddPathToCurrentProfiles(sample2.timestamp, symbolized.stack_trace,
|
profiles.AddPathToCurrentProfiles(
|
||||||
symbolized.src_line, true,
|
sample2.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||||
base::TimeDelta());
|
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||||
CHECK_EQ(1, mock_platform->posted_count());
|
CHECK_EQ(1, mock_platform->posted_count());
|
||||||
TickSample sample3;
|
TickSample sample3;
|
||||||
sample3.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
sample3.timestamp = v8::base::TimeTicks::HighResolutionNow();
|
||||||
sample3.pc = ToPointer(0x1510);
|
sample3.pc = ToPointer(0x1510);
|
||||||
sample3.frames_count = 3;
|
sample3.frames_count = 3;
|
||||||
symbolized = symbolizer.SymbolizeTickSample(sample3);
|
symbolized = symbolizer.SymbolizeTickSample(sample3);
|
||||||
profiles.AddPathToCurrentProfiles(sample3.timestamp, symbolized.stack_trace,
|
profiles.AddPathToCurrentProfiles(
|
||||||
symbolized.src_line, true,
|
sample3.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||||
base::TimeDelta());
|
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||||
CHECK_EQ(1, mock_platform->posted_count());
|
CHECK_EQ(1, mock_platform->posted_count());
|
||||||
|
|
||||||
// Teardown
|
// Teardown
|
||||||
@ -654,7 +654,8 @@ TEST(NoSamples) {
|
|||||||
auto symbolized = symbolizer.SymbolizeTickSample(sample1);
|
auto symbolized = symbolizer.SymbolizeTickSample(sample1);
|
||||||
profiles.AddPathToCurrentProfiles(v8::base::TimeTicks::HighResolutionNow(),
|
profiles.AddPathToCurrentProfiles(v8::base::TimeTicks::HighResolutionNow(),
|
||||||
symbolized.stack_trace, symbolized.src_line,
|
symbolized.stack_trace, symbolized.src_line,
|
||||||
true, base::TimeDelta());
|
true, base::TimeDelta(), StateTag::JS,
|
||||||
|
EmbedderStateTag::EMPTY);
|
||||||
|
|
||||||
CpuProfile* profile = profiles.StopProfiling("");
|
CpuProfile* profile = profiles.StopProfiling("");
|
||||||
unsigned nodeId = 1;
|
unsigned nodeId = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user