Commit 20feaf9a authored by Andrew Comminos's avatar Andrew Comminos Committed by Commit Bot

[cpu-profiler] Implement basic refcounting of CodeEntry strings

As a first step towards freeing CodeEntry objects that are neither still
referenced by JS or stored in a profile, enable freeing of refcounted
strings by CodeEntry instances. For now, this leaves behaviour unchanged
until we receive CodeEntry destruction events.

Bug: v8:11054
Change-Id: Iabd05aa730343cd1a879ff5b04326f23e68aa948
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2590604
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71858}
parent a66bb000
...@@ -321,12 +321,17 @@ void* SamplingEventsProcessor::operator new(size_t size) { ...@@ -321,12 +321,17 @@ void* SamplingEventsProcessor::operator new(size_t size) {
void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); } void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate) ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate)
: isolate_(isolate), processor_(nullptr) { : isolate_(isolate), code_map_(strings_), processor_(nullptr) {
CreateEntriesForRuntimeCallStats(); CreateEntriesForRuntimeCallStats();
LogBuiltins(); LogBuiltins();
} }
void ProfilerCodeObserver::ClearCodeMap() { code_map_.Clear(); } 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());
}
void ProfilerCodeObserver::CodeEventHandler( void ProfilerCodeObserver::CodeEventHandler(
const CodeEventsContainer& evt_rec) { const CodeEventsContainer& evt_rec) {
...@@ -445,22 +450,24 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager) ...@@ -445,22 +450,24 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager)
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode, CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode) CpuProfilingLoggingMode logging_mode)
: CpuProfiler(isolate, naming_mode, logging_mode, : CpuProfiler(isolate, naming_mode, logging_mode,
new CpuProfilesCollection(isolate), nullptr, nullptr) {} new CpuProfilesCollection(isolate), nullptr, nullptr,
new ProfilerCodeObserver(isolate)) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode, CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode, CpuProfilingLoggingMode logging_mode,
CpuProfilesCollection* test_profiles, CpuProfilesCollection* test_profiles,
Symbolizer* test_symbolizer, Symbolizer* test_symbolizer,
ProfilerEventsProcessor* test_processor) ProfilerEventsProcessor* test_processor,
ProfilerCodeObserver* test_code_observer)
: isolate_(isolate), : isolate_(isolate),
naming_mode_(naming_mode), naming_mode_(naming_mode),
logging_mode_(logging_mode), logging_mode_(logging_mode),
base_sampling_interval_(base::TimeDelta::FromMicroseconds( base_sampling_interval_(base::TimeDelta::FromMicroseconds(
FLAG_cpu_profiler_sampling_interval)), FLAG_cpu_profiler_sampling_interval)),
code_observer_(test_code_observer),
profiles_(test_profiles), profiles_(test_profiles),
symbolizer_(test_symbolizer), symbolizer_(test_symbolizer),
processor_(test_processor), processor_(test_processor),
code_observer_(isolate),
is_profiling_(false) { is_profiling_(false) {
profiles_->set_cpu_profiler(this); profiles_->set_cpu_profiler(this);
GetProfilersManager()->AddProfiler(isolate, this); GetProfilersManager()->AddProfiler(isolate, this);
...@@ -491,7 +498,7 @@ void CpuProfiler::ResetProfiles() { ...@@ -491,7 +498,7 @@ void CpuProfiler::ResetProfiles() {
symbolizer_.reset(); symbolizer_.reset();
if (!profiling_scope_) { if (!profiling_scope_) {
profiler_listener_.reset(); profiler_listener_.reset();
code_observer_.ClearCodeMap(); code_observer_->ClearCodeMap();
} }
} }
...@@ -500,7 +507,8 @@ void CpuProfiler::EnableLogging() { ...@@ -500,7 +507,8 @@ void CpuProfiler::EnableLogging() {
if (!profiler_listener_) { if (!profiler_listener_) {
profiler_listener_.reset( profiler_listener_.reset(
new ProfilerListener(isolate_, &code_observer_, naming_mode_)); new ProfilerListener(isolate_, code_observer_.get(),
*code_observer_->strings(), naming_mode_));
} }
profiling_scope_.reset( profiling_scope_.reset(
new ProfilingScope(isolate_, profiler_listener_.get())); new ProfilingScope(isolate_, profiler_listener_.get()));
...@@ -568,12 +576,12 @@ void CpuProfiler::StartProcessorIfNotStarted() { ...@@ -568,12 +576,12 @@ void CpuProfiler::StartProcessorIfNotStarted() {
} }
if (!symbolizer_) { if (!symbolizer_) {
symbolizer_ = std::make_unique<Symbolizer>(code_observer_.code_map()); symbolizer_ = std::make_unique<Symbolizer>(code_observer_->code_map());
} }
base::TimeDelta sampling_interval = ComputeSamplingInterval(); base::TimeDelta sampling_interval = ComputeSamplingInterval();
processor_.reset(new SamplingEventsProcessor( processor_.reset(new SamplingEventsProcessor(
isolate_, symbolizer_.get(), &code_observer_, profiles_.get(), isolate_, symbolizer_.get(), code_observer_.get(), profiles_.get(),
sampling_interval, use_precise_sampling_)); sampling_interval, use_precise_sampling_));
is_profiling_ = true; is_profiling_ = true;
......
...@@ -236,16 +236,18 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor ...@@ -236,16 +236,18 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
// low sampling intervals on Windows. // low sampling intervals on Windows.
}; };
// Builds and maintains a CodeMap tracking code objects on the VM heap. While // Builds and maintains a CodeMap tracking code objects on the VM heap, as well
// alive, logs generated code, callbacks, and builtins from the isolate. // as strings owned by them. While alive, logs generated code, callbacks, and
// Redirects events to the profiler events processor when present. // builtins from the isolate. Redirects events to the profiler events
// processor when present.
class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver { class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
public: public:
explicit ProfilerCodeObserver(Isolate*); explicit ProfilerCodeObserver(Isolate*);
void CodeEventHandler(const CodeEventsContainer& evt_rec) override; void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
CodeMap* code_map() { return &code_map_; } CodeMap* code_map() { return &code_map_; }
StringsStorage* strings() { return &strings_; }
void ClearCodeMap(); void ClearCodeMap();
private: private:
...@@ -267,6 +269,7 @@ class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver { ...@@ -267,6 +269,7 @@ class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
void clear_processor() { processor_ = nullptr; } void clear_processor() { processor_ = nullptr; }
Isolate* const isolate_; Isolate* const isolate_;
StringsStorage strings_;
CodeMap code_map_; CodeMap code_map_;
ProfilerEventsProcessor* processor_; ProfilerEventsProcessor* processor_;
}; };
...@@ -299,7 +302,8 @@ class V8_EXPORT_PRIVATE CpuProfiler { ...@@ -299,7 +302,8 @@ class V8_EXPORT_PRIVATE CpuProfiler {
CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode, CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
CpuProfilingLoggingMode logging_mode, CpuProfilingLoggingMode logging_mode,
CpuProfilesCollection* profiles, Symbolizer* test_symbolizer, CpuProfilesCollection* profiles, Symbolizer* test_symbolizer,
ProfilerEventsProcessor* test_processor); ProfilerEventsProcessor* test_processor,
ProfilerCodeObserver* test_code_observer);
~CpuProfiler(); ~CpuProfiler();
CpuProfiler(const CpuProfiler&) = delete; CpuProfiler(const CpuProfiler&) = delete;
...@@ -337,7 +341,7 @@ class V8_EXPORT_PRIVATE CpuProfiler { ...@@ -337,7 +341,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
ProfilerListener* profiler_listener_for_test() const { ProfilerListener* profiler_listener_for_test() const {
return profiler_listener_.get(); return profiler_listener_.get();
} }
CodeMap* code_map_for_test() { return code_observer_.code_map(); } CodeMap* code_map_for_test() { return code_observer_->code_map(); }
private: private:
void StartProcessorIfNotStarted(); void StartProcessorIfNotStarted();
...@@ -361,12 +365,12 @@ class V8_EXPORT_PRIVATE CpuProfiler { ...@@ -361,12 +365,12 @@ class V8_EXPORT_PRIVATE CpuProfiler {
// Sampling interval to which per-profile sampling intervals will be clamped // Sampling interval to which per-profile sampling intervals will be clamped
// to a multiple of, or used as the default if unspecified. // to a multiple of, or used as the default if unspecified.
base::TimeDelta base_sampling_interval_; base::TimeDelta base_sampling_interval_;
std::unique_ptr<ProfilerCodeObserver> code_observer_;
std::unique_ptr<CpuProfilesCollection> profiles_; std::unique_ptr<CpuProfilesCollection> profiles_;
std::unique_ptr<Symbolizer> symbolizer_; std::unique_ptr<Symbolizer> symbolizer_;
std::unique_ptr<ProfilerEventsProcessor> processor_; std::unique_ptr<ProfilerEventsProcessor> processor_;
std::unique_ptr<ProfilerListener> profiler_listener_; std::unique_ptr<ProfilerListener> profiler_listener_;
std::unique_ptr<ProfilingScope> profiling_scope_; std::unique_ptr<ProfilingScope> profiling_scope_;
ProfilerCodeObserver code_observer_;
bool is_profiling_; bool is_profiling_;
}; };
......
...@@ -221,6 +221,25 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() { ...@@ -221,6 +221,25 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() {
return rare_data_.get(); return rare_data_.get();
} }
void CodeEntry::ReleaseStrings(StringsStorage& strings) {
if (name_) {
strings.Release(name_);
name_ = nullptr;
}
if (resource_name_) {
strings.Release(resource_name_);
resource_name_ = nullptr;
}
if (rare_data_) {
// All inline entries are exclusively owned by the CodeEntry. They'll be
// deallocated when the CodeEntry is deallocated.
for (auto& entry : rare_data_->inline_entries_) {
entry->ReleaseStrings(strings);
}
}
}
void CodeEntry::print() const { void CodeEntry::print() const {
base::OS::Print("CodeEntry: at %p\n", this); base::OS::Print("CodeEntry: at %p\n", this);
...@@ -641,7 +660,8 @@ void CpuProfile::Print() const { ...@@ -641,7 +660,8 @@ void CpuProfile::Print() const {
ProfilerStats::Instance()->Clear(); ProfilerStats::Instance()->Clear();
} }
CodeMap::CodeMap() = default; CodeMap::CodeMap(StringsStorage& function_and_resource_names)
: function_and_resource_names_(function_and_resource_names) {}
CodeMap::~CodeMap() { Clear(); } CodeMap::~CodeMap() { Clear(); }
...@@ -654,7 +674,12 @@ void CodeMap::Clear() { ...@@ -654,7 +674,12 @@ void CodeMap::Clear() {
code_entries_[free_slot].entry = nullptr; code_entries_[free_slot].entry = nullptr;
free_slot = next_slot; free_slot = next_slot;
} }
for (auto slot : code_entries_) delete slot.entry; for (auto slot : code_entries_) {
if (slot.entry) {
slot.entry->ReleaseStrings(function_and_resource_names_);
delete slot.entry;
}
}
code_entries_.clear(); code_entries_.clear();
code_map_.clear(); code_map_.clear();
...@@ -717,7 +742,10 @@ unsigned CodeMap::AddCodeEntry(Address start, CodeEntry* entry) { ...@@ -717,7 +742,10 @@ unsigned CodeMap::AddCodeEntry(Address start, CodeEntry* entry) {
} }
void CodeMap::DeleteCodeEntry(unsigned index) { void CodeMap::DeleteCodeEntry(unsigned index) {
delete code_entries_[index].entry; auto* entry = code_entries_[index].entry;
entry->ReleaseStrings(function_and_resource_names_);
delete entry;
code_entries_[index].next_free_slot = free_list_head_; code_entries_[index].next_free_slot = free_list_head_;
free_list_head_ = index; free_list_head_ = index;
} }
......
...@@ -59,7 +59,8 @@ struct CodeEntryAndLineNumber; ...@@ -59,7 +59,8 @@ struct CodeEntryAndLineNumber;
class CodeEntry { class CodeEntry {
public: public:
// CodeEntry doesn't own name strings, just references them. // CodeEntry may reference strings (|name|, |resource_name|) managed by a
// StringsStorage instance. These must be freed via ReleaseStrings.
inline CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name, inline CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
const char* resource_name = CodeEntry::kEmptyResourceName, const char* resource_name = CodeEntry::kEmptyResourceName,
int line_number = v8::CpuProfileNode::kNoLineNumberInfo, int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
...@@ -163,6 +164,12 @@ class CodeEntry { ...@@ -163,6 +164,12 @@ class CodeEntry {
} }
V8_INLINE static CodeEntry* root_entry() { return kRootEntry.Pointer(); } V8_INLINE static CodeEntry* root_entry() { return kRootEntry.Pointer(); }
// Releases strings owned by this CodeEntry, which may be allocated in the
// provided StringsStorage instance. This instance is not stored directly
// with the CodeEntry in order to reduce memory footprint.
// Called before every destruction.
void ReleaseStrings(StringsStorage& strings);
void print() const; void print() const;
private: private:
...@@ -404,7 +411,9 @@ class CpuProfile { ...@@ -404,7 +411,9 @@ class CpuProfile {
class V8_EXPORT_PRIVATE CodeMap { class V8_EXPORT_PRIVATE CodeMap {
public: public:
CodeMap(); // Creates a new CodeMap with an associated StringsStorage to store the
// strings of CodeEntry objects within.
explicit CodeMap(StringsStorage& function_and_resource_names);
~CodeMap(); ~CodeMap();
CodeMap(const CodeMap&) = delete; CodeMap(const CodeMap&) = delete;
CodeMap& operator=(const CodeMap&) = delete; CodeMap& operator=(const CodeMap&) = delete;
...@@ -439,6 +448,7 @@ class V8_EXPORT_PRIVATE CodeMap { ...@@ -439,6 +448,7 @@ class V8_EXPORT_PRIVATE CodeMap {
std::deque<CodeEntrySlotInfo> code_entries_; std::deque<CodeEntrySlotInfo> code_entries_;
std::map<Address, CodeEntryMapInfo> code_map_; std::map<Address, CodeEntryMapInfo> code_map_;
unsigned free_list_head_ = kNoFreeSlot; unsigned free_list_head_ = kNoFreeSlot;
StringsStorage& function_and_resource_names_;
}; };
class V8_EXPORT_PRIVATE CpuProfilesCollection { class V8_EXPORT_PRIVATE CpuProfilesCollection {
......
...@@ -25,8 +25,12 @@ namespace internal { ...@@ -25,8 +25,12 @@ namespace internal {
ProfilerListener::ProfilerListener(Isolate* isolate, ProfilerListener::ProfilerListener(Isolate* isolate,
CodeEventObserver* observer, CodeEventObserver* observer,
StringsStorage& function_and_resource_names,
CpuProfilingNamingMode naming_mode) CpuProfilingNamingMode naming_mode)
: isolate_(isolate), observer_(observer), naming_mode_(naming_mode) {} : isolate_(isolate),
observer_(observer),
function_and_resource_names_(function_and_resource_names),
naming_mode_(naming_mode) {}
ProfilerListener::~ProfilerListener() = default; ProfilerListener::~ProfilerListener() = default;
...@@ -78,9 +82,12 @@ namespace { ...@@ -78,9 +82,12 @@ namespace {
CodeEntry* GetOrInsertCachedEntry( CodeEntry* GetOrInsertCachedEntry(
std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher, std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
CodeEntry::Equals>* entries, CodeEntry::Equals>* entries,
std::unique_ptr<CodeEntry> search_value) { std::unique_ptr<CodeEntry> search_value, StringsStorage& strings) {
auto it = entries->find(search_value); auto it = entries->find(search_value);
if (it != entries->end()) return it->get(); if (it != entries->end()) {
search_value->ReleaseStrings(strings);
return it->get();
}
CodeEntry* ret = search_value.get(); CodeEntry* ret = search_value.get();
entries->insert(std::move(search_value)); entries->insert(std::move(search_value));
return ret; return ret;
...@@ -168,7 +175,8 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag, ...@@ -168,7 +175,8 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
// Create a canonical CodeEntry for each inlined frame and then re-use // Create a canonical CodeEntry for each inlined frame and then re-use
// them for subsequent inline stacks to avoid a lot of duplication. // them for subsequent inline stacks to avoid a lot of duplication.
CodeEntry* cached_entry = GetOrInsertCachedEntry( CodeEntry* cached_entry = GetOrInsertCachedEntry(
&cached_inline_entries, std::move(inline_entry)); &cached_inline_entries, std::move(inline_entry),
function_and_resource_names_);
inline_stack.push_back({cached_entry, line_number}); inline_stack.push_back({cached_entry, line_number});
} }
......
...@@ -27,6 +27,7 @@ class CodeEventObserver { ...@@ -27,6 +27,7 @@ class CodeEventObserver {
class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener { class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
public: public:
ProfilerListener(Isolate*, CodeEventObserver*, ProfilerListener(Isolate*, CodeEventObserver*,
StringsStorage& function_and_resource_names,
CpuProfilingNamingMode mode = kDebugNaming); CpuProfilingNamingMode mode = kDebugNaming);
~ProfilerListener() override; ~ProfilerListener() override;
ProfilerListener(const ProfilerListener&) = delete; ProfilerListener(const ProfilerListener&) = delete;
...@@ -89,7 +90,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener { ...@@ -89,7 +90,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
Isolate* isolate_; Isolate* isolate_;
CodeEventObserver* observer_; CodeEventObserver* observer_;
StringsStorage function_and_resource_names_; StringsStorage& function_and_resource_names_;
const CpuProfilingNamingMode naming_mode_; const CpuProfilingNamingMode naming_mode_;
}; };
......
...@@ -49,6 +49,7 @@ const char* StringsStorage::GetFormatted(const char* format, ...) { ...@@ -49,6 +49,7 @@ const char* StringsStorage::GetFormatted(const char* format, ...) {
} }
const char* StringsStorage::AddOrDisposeString(char* str, int len) { const char* StringsStorage::AddOrDisposeString(char* str, int len) {
base::MutexGuard guard(&mutex_);
base::HashMap::Entry* entry = GetEntry(str, len); base::HashMap::Entry* entry = GetEntry(str, len);
if (entry->value == nullptr) { if (entry->value == nullptr) {
// New entry added. // New entry added.
...@@ -119,11 +120,15 @@ inline uint32_t ComputeStringHash(const char* str, int len) { ...@@ -119,11 +120,15 @@ inline uint32_t ComputeStringHash(const char* str, int len) {
} // namespace } // namespace
bool StringsStorage::Release(const char* str) { bool StringsStorage::Release(const char* str) {
base::MutexGuard guard(&mutex_);
int len = static_cast<int>(strlen(str)); int len = static_cast<int>(strlen(str));
uint32_t hash = ComputeStringHash(str, len); uint32_t hash = ComputeStringHash(str, len);
base::HashMap::Entry* entry = names_.Lookup(const_cast<char*>(str), hash); base::HashMap::Entry* entry = names_.Lookup(const_cast<char*>(str), hash);
DCHECK(entry);
if (!entry) { // If an entry wasn't found or the address of the found entry doesn't match
// the one passed in, this string wasn't managed by this StringsStorage
// instance (i.e. a constant). Ignore this.
if (!entry || entry->key != str) {
return false; return false;
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/base/hashmap.h" #include "src/base/hashmap.h"
#include "src/base/platform/mutex.h"
#include "src/common/globals.h" #include "src/common/globals.h"
namespace v8 { namespace v8 {
...@@ -38,13 +39,16 @@ class V8_EXPORT_PRIVATE StringsStorage { ...@@ -38,13 +39,16 @@ class V8_EXPORT_PRIVATE StringsStorage {
// result. // result.
const char* GetConsName(const char* prefix, Name name); const char* GetConsName(const char* prefix, Name name);
// Reduces the refcount of the given string, freeing it if no other // Reduces the refcount of the given string, freeing it if no other
// references are made to it. // references are made to it. Returns true if the string was successfully
// Returns true if the string was successfully unref'd. // unref'd, or false if the string was not present in the table.
bool Release(const char* str); bool Release(const char* str);
// Returns the number of strings in the store. // Returns the number of strings in the store.
size_t GetStringCountForTesting() const; size_t GetStringCountForTesting() const;
// Returns true if the strings table is empty.
bool empty() const { return names_.occupancy() == 0; }
private: private:
static bool StringsMatch(void* key1, void* key2); static bool StringsMatch(void* key1, void* key2);
// Adds the string to storage and returns it, or if a matching string exists // Adds the string to storage and returns it, or if a matching string exists
...@@ -55,6 +59,7 @@ class V8_EXPORT_PRIVATE StringsStorage { ...@@ -55,6 +59,7 @@ class V8_EXPORT_PRIVATE StringsStorage {
const char* GetVFormatted(const char* format, va_list args); const char* GetVFormatted(const char* format, va_list args);
base::CustomMatcherHashMap names_; base::CustomMatcherHashMap names_;
base::Mutex mutex_;
}; };
} // namespace internal } // namespace internal
......
...@@ -177,7 +177,8 @@ TEST(CodeEvents) { ...@@ -177,7 +177,8 @@ TEST(CodeEvents) {
isolate, symbolizer, &code_observer, profiles, isolate, symbolizer, &code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(100), true); v8::base::TimeDelta::FromMicroseconds(100), true);
CHECK(processor->Start()); CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor); ProfilerListener profiler_listener(isolate, processor,
*code_observer.strings());
isolate->logger()->AddCodeEventListener(&profiler_listener); isolate->logger()->AddCodeEventListener(&profiler_listener);
// Enqueue code creation events. // Enqueue code creation events.
...@@ -232,16 +233,17 @@ TEST(TickEvents) { ...@@ -232,16 +233,17 @@ TEST(TickEvents) {
i::Handle<i::AbstractCode> frame3_code(CreateCode(isolate, &env), isolate); i::Handle<i::AbstractCode> frame3_code(CreateCode(isolate, &env), isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate); ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor( ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), symbolizer, &code_observer, profiles, CcTest::i_isolate(), symbolizer, code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(100), true); v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
symbolizer, processor); symbolizer, processor, code_observer);
profiles->StartProfiling(""); profiles->StartProfiling("");
CHECK(processor->Start()); CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor); ProfilerListener profiler_listener(isolate, processor,
*code_observer->strings());
isolate->logger()->AddCodeEventListener(&profiler_listener); isolate->logger()->AddCodeEventListener(&profiler_listener);
profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb"); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
...@@ -392,16 +394,17 @@ TEST(Issue1398) { ...@@ -392,16 +394,17 @@ TEST(Issue1398) {
i::Handle<i::AbstractCode> code(CreateCode(isolate, &env), isolate); i::Handle<i::AbstractCode> code(CreateCode(isolate, &env), isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate); ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor( ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), symbolizer, &code_observer, profiles, CcTest::i_isolate(), symbolizer, code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(100), true); v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
symbolizer, processor); symbolizer, processor, code_observer);
profiles->StartProfiling(""); profiles->StartProfiling("");
CHECK(processor->Start()); CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor); ProfilerListener profiler_listener(isolate, processor,
*code_observer->strings());
profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb"); profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, code, "bbb");
...@@ -1245,13 +1248,13 @@ static void TickLines(bool optimize) { ...@@ -1245,13 +1248,13 @@ static void TickLines(bool optimize) {
CHECK_NE(code_address, kNullAddress); CHECK_NE(code_address, kNullAddress);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate); ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = new SamplingEventsProcessor( ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
CcTest::i_isolate(), symbolizer, &code_observer, profiles, CcTest::i_isolate(), symbolizer, code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(100), true); v8::base::TimeDelta::FromMicroseconds(100), true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
symbolizer, processor); symbolizer, processor, code_observer);
profiles->StartProfiling(""); profiles->StartProfiling("");
// TODO(delphick): Stop using the CpuProfiler internals here: This forces // TODO(delphick): Stop using the CpuProfiler internals here: This forces
// LogCompiledFunctions so that source positions are collected everywhere. // LogCompiledFunctions so that source positions are collected everywhere.
...@@ -1259,7 +1262,8 @@ static void TickLines(bool optimize) { ...@@ -1259,7 +1262,8 @@ static void TickLines(bool optimize) {
// but doesn't because it's constructed with a symbolizer and a processor. // but doesn't because it's constructed with a symbolizer and a processor.
isolate->logger()->LogCompiledFunctions(); isolate->logger()->LogCompiledFunctions();
CHECK(processor->Start()); CHECK(processor->Start());
ProfilerListener profiler_listener(isolate, processor); ProfilerListener profiler_listener(isolate, processor,
*code_observer->strings());
// Enqueue code creation events. // Enqueue code creation events.
i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name); i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
...@@ -3549,14 +3553,14 @@ TEST(ProflilerSubsampling) { ...@@ -3549,14 +3553,14 @@ TEST(ProflilerSubsampling) {
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate); ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles, new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(1), v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true); /* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
symbolizer, processor); symbolizer, processor, code_observer);
// Create a new CpuProfile that wants samples at 8us. // Create a new CpuProfile that wants samples at 8us.
CpuProfile profile(&profiler, "", CpuProfile profile(&profiler, "",
...@@ -3593,14 +3597,14 @@ TEST(DynamicResampling) { ...@@ -3593,14 +3597,14 @@ TEST(DynamicResampling) {
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate); ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles, new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(1), v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true); /* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
symbolizer, processor); symbolizer, processor, code_observer);
// Set a 1us base sampling rate, dividing all possible intervals. // Set a 1us base sampling rate, dividing all possible intervals.
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(1)); profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(1));
...@@ -3654,14 +3658,14 @@ TEST(DynamicResamplingWithBaseInterval) { ...@@ -3654,14 +3658,14 @@ TEST(DynamicResamplingWithBaseInterval) {
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate); CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
ProfilerCodeObserver code_observer(isolate); ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map()); Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
ProfilerEventsProcessor* processor = ProfilerEventsProcessor* processor =
new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles, new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
v8::base::TimeDelta::FromMicroseconds(1), v8::base::TimeDelta::FromMicroseconds(1),
/* use_precise_sampling */ true); /* use_precise_sampling */ true);
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles, CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
symbolizer, processor); symbolizer, processor, code_observer);
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(7)); profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(7));
......
...@@ -311,7 +311,8 @@ static inline i::Address ToAddress(int n) { return static_cast<i::Address>(n); } ...@@ -311,7 +311,8 @@ static inline i::Address ToAddress(int n) { return static_cast<i::Address>(n); }
static inline void* ToPointer(int n) { return reinterpret_cast<void*>(n); } static inline void* ToPointer(int n) { return reinterpret_cast<void*>(n); }
TEST(CodeMapAddCode) { TEST(CodeMapAddCode) {
CodeMap code_map; StringsStorage strings;
CodeMap code_map(strings);
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
CodeEntry* entry3 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc"); CodeEntry* entry3 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc");
...@@ -340,7 +341,8 @@ TEST(CodeMapAddCode) { ...@@ -340,7 +341,8 @@ TEST(CodeMapAddCode) {
} }
TEST(CodeMapMoveAndDeleteCode) { TEST(CodeMapMoveAndDeleteCode) {
CodeMap code_map; StringsStorage strings;
CodeMap code_map(strings);
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
code_map.AddCode(ToAddress(0x1500), entry1, 0x200); code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
...@@ -357,7 +359,8 @@ TEST(CodeMapMoveAndDeleteCode) { ...@@ -357,7 +359,8 @@ TEST(CodeMapMoveAndDeleteCode) {
} }
TEST(CodeMapClear) { TEST(CodeMapClear) {
CodeMap code_map; StringsStorage strings;
CodeMap code_map(strings);
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa"); CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb"); CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
code_map.AddCode(ToAddress(0x1500), entry1, 0x200); code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
...@@ -392,7 +395,8 @@ class TestSetup { ...@@ -392,7 +395,8 @@ class TestSetup {
TEST(SymbolizeTickSample) { TEST(SymbolizeTickSample) {
TestSetup test_setup; TestSetup test_setup;
CodeMap code_map; StringsStorage strings;
CodeMap code_map(strings);
Symbolizer symbolizer(&code_map); Symbolizer symbolizer(&code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa"); CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb"); CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
...@@ -460,7 +464,8 @@ TEST(SampleIds) { ...@@ -460,7 +464,8 @@ TEST(SampleIds) {
CpuProfiler profiler(isolate); CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler); profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers}); profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
CodeMap code_map; StringsStorage strings;
CodeMap code_map(strings);
Symbolizer symbolizer(&code_map); Symbolizer symbolizer(&code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa"); CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb"); CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
...@@ -525,7 +530,8 @@ TEST(NoSamples) { ...@@ -525,7 +530,8 @@ TEST(NoSamples) {
CpuProfiler profiler(isolate); CpuProfiler profiler(isolate);
profiles.set_cpu_profiler(&profiler); profiles.set_cpu_profiler(&profiler);
profiles.StartProfiling(""); profiles.StartProfiling("");
CodeMap code_map; StringsStorage strings;
CodeMap code_map(strings);
Symbolizer symbolizer(&code_map); Symbolizer symbolizer(&code_map);
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa"); CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200); symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
......
...@@ -141,20 +141,15 @@ TEST_F(StringsStorageWithIsolate, Refcounting) { ...@@ -141,20 +141,15 @@ TEST_F(StringsStorageWithIsolate, Refcounting) {
CHECK_EQ(storage.GetStringCountForTesting(), 1); CHECK_EQ(storage.GetStringCountForTesting(), 1);
CHECK(storage.Release(d)); CHECK(storage.Release(d));
CHECK_EQ(storage.GetStringCountForTesting(), 0); CHECK_EQ(storage.GetStringCountForTesting(), 0);
#if !DEBUG
CHECK(!storage.Release("12")); CHECK(!storage.Release("12"));
#endif // !DEBUG
} }
TEST_F(StringsStorageWithIsolate, InvalidRelease) { TEST_F(StringsStorageWithIsolate, InvalidRelease) {
StringsStorage storage; StringsStorage storage;
// If a refcount becomes invalid, throw in debug builds. // If we attempt to release a string not being managed by the StringsStorage,
#ifdef DEBUG // return false.
ASSERT_DEATH_IF_SUPPORTED(storage.Release("12"), "check failed");
#else
CHECK(!storage.Release("12")); CHECK(!storage.Release("12"));
#endif // DEBUG
} }
TEST_F(StringsStorageWithIsolate, CopyAndConsShareStorage) { TEST_F(StringsStorageWithIsolate, CopyAndConsShareStorage) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment