[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: Peter Marshall <petermarshall@chromium.org> Cr-Commit-Position: refs/heads/master@{#71858}
This commit is contained in:
parent
a66bb00024
commit
20feaf9a00
@ -321,12 +321,17 @@ void* SamplingEventsProcessor::operator new(size_t size) {
|
||||
void SamplingEventsProcessor::operator delete(void* ptr) { AlignedFree(ptr); }
|
||||
|
||||
ProfilerCodeObserver::ProfilerCodeObserver(Isolate* isolate)
|
||||
: isolate_(isolate), processor_(nullptr) {
|
||||
: isolate_(isolate), code_map_(strings_), processor_(nullptr) {
|
||||
CreateEntriesForRuntimeCallStats();
|
||||
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(
|
||||
const CodeEventsContainer& evt_rec) {
|
||||
@ -445,22 +450,24 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(CpuProfilersManager, GetProfilersManager)
|
||||
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
|
||||
CpuProfilingLoggingMode 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,
|
||||
CpuProfilingLoggingMode logging_mode,
|
||||
CpuProfilesCollection* test_profiles,
|
||||
Symbolizer* test_symbolizer,
|
||||
ProfilerEventsProcessor* test_processor)
|
||||
ProfilerEventsProcessor* test_processor,
|
||||
ProfilerCodeObserver* test_code_observer)
|
||||
: isolate_(isolate),
|
||||
naming_mode_(naming_mode),
|
||||
logging_mode_(logging_mode),
|
||||
base_sampling_interval_(base::TimeDelta::FromMicroseconds(
|
||||
FLAG_cpu_profiler_sampling_interval)),
|
||||
code_observer_(test_code_observer),
|
||||
profiles_(test_profiles),
|
||||
symbolizer_(test_symbolizer),
|
||||
processor_(test_processor),
|
||||
code_observer_(isolate),
|
||||
is_profiling_(false) {
|
||||
profiles_->set_cpu_profiler(this);
|
||||
GetProfilersManager()->AddProfiler(isolate, this);
|
||||
@ -491,7 +498,7 @@ void CpuProfiler::ResetProfiles() {
|
||||
symbolizer_.reset();
|
||||
if (!profiling_scope_) {
|
||||
profiler_listener_.reset();
|
||||
code_observer_.ClearCodeMap();
|
||||
code_observer_->ClearCodeMap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,7 +507,8 @@ void CpuProfiler::EnableLogging() {
|
||||
|
||||
if (!profiler_listener_) {
|
||||
profiler_listener_.reset(
|
||||
new ProfilerListener(isolate_, &code_observer_, naming_mode_));
|
||||
new ProfilerListener(isolate_, code_observer_.get(),
|
||||
*code_observer_->strings(), naming_mode_));
|
||||
}
|
||||
profiling_scope_.reset(
|
||||
new ProfilingScope(isolate_, profiler_listener_.get()));
|
||||
@ -568,12 +576,12 @@ void CpuProfiler::StartProcessorIfNotStarted() {
|
||||
}
|
||||
|
||||
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();
|
||||
processor_.reset(new SamplingEventsProcessor(
|
||||
isolate_, symbolizer_.get(), &code_observer_, profiles_.get(),
|
||||
isolate_, symbolizer_.get(), code_observer_.get(), profiles_.get(),
|
||||
sampling_interval, use_precise_sampling_));
|
||||
is_profiling_ = true;
|
||||
|
||||
|
@ -236,16 +236,18 @@ class V8_EXPORT_PRIVATE SamplingEventsProcessor
|
||||
// low sampling intervals on Windows.
|
||||
};
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
|
||||
public:
|
||||
explicit ProfilerCodeObserver(Isolate*);
|
||||
|
||||
void CodeEventHandler(const CodeEventsContainer& evt_rec) override;
|
||||
|
||||
CodeMap* code_map() { return &code_map_; }
|
||||
StringsStorage* strings() { return &strings_; }
|
||||
|
||||
void ClearCodeMap();
|
||||
|
||||
private:
|
||||
@ -267,6 +269,7 @@ class V8_EXPORT_PRIVATE ProfilerCodeObserver : public CodeEventObserver {
|
||||
void clear_processor() { processor_ = nullptr; }
|
||||
|
||||
Isolate* const isolate_;
|
||||
StringsStorage strings_;
|
||||
CodeMap code_map_;
|
||||
ProfilerEventsProcessor* processor_;
|
||||
};
|
||||
@ -299,7 +302,8 @@ class V8_EXPORT_PRIVATE CpuProfiler {
|
||||
CpuProfiler(Isolate* isolate, CpuProfilingNamingMode naming_mode,
|
||||
CpuProfilingLoggingMode logging_mode,
|
||||
CpuProfilesCollection* profiles, Symbolizer* test_symbolizer,
|
||||
ProfilerEventsProcessor* test_processor);
|
||||
ProfilerEventsProcessor* test_processor,
|
||||
ProfilerCodeObserver* test_code_observer);
|
||||
|
||||
~CpuProfiler();
|
||||
CpuProfiler(const CpuProfiler&) = delete;
|
||||
@ -337,7 +341,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
|
||||
ProfilerListener* profiler_listener_for_test() const {
|
||||
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:
|
||||
void StartProcessorIfNotStarted();
|
||||
@ -361,12 +365,12 @@ 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_;
|
||||
std::unique_ptr<ProfilerCodeObserver> code_observer_;
|
||||
std::unique_ptr<CpuProfilesCollection> profiles_;
|
||||
std::unique_ptr<Symbolizer> symbolizer_;
|
||||
std::unique_ptr<ProfilerEventsProcessor> processor_;
|
||||
std::unique_ptr<ProfilerListener> profiler_listener_;
|
||||
std::unique_ptr<ProfilingScope> profiling_scope_;
|
||||
ProfilerCodeObserver code_observer_;
|
||||
bool is_profiling_;
|
||||
};
|
||||
|
||||
|
@ -221,6 +221,25 @@ CodeEntry::RareData* CodeEntry::EnsureRareData() {
|
||||
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 {
|
||||
base::OS::Print("CodeEntry: at %p\n", this);
|
||||
|
||||
@ -641,7 +660,8 @@ void CpuProfile::Print() const {
|
||||
ProfilerStats::Instance()->Clear();
|
||||
}
|
||||
|
||||
CodeMap::CodeMap() = default;
|
||||
CodeMap::CodeMap(StringsStorage& function_and_resource_names)
|
||||
: function_and_resource_names_(function_and_resource_names) {}
|
||||
|
||||
CodeMap::~CodeMap() { Clear(); }
|
||||
|
||||
@ -654,7 +674,12 @@ void CodeMap::Clear() {
|
||||
code_entries_[free_slot].entry = nullptr;
|
||||
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_map_.clear();
|
||||
@ -717,7 +742,10 @@ unsigned CodeMap::AddCodeEntry(Address start, CodeEntry* entry) {
|
||||
}
|
||||
|
||||
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_;
|
||||
free_list_head_ = index;
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ struct CodeEntryAndLineNumber;
|
||||
|
||||
class CodeEntry {
|
||||
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,
|
||||
const char* resource_name = CodeEntry::kEmptyResourceName,
|
||||
int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
|
||||
@ -163,6 +164,12 @@ class CodeEntry {
|
||||
}
|
||||
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;
|
||||
|
||||
private:
|
||||
@ -404,7 +411,9 @@ class CpuProfile {
|
||||
|
||||
class V8_EXPORT_PRIVATE CodeMap {
|
||||
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(const CodeMap&) = delete;
|
||||
CodeMap& operator=(const CodeMap&) = delete;
|
||||
@ -439,6 +448,7 @@ class V8_EXPORT_PRIVATE CodeMap {
|
||||
std::deque<CodeEntrySlotInfo> code_entries_;
|
||||
std::map<Address, CodeEntryMapInfo> code_map_;
|
||||
unsigned free_list_head_ = kNoFreeSlot;
|
||||
StringsStorage& function_and_resource_names_;
|
||||
};
|
||||
|
||||
class V8_EXPORT_PRIVATE CpuProfilesCollection {
|
||||
|
@ -25,8 +25,12 @@ namespace internal {
|
||||
|
||||
ProfilerListener::ProfilerListener(Isolate* isolate,
|
||||
CodeEventObserver* observer,
|
||||
StringsStorage& function_and_resource_names,
|
||||
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;
|
||||
|
||||
@ -78,9 +82,12 @@ namespace {
|
||||
CodeEntry* GetOrInsertCachedEntry(
|
||||
std::unordered_set<std::unique_ptr<CodeEntry>, CodeEntry::Hasher,
|
||||
CodeEntry::Equals>* entries,
|
||||
std::unique_ptr<CodeEntry> search_value) {
|
||||
std::unique_ptr<CodeEntry> search_value, StringsStorage& strings) {
|
||||
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();
|
||||
entries->insert(std::move(search_value));
|
||||
return ret;
|
||||
@ -168,7 +175,8 @@ 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));
|
||||
&cached_inline_entries, std::move(inline_entry),
|
||||
function_and_resource_names_);
|
||||
|
||||
inline_stack.push_back({cached_entry, line_number});
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ class CodeEventObserver {
|
||||
class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
|
||||
public:
|
||||
ProfilerListener(Isolate*, CodeEventObserver*,
|
||||
StringsStorage& function_and_resource_names,
|
||||
CpuProfilingNamingMode mode = kDebugNaming);
|
||||
~ProfilerListener() override;
|
||||
ProfilerListener(const ProfilerListener&) = delete;
|
||||
@ -89,7 +90,7 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
|
||||
|
||||
Isolate* isolate_;
|
||||
CodeEventObserver* observer_;
|
||||
StringsStorage function_and_resource_names_;
|
||||
StringsStorage& function_and_resource_names_;
|
||||
const CpuProfilingNamingMode naming_mode_;
|
||||
};
|
||||
|
||||
|
@ -49,6 +49,7 @@ const char* StringsStorage::GetFormatted(const char* format, ...) {
|
||||
}
|
||||
|
||||
const char* StringsStorage::AddOrDisposeString(char* str, int len) {
|
||||
base::MutexGuard guard(&mutex_);
|
||||
base::HashMap::Entry* entry = GetEntry(str, len);
|
||||
if (entry->value == nullptr) {
|
||||
// New entry added.
|
||||
@ -119,11 +120,15 @@ inline uint32_t ComputeStringHash(const char* str, int len) {
|
||||
} // namespace
|
||||
|
||||
bool StringsStorage::Release(const char* str) {
|
||||
base::MutexGuard guard(&mutex_);
|
||||
int len = static_cast<int>(strlen(str));
|
||||
uint32_t hash = ComputeStringHash(str, len);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "src/base/compiler-specific.h"
|
||||
#include "src/base/hashmap.h"
|
||||
#include "src/base/platform/mutex.h"
|
||||
#include "src/common/globals.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -38,13 +39,16 @@ class V8_EXPORT_PRIVATE StringsStorage {
|
||||
// result.
|
||||
const char* GetConsName(const char* prefix, Name name);
|
||||
// Reduces the refcount of the given string, freeing it if no other
|
||||
// references are made to it.
|
||||
// Returns true if the string was successfully unref'd.
|
||||
// references are made to it. Returns true if the string was successfully
|
||||
// unref'd, or false if the string was not present in the table.
|
||||
bool Release(const char* str);
|
||||
|
||||
// Returns the number of strings in the store.
|
||||
size_t GetStringCountForTesting() const;
|
||||
|
||||
// Returns true if the strings table is empty.
|
||||
bool empty() const { return names_.occupancy() == 0; }
|
||||
|
||||
private:
|
||||
static bool StringsMatch(void* key1, void* key2);
|
||||
// Adds the string to storage and returns it, or if a matching string exists
|
||||
@ -55,6 +59,7 @@ class V8_EXPORT_PRIVATE StringsStorage {
|
||||
const char* GetVFormatted(const char* format, va_list args);
|
||||
|
||||
base::CustomMatcherHashMap names_;
|
||||
base::Mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -177,7 +177,8 @@ TEST(CodeEvents) {
|
||||
isolate, symbolizer, &code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CHECK(processor->Start());
|
||||
ProfilerListener profiler_listener(isolate, processor);
|
||||
ProfilerListener profiler_listener(isolate, processor,
|
||||
*code_observer.strings());
|
||||
isolate->logger()->AddCodeEventListener(&profiler_listener);
|
||||
|
||||
// Enqueue code creation events.
|
||||
@ -232,16 +233,17 @@ TEST(TickEvents) {
|
||||
i::Handle<i::AbstractCode> frame3_code(CreateCode(isolate, &env), isolate);
|
||||
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
|
||||
ProfilerCodeObserver code_observer(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
|
||||
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
|
||||
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
|
||||
CcTest::i_isolate(), symbolizer, &code_observer, profiles,
|
||||
CcTest::i_isolate(), symbolizer, code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor);
|
||||
symbolizer, processor, code_observer);
|
||||
profiles->StartProfiling("");
|
||||
CHECK(processor->Start());
|
||||
ProfilerListener profiler_listener(isolate, processor);
|
||||
ProfilerListener profiler_listener(isolate, processor,
|
||||
*code_observer->strings());
|
||||
isolate->logger()->AddCodeEventListener(&profiler_listener);
|
||||
|
||||
profiler_listener.CodeCreateEvent(i::Logger::BUILTIN_TAG, frame1_code, "bbb");
|
||||
@ -392,16 +394,17 @@ TEST(Issue1398) {
|
||||
i::Handle<i::AbstractCode> code(CreateCode(isolate, &env), isolate);
|
||||
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
|
||||
ProfilerCodeObserver code_observer(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
|
||||
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
|
||||
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
|
||||
CcTest::i_isolate(), symbolizer, &code_observer, profiles,
|
||||
CcTest::i_isolate(), symbolizer, code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor);
|
||||
symbolizer, processor, code_observer);
|
||||
profiles->StartProfiling("");
|
||||
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");
|
||||
|
||||
@ -1245,13 +1248,13 @@ static void TickLines(bool optimize) {
|
||||
CHECK_NE(code_address, kNullAddress);
|
||||
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
|
||||
ProfilerCodeObserver code_observer(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
|
||||
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
|
||||
ProfilerEventsProcessor* processor = new SamplingEventsProcessor(
|
||||
CcTest::i_isolate(), symbolizer, &code_observer, profiles,
|
||||
CcTest::i_isolate(), symbolizer, code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor);
|
||||
symbolizer, processor, code_observer);
|
||||
profiles->StartProfiling("");
|
||||
// TODO(delphick): Stop using the CpuProfiler internals here: This forces
|
||||
// LogCompiledFunctions so that source positions are collected everywhere.
|
||||
@ -1259,7 +1262,8 @@ static void TickLines(bool optimize) {
|
||||
// but doesn't because it's constructed with a symbolizer and a processor.
|
||||
isolate->logger()->LogCompiledFunctions();
|
||||
CHECK(processor->Start());
|
||||
ProfilerListener profiler_listener(isolate, processor);
|
||||
ProfilerListener profiler_listener(isolate, processor,
|
||||
*code_observer->strings());
|
||||
|
||||
// Enqueue code creation events.
|
||||
i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
|
||||
@ -3549,14 +3553,14 @@ TEST(ProflilerSubsampling) {
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
|
||||
ProfilerCodeObserver code_observer(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
|
||||
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
|
||||
ProfilerEventsProcessor* processor =
|
||||
new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles,
|
||||
new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(1),
|
||||
/* use_precise_sampling */ true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor);
|
||||
symbolizer, processor, code_observer);
|
||||
|
||||
// Create a new CpuProfile that wants samples at 8us.
|
||||
CpuProfile profile(&profiler, "",
|
||||
@ -3593,14 +3597,14 @@ TEST(DynamicResampling) {
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
|
||||
ProfilerCodeObserver code_observer(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
|
||||
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
|
||||
ProfilerEventsProcessor* processor =
|
||||
new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles,
|
||||
new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(1),
|
||||
/* use_precise_sampling */ true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor);
|
||||
symbolizer, processor, code_observer);
|
||||
|
||||
// Set a 1us base sampling rate, dividing all possible intervals.
|
||||
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(1));
|
||||
@ -3654,14 +3658,14 @@ TEST(DynamicResamplingWithBaseInterval) {
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate);
|
||||
ProfilerCodeObserver code_observer(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer.code_map());
|
||||
ProfilerCodeObserver* code_observer = new ProfilerCodeObserver(isolate);
|
||||
Symbolizer* symbolizer = new Symbolizer(code_observer->code_map());
|
||||
ProfilerEventsProcessor* processor =
|
||||
new SamplingEventsProcessor(isolate, symbolizer, &code_observer, profiles,
|
||||
new SamplingEventsProcessor(isolate, symbolizer, code_observer, profiles,
|
||||
v8::base::TimeDelta::FromMicroseconds(1),
|
||||
/* use_precise_sampling */ true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor);
|
||||
symbolizer, processor, code_observer);
|
||||
|
||||
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); }
|
||||
static inline void* ToPointer(int n) { return reinterpret_cast<void*>(n); }
|
||||
|
||||
TEST(CodeMapAddCode) {
|
||||
CodeMap code_map;
|
||||
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");
|
||||
@ -340,7 +341,8 @@ TEST(CodeMapAddCode) {
|
||||
}
|
||||
|
||||
TEST(CodeMapMoveAndDeleteCode) {
|
||||
CodeMap code_map;
|
||||
StringsStorage strings;
|
||||
CodeMap code_map(strings);
|
||||
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
|
||||
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
|
||||
code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
|
||||
@ -357,7 +359,8 @@ TEST(CodeMapMoveAndDeleteCode) {
|
||||
}
|
||||
|
||||
TEST(CodeMapClear) {
|
||||
CodeMap code_map;
|
||||
StringsStorage strings;
|
||||
CodeMap code_map(strings);
|
||||
CodeEntry* entry1 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
|
||||
CodeEntry* entry2 = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
|
||||
code_map.AddCode(ToAddress(0x1500), entry1, 0x200);
|
||||
@ -392,7 +395,8 @@ class TestSetup {
|
||||
|
||||
TEST(SymbolizeTickSample) {
|
||||
TestSetup test_setup;
|
||||
CodeMap code_map;
|
||||
StringsStorage strings;
|
||||
CodeMap code_map(strings);
|
||||
Symbolizer symbolizer(&code_map);
|
||||
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
|
||||
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
|
||||
@ -460,7 +464,8 @@ TEST(SampleIds) {
|
||||
CpuProfiler profiler(isolate);
|
||||
profiles.set_cpu_profiler(&profiler);
|
||||
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
|
||||
CodeMap code_map;
|
||||
StringsStorage strings;
|
||||
CodeMap code_map(strings);
|
||||
Symbolizer symbolizer(&code_map);
|
||||
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
|
||||
CodeEntry* entry2 = new CodeEntry(i::Logger::FUNCTION_TAG, "bbb");
|
||||
@ -525,7 +530,8 @@ TEST(NoSamples) {
|
||||
CpuProfiler profiler(isolate);
|
||||
profiles.set_cpu_profiler(&profiler);
|
||||
profiles.StartProfiling("");
|
||||
CodeMap code_map;
|
||||
StringsStorage strings;
|
||||
CodeMap code_map(strings);
|
||||
Symbolizer symbolizer(&code_map);
|
||||
CodeEntry* entry1 = new CodeEntry(i::Logger::FUNCTION_TAG, "aaa");
|
||||
symbolizer.code_map()->AddCode(ToAddress(0x1500), entry1, 0x200);
|
||||
|
@ -141,20 +141,15 @@ TEST_F(StringsStorageWithIsolate, Refcounting) {
|
||||
CHECK_EQ(storage.GetStringCountForTesting(), 1);
|
||||
CHECK(storage.Release(d));
|
||||
CHECK_EQ(storage.GetStringCountForTesting(), 0);
|
||||
#if !DEBUG
|
||||
CHECK(!storage.Release("12"));
|
||||
#endif // !DEBUG
|
||||
}
|
||||
|
||||
TEST_F(StringsStorageWithIsolate, InvalidRelease) {
|
||||
StringsStorage storage;
|
||||
|
||||
// If a refcount becomes invalid, throw in debug builds.
|
||||
#ifdef DEBUG
|
||||
ASSERT_DEATH_IF_SUPPORTED(storage.Release("12"), "check failed");
|
||||
#else
|
||||
// If we attempt to release a string not being managed by the StringsStorage,
|
||||
// return false.
|
||||
CHECK(!storage.Release("12"));
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
TEST_F(StringsStorageWithIsolate, CopyAndConsShareStorage) {
|
||||
|
Loading…
Reference in New Issue
Block a user