[cpu-profiler] Reference counting for code entries

To enable deallocation of CodeEntry objects after they're no longer
being referenced by an active profile or alive on the heap, replace the
|used| bit with a proper reference count maintained by a CodeMap.

Bug: v8:11054
Change-Id: Id3d5941e509504415692f833e406ecdd2553d426
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2945541
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Cr-Commit-Position: refs/heads/master@{#75164}
This commit is contained in:
Andrew Comminos 2021-06-14 12:39:57 -07:00 committed by V8 LUCI CQ
parent 7d468b70cd
commit 8e44ee5f75
11 changed files with 221 additions and 154 deletions

View File

@ -53,8 +53,8 @@ void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) {
if (builtin == Builtin::kGenericJSToWasmWrapper) {
// Make sure to add the generic js-to-wasm wrapper builtin, because that
// one is supposed to show up in profiles.
entry =
new CodeEntry(CodeEventListener::BUILTIN_TAG, Builtins::name(builtin));
entry = code_map->code_entries().Create(CodeEventListener::BUILTIN_TAG,
Builtins::name(builtin));
code_map->AddCode(instruction_start, entry, instruction_size);
}
#endif // V8_ENABLE_WEBASSEMBLY

View File

@ -336,9 +336,11 @@ void* SamplingEventsProcessor::operator new(size_t size) {
void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate)
ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate,
CodeEntryStorage& storage)
: isolate_(isolate),
code_map_(strings_),
code_entries_(storage),
code_map_(storage),
weak_code_registry_(isolate),
processor_(nullptr) {
CreateEntriesForRuntimeCallStats();
@ -350,7 +352,7 @@ void ProfilerCodeObserver::ClearCodeMap() {
code_map_.Clear();
// We don't currently expect any references to refcounted strings to be
// maintained with zero profiles after the code map is cleared.
DCHECK(strings_.empty());
DCHECK(code_entries_.strings().empty());
}
void ProfilerCodeObserver::CodeEventHandler(
@ -385,8 +387,8 @@ void ProfilerCodeObserver::CreateEntriesForRuntimeCallStats() {
for (int i = 0; i < RuntimeCallStats::kNumberOfCounters; ++i) {
RuntimeCallCounter* counter = rcs->GetCounter(i);
DCHECK(counter->name());
auto entry = new CodeEntry(CodeEventListener::FUNCTION_TAG, counter->name(),
"native V8Runtime");
auto entry = code_entries_.Create(CodeEventListener::FUNCTION_TAG,
counter->name(), "native V8Runtime");
code_map_.AddCode(reinterpret_cast<Address>(counter), entry, 1);
}
#endif // V8_RUNTIME_CALL_STATS
@ -473,7 +475,7 @@ CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode)
: CpuProfiler(isolate, naming_mode, logging_mode,
new CpuProfilesCollection(isolate), nullptr, nullptr,
new ProfilerCodeObserver(isolate)) {}
new ProfilerCodeObserver(isolate, code_entries_)) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode,
@ -529,7 +531,7 @@ void CpuProfiler::EnableLogging() {
if (!profiler_listener_) {
profiler_listener_.reset(new ProfilerListener(
isolate_, code_observer_.get(), *code_observer_->strings(),
isolate_, code_observer_.get(), *code_observer_->code_entries(),
*code_observer_->weak_code_registry(), naming_mode_));
}
profiling_scope_.reset(

View File

@ -256,17 +256,17 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
// low sampling intervals on Windows.
};
// Builds and maintains a CodeMap tracking code objects on the VM heap, as well
// as strings owned by them. While alive, logs generated code, callbacks, and
// builtins from the isolate. Redirects events to the profiler events
// processor when present.
// Builds and maintains a CodeMap tracking code objects on the VM heap. While
// alive, logs generated code, callbacks, and builtins from the isolate.
// Redirects events to the profiler events processor when present. CodeEntry
// lifetime is associated with the given CodeEntryStorage.
class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
public:
explicit ProfilerCodeObserver(Isolate*);
explicit ProfilerCodeObserver(Isolate*, CodeEntryStorage&);
void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
CodeEntryStorage* code_entries() { return &code_entries_; }
CodeMap* code_map() { return &code_map_; }
StringsStorage* strings() { return &strings_; }
WeakCodeRegistry* weak_code_registry() { return &weak_code_registry_; }
void ClearCodeMap();
@ -290,7 +290,7 @@ class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
void clear_processor() { processor_ = nullptr; }
Isolate* const isolate_;
StringsStorage strings_;
CodeEntryStorage& code_entries_;
CodeMap code_map_;
WeakCodeRegistry weak_code_registry_;
ProfilerEventsProcessor* processor_;
@ -361,6 +361,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
Symbolizer* symbolizer() const { return symbolizer_.get(); }
ProfilerEventsProcessor* processor() const { return processor_.get(); }
Isolate* isolate() const { return isolate_; }
CodeEntryStorage* code_entries() { return &code_entries_; }
ProfilerListener* profiler_listener_for_test() const {
return profiler_listener_.get();
@ -389,6 +390,11 @@ class V8_EXPORT_PRIVATE CpuProfiler {
// Sampling interval to which per-profile sampling intervals will be clamped
// to a multiple of, or used as the default if unspecified.
base::TimeDelta base_sampling_interval_;
// Storage for CodeEntry objects allocated by the profiler. May live for
// multiple profiling sessions, independent of heap listener state.
CodeEntryStorage code_entries_;
std::unique_ptr<ProfilerCodeObserver> code_observer_;
std::unique_ptr<CpuProfilesCollection> profiles_;
std::unique_ptr<Symbolizer> symbolizer_;

View File

@ -38,6 +38,7 @@ ProfileNode::ProfileNode(ProfileTree* tree, CodeEntry* entry,
parent_(parent),
id_(tree->next_node_id()) {
tree_->EnqueueNode(this);
if (tree_->code_entries()) tree_->code_entries()->AddRef(entry_);
}
inline Isolate* ProfileNode::isolate() const { return tree_->isolate(); }

View File

@ -231,6 +231,8 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() {
}
void CodeEntry::ReleaseStrings(StringsStorage& strings) {
DCHECK_EQ(ref_count_, 0UL);
if (name_) {
strings.Release(name_);
name_ = nullptr;
@ -296,6 +298,10 @@ void CodeEntry::print() const {
base::OS::Print("\n");
}
ProfileNode::~ProfileNode() {
if (tree_->code_entries()) tree_->code_entries()->DecRef(entry_);
}
CpuProfileNode::SourceType ProfileNode::source_type() const {
// Handle metadata and VM state code entry types.
if (entry_ == CodeEntry::program_entry() ||
@ -433,10 +439,11 @@ class DeleteNodesCallback {
void AfterChildTraversed(ProfileNode*, ProfileNode*) { }
};
ProfileTree::ProfileTree(Isolate* isolate)
ProfileTree::ProfileTree(Isolate* isolate, CodeEntryStorage* storage)
: next_node_id_(1),
root_(new ProfileNode(this, CodeEntry::root_entry(), nullptr)),
isolate_(isolate) {}
isolate_(isolate),
code_entries_(storage) {}
ProfileTree::~ProfileTree() {
DeleteNodesCallback cb;
@ -548,7 +555,7 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
options_(options),
delegate_(std::move(delegate)),
start_time_(base::TimeTicks::HighResolutionNow()),
top_down_(profiler->isolate()),
top_down_(profiler->isolate(), profiler->code_entries()),
profiler_(profiler),
streaming_next_sample_(0),
id_(++last_id_) {
@ -739,31 +746,32 @@ void CpuProfile::Print() const {
ProfilerStats::Instance()->Clear();
}
CodeMap::CodeMap(StringsStorage& function_and_resource_names)
: function_and_resource_names_(function_and_resource_names) {}
void CodeEntryStorage::AddRef(CodeEntry* entry) {
if (entry->is_ref_counted()) entry->AddRef();
}
void CodeEntryStorage::DecRef(CodeEntry* entry) {
if (entry->is_ref_counted() && entry->DecRef() == 0) {
entry->ReleaseStrings(function_and_resource_names_);
delete entry;
}
}
CodeMap::CodeMap(CodeEntryStorage& storage) : code_entries_(storage) {}
CodeMap::~CodeMap() { Clear(); }
void CodeMap::Clear() {
for (auto& slot : code_map_) {
if (CodeEntry* entry = slot.second.entry) {
entry->ReleaseStrings(function_and_resource_names_);
delete entry;
code_entries_.DecRef(entry);
} else {
// We expect all entries in the code mapping to contain a CodeEntry.
UNREACHABLE();
}
}
// Free all CodeEntry objects that are no longer in the map, but in a profile.
// TODO(acomminos): Remove this deque after we refcount CodeEntry objects.
for (CodeEntry* entry : used_entries_) {
DCHECK(entry->used());
DeleteCodeEntry(entry);
}
code_map_.clear();
used_entries_.clear();
}
void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
@ -775,11 +783,7 @@ bool CodeMap::RemoveCode(CodeEntry* entry) {
auto range = code_map_.equal_range(entry->instruction_start());
for (auto i = range.first; i != range.second; ++i) {
if (i->second.entry == entry) {
if (!entry->used()) {
DeleteCodeEntry(entry);
} else {
used_entries_.push_back(entry);
}
code_entries_.DecRef(entry);
code_map_.erase(i);
return true;
}
@ -795,11 +799,7 @@ void CodeMap::ClearCodesInRange(Address start, Address end) {
}
auto right = left;
for (; right != code_map_.end() && right->first < end; ++right) {
if (!right->second.entry->used()) {
DeleteCodeEntry(right->second.entry);
} else {
used_entries_.push_back(right->second.entry);
}
code_entries_.DecRef(right->second.entry);
}
code_map_.erase(left, right);
}
@ -842,11 +842,6 @@ void CodeMap::MoveCode(Address from, Address to) {
code_map_.erase(range.first, it);
}
void CodeMap::DeleteCodeEntry(CodeEntry* entry) {
entry->ReleaseStrings(function_and_resource_names_);
delete entry;
}
void CodeMap::Print() {
for (const auto& pair : code_map_) {
base::OS::Print("%p %5d %s\n", reinterpret_cast<void*>(pair.first),

View File

@ -76,6 +76,7 @@ class CodeEntry {
// No alive handles should be associated with the CodeEntry at time of
// destruction.
DCHECK(!heap_object_location_);
DCHECK_EQ(ref_count_, 0UL);
}
const char* name() const { return name_; }
@ -107,8 +108,6 @@ class CodeEntry {
rare_data_->deopt_reason_ = kNoDeoptReason;
rare_data_->deopt_id_ = kNoDeoptimizationId;
}
void mark_used() { bit_field_ = UsedField::update(bit_field_, true); }
bool used() const { return UsedField::decode(bit_field_); }
const char* code_type_string() const {
switch (CodeTypeField::decode(bit_field_)) {
@ -137,6 +136,10 @@ class CodeEntry {
return SharedCrossOriginField::decode(bit_field_);
}
// Returns whether or not the lifetime of this CodeEntry is reference
// counted, and managed by a CodeMap.
bool is_ref_counted() const { return RefCountedField::decode(bit_field_); }
uint32_t GetHash() const;
bool IsSameFunctionAs(const CodeEntry* entry) const;
@ -193,6 +196,8 @@ class CodeEntry {
void print() const;
private:
friend class CodeEntryStorage;
struct RareData {
const char* deopt_reason_ = kNoDeoptReason;
const char* bailout_reason_ = kEmptyBailoutReason;
@ -205,17 +210,35 @@ class CodeEntry {
RareData* EnsureRareData();
void mark_ref_counted() {
bit_field_ = RefCountedField::update(bit_field_, true);
ref_count_ = 1;
}
size_t AddRef() {
DCHECK(is_ref_counted());
DCHECK_LT(ref_count_, std::numeric_limits<size_t>::max());
ref_count_++;
return ref_count_;
}
size_t DecRef() {
DCHECK(is_ref_counted());
DCHECK_GT(ref_count_, 0UL);
ref_count_--;
return ref_count_;
}
using TagField = base::BitField<CodeEventListener::LogEventsAndTags, 0, 8>;
using BuiltinField = base::BitField<Builtin, 8, 20>;
static_assert(Builtins::kBuiltinCount <= BuiltinField::kNumValues,
"builtin_count exceeds size of bitfield");
using CodeTypeField = base::BitField<CodeType, 28, 2>;
using UsedField = base::BitField<bool, 30, 1>;
using RefCountedField = base::BitField<bool, 28, 1>;
using CodeTypeField = base::BitField<CodeType, 29, 2>;
using SharedCrossOriginField = base::BitField<bool, 31, 1>;
// Atomic because Used is written from the profiler thread while CodeType is
// read from the main thread.
std::atomic<std::uint32_t> bit_field_;
std::uint32_t bit_field_;
std::atomic<std::size_t> ref_count_ = {0};
const char* name_;
const char* resource_name_;
int line_number_;
@ -266,6 +289,7 @@ class V8_EXPORT_PRIVATE ProfileNode {
public:
inline ProfileNode(ProfileTree* tree, CodeEntry* entry, ProfileNode* parent,
int line_number = 0);
~ProfileNode();
ProfileNode(const ProfileNode&) = delete;
ProfileNode& operator=(const ProfileNode&) = delete;
@ -329,9 +353,11 @@ class V8_EXPORT_PRIVATE ProfileNode {
std::vector<CpuProfileDeoptInfo> deopt_infos_;
};
class CodeEntryStorage;
class V8_EXPORT_PRIVATE ProfileTree {
public:
explicit ProfileTree(Isolate* isolate);
explicit ProfileTree(Isolate* isolate, CodeEntryStorage* storage = nullptr);
~ProfileTree();
ProfileTree(const ProfileTree&) = delete;
ProfileTree& operator=(const ProfileTree&) = delete;
@ -360,6 +386,8 @@ class V8_EXPORT_PRIVATE ProfileTree {
return std::move(pending_nodes_);
}
CodeEntryStorage* code_entries() { return code_entries_; }
private:
template <typename Callback>
void TraverseDepthFirst(Callback* callback);
@ -369,6 +397,7 @@ class V8_EXPORT_PRIVATE ProfileTree {
unsigned next_node_id_;
ProfileNode* root_;
Isolate* isolate_;
CodeEntryStorage* code_entries_;
};
class CpuProfiler;
@ -450,13 +479,13 @@ class CpuProfileMaxSamplesCallbackTask : public v8::Task {
class V8_EXPORT_PRIVATE CodeMap {
public:
// Creates a new CodeMap with an associated StringsStorage to store the
// strings of CodeEntry objects within.
explicit CodeMap(StringsStorage& function_and_resource_names);
explicit CodeMap(CodeEntryStorage& storage);
~CodeMap();
CodeMap(const CodeMap&) = delete;
CodeMap& operator=(const CodeMap&) = delete;
// Adds the given CodeEntry to the CodeMap. The CodeMap takes ownership of
// the CodeEntry.
void AddCode(Address addr, CodeEntry* entry, unsigned size);
void MoveCode(Address from, Address to);
// Attempts to remove the given CodeEntry from the CodeMap.
@ -467,6 +496,8 @@ class V8_EXPORT_PRIVATE CodeMap {
void Print();
size_t size() const { return code_map_.size(); }
CodeEntryStorage& code_entries() { return code_entries_; }
void Clear();
private:
@ -475,12 +506,28 @@ class V8_EXPORT_PRIVATE CodeMap {
unsigned size;
};
void DeleteCodeEntry(CodeEntry*);
std::multimap<Address, CodeEntryMapInfo> code_map_;
std::deque<CodeEntry*> used_entries_; // Entries that are no longer in the
// map, but used by a profile.
StringsStorage& function_and_resource_names_;
CodeEntryStorage& code_entries_;
};
// Manages the lifetime of CodeEntry objects, and stores shared resources
// between them.
class V8_EXPORT_PRIVATE CodeEntryStorage {
public:
template <typename... Args>
static CodeEntry* Create(Args&&... args) {
CodeEntry* const entry = new CodeEntry(std::forward<Args>(args)...);
entry->mark_ref_counted();
return entry;
}
void AddRef(CodeEntry*);
void DecRef(CodeEntry*);
StringsStorage& strings() { return function_and_resource_names_; }
private:
StringsStorage function_and_resource_names_;
};
class V8_EXPORT_PRIVATE CpuProfilesCollection {

View File

@ -29,12 +29,12 @@ namespace internal {
ProfilerListener::ProfilerListener(Isolate* isolate,
CodeEventObserver* observer,
StringsStorage& function_and_resource_names,
CodeEntryStorage& code_entry_storage,
WeakCodeRegistry& weak_code_registry,
CpuProfilingNamingMode naming_mode)
: isolate_(isolate),
observer_(observer),
function_and_resource_names_(function_and_resource_names),
code_entries_(code_entry_storage),
weak_code_registry_(weak_code_registry),
naming_mode_(naming_mode) {}
@ -46,9 +46,10 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = code->InstructionStart();
rec->entry = new CodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);
rec->entry =
code_entries_.Create(tag, GetName(name), CodeEntry::kEmptyResourceName,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);
rec->instruction_size = code->InstructionSize();
weak_code_registry_.Track(rec->entry, code);
DispatchCodeEvent(evt_rec);
@ -60,9 +61,10 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = code->InstructionStart();
rec->entry = new CodeEntry(tag, GetName(*name), CodeEntry::kEmptyResourceName,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);
rec->entry =
code_entries_.Create(tag, GetName(*name), CodeEntry::kEmptyResourceName,
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);
rec->instruction_size = code->InstructionSize();
weak_code_registry_.Track(rec->entry, code);
DispatchCodeEvent(evt_rec);
@ -75,10 +77,11 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = code->InstructionStart();
rec->entry = new CodeEntry(tag, GetName(shared->DebugNameCStr().get()),
GetName(InferScriptName(*script_name, *shared)),
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);
rec->entry =
code_entries_.Create(tag, GetName(shared->DebugNameCStr().get()),
GetName(InferScriptName(*script_name, *shared)),
CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);
DCHECK_IMPLIES(code->IsCode(), code->kind() == CodeKind::BASELINE);
rec->entry->FillFunctionInfo(*shared);
rec->instruction_size = code->InstructionSize();
@ -91,10 +94,10 @@ namespace {
CodeEntry* GetOrInsertCachedEntry(
std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
CodeEntry::Equals>* entries,
std::unique_ptr<CodeEntry> search_value, StringsStorage& strings) {
std::unique_ptr<CodeEntry> search_value, CodeEntryStorage& storage) {
auto it = entries->find(search_value);
if (it != entries->end()) {
search_value->ReleaseStrings(strings);
search_value->ReleaseStrings(storage.strings());
return it->get();
}
CodeEntry* ret = search_value.get();
@ -204,8 +207,7 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
// Create a canonical CodeEntry for each inlined frame and then re-use
// them for subsequent inline stacks to avoid a lot of duplication.
CodeEntry* cached_entry = GetOrInsertCachedEntry(
&cached_inline_entries, std::move(inline_entry),
function_and_resource_names_);
&cached_inline_entries, std::move(inline_entry), code_entries_);
inline_stack.push_back({cached_entry, line_number});
}
@ -214,10 +216,10 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
}
}
}
rec->entry =
new CodeEntry(tag, GetFunctionName(*shared),
GetName(InferScriptName(*script_name, *shared)), line,
column, std::move(line_table), is_shared_cross_origin);
rec->entry = code_entries_.Create(
tag, GetFunctionName(*shared),
GetName(InferScriptName(*script_name, *shared)), line, column,
std::move(line_table), is_shared_cross_origin);
if (!inline_stacks.empty()) {
rec->entry->SetInlineStacks(std::move(cached_inline_entries),
std::move(inline_stacks));
@ -238,9 +240,9 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = code->instruction_start();
rec->entry =
new CodeEntry(tag, GetName(name), GetName(source_url), 1, code_offset + 1,
nullptr, true, CodeEntry::CodeType::WASM);
rec->entry = code_entries_.Create(tag, GetName(name), GetName(source_url), 1,
code_offset + 1, nullptr, true,
CodeEntry::CodeType::WASM);
rec->entry->set_script_id(script_id);
rec->entry->set_position(code_offset);
rec->instruction_size = code->instructions().length();
@ -252,7 +254,8 @@ void ProfilerListener::CallbackEvent(Handle<Name> name, Address entry_point) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = entry_point;
rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG, GetName(*name));
rec->entry =
code_entries_.Create(CodeEventListener::CALLBACK_TAG, GetName(*name));
rec->instruction_size = 1;
DispatchCodeEvent(evt_rec);
}
@ -262,8 +265,8 @@ void ProfilerListener::GetterCallbackEvent(Handle<Name> name,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = entry_point;
rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG,
GetConsName("get ", *name));
rec->entry = code_entries_.Create(CodeEventListener::CALLBACK_TAG,
GetConsName("get ", *name));
rec->instruction_size = 1;
DispatchCodeEvent(evt_rec);
}
@ -273,8 +276,8 @@ void ProfilerListener::SetterCallbackEvent(Handle<Name> name,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = entry_point;
rec->entry = new CodeEntry(CodeEventListener::CALLBACK_TAG,
GetConsName("set ", *name));
rec->entry = code_entries_.Create(CodeEventListener::CALLBACK_TAG,
GetConsName("set ", *name));
rec->instruction_size = 1;
DispatchCodeEvent(evt_rec);
}
@ -284,7 +287,7 @@ void ProfilerListener::RegExpCodeCreateEvent(Handle<AbstractCode> code,
CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION);
CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
rec->instruction_start = code->InstructionStart();
rec->entry = new CodeEntry(
rec->entry = code_entries_.Create(
CodeEventListener::REG_EXP_TAG, GetConsName("RegExp: ", *source),
CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo,
CpuProfileNode::kNoColumnNumberInfo, nullptr);

View File

@ -29,7 +29,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener,
public WeakCodeRegistry::Listener {
public:
ProfilerListener(Isolate*, CodeEventObserver*,
StringsStorage& function_and_resource_names,
CodeEntryStorage& code_entry_storage,
WeakCodeRegistry& weak_code_registry,
CpuProfilingNamingMode mode = kDebugNaming);
~ProfilerListener() override;
@ -76,17 +76,17 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener,
void CodeSweepEvent();
const char* GetName(Name name) {
return function_and_resource_names_.GetName(name);
return code_entries_.strings().GetName(name);
}
const char* GetName(int args_count) {
return function_and_resource_names_.GetName(args_count);
return code_entries_.strings().GetName(args_count);
}
const char* GetName(const char* name) {
return function_and_resource_names_.GetCopy(name);
return code_entries_.strings().GetCopy(name);
}
const char* GetName(Vector<const char> name);
const char* GetConsName(const char* prefix, Name name) {
return function_and_resource_names_.GetConsName(prefix, name);
return code_entries_.strings().GetConsName(prefix, name);
}
void set_observer(CodeEventObserver* observer) { observer_ = observer; }
@ -102,7 +102,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener,
Isolate* isolate_;
CodeEventObserver* observer_;
StringsStorage& function_and_resource_names_;
CodeEntryStorage& code_entries_;
WeakCodeRegistry& weak_code_registry_;
const CpuProfilingNamingMode naming_mode_;
};

View File

@ -16,9 +16,7 @@ Symbolizer::Symbolizer(CodeMap* code_map) : code_map_(code_map) {}
CodeEntry* Symbolizer::FindEntry(Address address,
Address* out_instruction_start) {
CodeEntry* entry = code_map_->FindEntry(address, out_instruction_start);
if (entry) entry->mark_used();
return entry;
return code_map_->FindEntry(address, out_instruction_start);
}
namespace {

View File

@ -88,8 +88,9 @@ static const char* reason(const i::DeoptimizeReason reason) {
TEST(StartStop) {
i::Isolate* isolate = CcTest::i_isolate();
CodeEntryStorage storage;
CpuProfilesCollection profiles(isolate);
ProfilerCodeObserver code_observer(isolate);
ProfilerCodeObserver code_observer(isolate, storage);
Symbolizer symbolizer(code_observer.code_map());
std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(
@ -171,15 +172,16 @@ TEST(CodeEvents) {
i::Handle<i::AbstractCode> comment2_code(CreateCode(isolate, &env), isolate);
i::Handle<i::AbstractCode> moved_code(CreateCode(isolate, &env), isolate);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate);
ProfilerCodeObserver code_observer(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
isolate, symbolizer, &code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(100), true);
CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor,
*code_observer.strings(),
*code_observer.code_entries(),
*code_observer.weak_code_registry());
isolate->logger()->AddCodeEventListener(&profiler_listener);
@ -234,8 +236,10 @@ TEST(TickEvents) {
i::Handle<i::AbstractCode> frame2_code(CreateCode(isolate, &env), isolate);
i::Handle<i::AbstractCode> frame3_code(CreateCode(isolate, &env), isolate);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), symbolizer, code_observer, profiles,
@ -245,7 +249,7 @@ TEST(TickEvents) {
profiles->StartProfiling("");
CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor,
*code_observer->strings(),
*code_observer->code_entries(),
*code_observer->weak_code_registry());
isolate->logger()->AddCodeEventListener(&profiler_listener);
@ -396,8 +400,10 @@ TEST(Issue1398) {
i::Handle<i::AbstractCode> code(CreateCode(isolate, &env), isolate);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), symbolizer, code_observer, profiles,
@ -407,7 +413,7 @@ TEST(Issue1398) {
profiles->StartProfiling("");
CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor,
*code_observer->strings(),
*code_observer->code_entries(),
*code_observer->weak_code_registry());
profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
@ -1262,8 +1268,10 @@ static void TickLines(bool optimize) {
i::Address code_address = code->raw_instruction_start();
CHECK_NE(code_address, kNullAddress);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), symbolizer, code_observer, profiles,
@ -1278,7 +1286,7 @@ static void TickLines(bool optimize) {
isolate->logger()->LogCompiledFunctions();
CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor,
*code_observer->strings(),
*code_observer->code_entries(),
*code_observer->weak_code_registry());
// Enqueue code creation events.
@ -3474,8 +3482,9 @@ TEST(MaxSimultaneousProfiles) {
TEST(LowPrecisionSamplingStartStopInternal) {
i::Isolate* isolate = CcTest::i_isolate();
CodeEntryStorage storage;
CpuProfilesCollection profiles(isolate);
ProfilerCodeObserver code_observer(isolate);
ProfilerCodeObserver code_observer(isolate, storage);
Symbolizer symbolizer(code_observer.code_map());
std::unique_ptr<ProfilerEventsProcessor> processor(
new SamplingEventsProcessor(
@ -3600,8 +3609,10 @@ TEST(ProflilerSubsampling) {
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
@ -3644,8 +3655,10 @@ TEST(DynamicResampling) {
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
@ -3705,8 +3718,10 @@ TEST(DynamicResamplingWithBaseInterval) {
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
CodeEntryStorage storage;
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
ProfilerCodeObserver* code_observer =
new ProfilerCodeObserver(isolate, storage);
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,

View File

@ -311,12 +311,12 @@ static inline i::Address ToAddress(int n) { return static_cast<i::Address>(n); }
static inline void* ToPointer(int n) { return reinterpret_cast<void*>(n); }
TEST(CodeMapAddCode) {
StringsStorage strings;
CodeMap code_map(strings);
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc");
CodeEntry* entry4 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ddd");
CodeEntryStorage storage;
CodeMap code_map(storage);
CodeEntry* entry1 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "ccc");
CodeEntry* entry4 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "ddd");
code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), entry2, 0x100);
code_map.AddCode(ToAddress(0x1900), entry3, 0x50);
@ -341,10 +341,10 @@ TEST(CodeMapAddCode) {
}
TEST(CodeMapMoveAndDeleteCode) {
StringsStorage strings;
CodeMap code_map(strings);
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntryStorage storage;
CodeMap code_map(storage);
CodeEntry* entry1 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb");
code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), entry2, 0x100);
CHECK_EQ(entry1, code_map.FindEntry(ToAddress(0x1500)));
@ -355,10 +355,10 @@ TEST(CodeMapMoveAndDeleteCode) {
}
TEST(CodeMapClear) {
StringsStorage strings;
CodeMap code_map(strings);
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntryStorage storage;
CodeMap code_map(storage);
CodeEntry* entry1 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb");
code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
code_map.AddCode(ToAddress(0x1700), entry2, 0x100);
@ -391,12 +391,12 @@ class TestSetup {
TEST(SymbolizeTickSample) {
TestSetup test_setup;
StringsStorage strings;
CodeMap code_map(strings);
CodeEntryStorage storage;
CodeMap code_map(storage);
Symbolizer symbolizer(&code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
CodeEntry* entry1 = storage.Create(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = storage.Create(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = storage.Create(i::Logger::FUNCTION_TAG, "ccc");
symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
symbolizer.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
symbolizer.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
@ -456,16 +456,16 @@ static void CheckNodeIds(const ProfileNode* node, unsigned* expectedId) {
TEST(SampleIds) {
TestSetup test_setup;
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
CpuProfiler profiler(isolate);
CpuProfilesCollection profiles(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
StringsStorage strings;
CodeMap code_map(strings);
CodeEntryStorage storage;
CodeMap code_map(storage);
Symbolizer symbolizer(&code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::Logger::FUNCTION_TAG, "ccc");
CodeEntry* entry1 = storage.Create(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = storage.Create(i::Logger::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = storage.Create(i::Logger::FUNCTION_TAG, "ccc");
symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
symbolizer.code_map()->AddCode(ToAddress(0x1700), entry2, 0x100);
symbolizer.code_map()->AddCode(ToAddress(0x1900), entry3, 0x50);
@ -592,8 +592,8 @@ TEST(MaxSamplesCallback) {
MaybeLocal<v8::Context>()},
std::move(impl));
StringsStorage strings;
CodeMap code_map(strings);
CodeEntryStorage storage;
CodeMap code_map(storage);
Symbolizer symbolizer(&code_map);
TickSample sample1;
sample1.timestamp = v8::base::TimeTicks::HighResolutionNow();
@ -633,14 +633,14 @@ TEST(MaxSamplesCallback) {
TEST(NoSamples) {
TestSetup test_setup;
i::Isolate* isolate = CcTest::i_isolate();
CpuProfilesCollection profiles(isolate);
CpuProfiler profiler(isolate);
CpuProfilesCollection profiles(isolate);
profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("");
StringsStorage strings;
CodeMap code_map(strings);
CodeEntryStorage storage;
CodeMap code_map(storage);
Symbolizer symbolizer(&code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry1 = storage.Create(i::Logger::FUNCTION_TAG, "aaa");
symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
// We are building the following calls tree:
@ -959,10 +959,10 @@ TEST(NodeSourceTypes) {
}
TEST(CodeMapRemoveCode) {
StringsStorage strings;
CodeMap code_map(strings);
CodeEntryStorage storage;
CodeMap code_map(storage);
CodeEntry* entry = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry = storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
code_map.AddCode(ToAddress(0x1000), entry, 0x100);
CHECK(code_map.RemoveCode(entry));
CHECK(!code_map.FindEntry(ToAddress(0x1000)));
@ -970,9 +970,9 @@ TEST(CodeMapRemoveCode) {
// Test that when two entries share the same address, we remove only the
// entry that we desired to.
CodeEntry* colliding_entry1 =
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* colliding_entry2 =
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
code_map.AddCode(ToAddress(0x1000), colliding_entry1, 0x100);
code_map.AddCode(ToAddress(0x1000), colliding_entry2, 0x100);
@ -984,14 +984,14 @@ TEST(CodeMapRemoveCode) {
}
TEST(CodeMapMoveOverlappingCode) {
StringsStorage strings;
CodeMap code_map(strings);
CodeEntryStorage storage;
CodeMap code_map(storage);
CodeEntry* colliding_entry1 =
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
storage.Create(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* colliding_entry2 =
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
storage.Create(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntry* after_entry =
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc");
storage.Create(i::CodeEventListener::FUNCTION_TAG, "ccc");
code_map.AddCode(ToAddress(0x1400), colliding_entry1, 0x200);
code_map.AddCode(ToAddress(0x1400), colliding_entry2, 0x200);