[api][profiler] Get StartProfiling, StopProfiling to accept integer ID rather than string
This CL adds support for interacting with CpuProfile with their integer id. A String ID is problematic because it forces an allocation when stopping or cancelling a Profiler which can happen during a GC when this is not allowed. Change-Id: I9a8e754bd67214be0bbc5ca051bcadf52bf71a68 Bug: chromium:1297283 Co-Authored-By: Nicolas Dubus <nicodubus@fb.com> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3522896 Reviewed-by: Camillo Bruni <cbruni@chromium.org> Auto-Submit: Corentin Pescheloche <cpescheloche@fb.com> Commit-Queue: Corentin Pescheloche <cpescheloche@fb.com> Cr-Commit-Position: refs/heads/main@{#79835}
This commit is contained in:
parent
6cf7330a61
commit
ca51ae3ac8
@ -28,6 +28,7 @@ enum StateTag : int;
|
||||
|
||||
using NativeObject = void*;
|
||||
using SnapshotObjectId = uint32_t;
|
||||
using ProfilerId = uint32_t;
|
||||
|
||||
struct CpuProfileDeoptFrame {
|
||||
int script_id;
|
||||
@ -273,15 +274,33 @@ enum class CpuProfilingStatus {
|
||||
kErrorTooManyProfilers
|
||||
};
|
||||
|
||||
/**
|
||||
* Result from StartProfiling returning the Profiling Status, and
|
||||
* id of the started profiler, or 0 if profiler is not started
|
||||
*/
|
||||
struct CpuProfilingResult {
|
||||
const ProfilerId id;
|
||||
const CpuProfilingStatus status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate for when max samples reached and samples are discarded.
|
||||
*/
|
||||
class V8_EXPORT DiscardedSamplesDelegate {
|
||||
public:
|
||||
DiscardedSamplesDelegate() {}
|
||||
DiscardedSamplesDelegate() = default;
|
||||
|
||||
virtual ~DiscardedSamplesDelegate() = default;
|
||||
virtual void Notify() = 0;
|
||||
|
||||
ProfilerId GetId() const { return profiler_id_; }
|
||||
|
||||
private:
|
||||
friend internal::CpuProfile;
|
||||
|
||||
void SetId(ProfilerId id) { profiler_id_ = id; }
|
||||
|
||||
ProfilerId profiler_id_;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -371,6 +390,45 @@ class V8_EXPORT CpuProfiler {
|
||||
*/
|
||||
void SetUsePreciseSampling(bool);
|
||||
|
||||
/**
|
||||
* Starts collecting a CPU profile. Several profiles may be collected at once.
|
||||
* Generates an anonymous profiler, without a String identifier.
|
||||
*/
|
||||
CpuProfilingResult Start(
|
||||
CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
|
||||
/**
|
||||
* Starts collecting a CPU profile. Title may be an empty string. Several
|
||||
* profiles may be collected at once. Attempts to start collecting several
|
||||
* profiles with the same title are silently ignored.
|
||||
*/
|
||||
CpuProfilingResult Start(
|
||||
Local<String> title, CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
|
||||
/**
|
||||
* Starts profiling with the same semantics as above, except with expanded
|
||||
* parameters.
|
||||
*
|
||||
* |record_samples| parameter controls whether individual samples should
|
||||
* be recorded in addition to the aggregated tree.
|
||||
*
|
||||
* |max_samples| controls the maximum number of samples that should be
|
||||
* recorded by the profiler. Samples obtained after this limit will be
|
||||
* discarded.
|
||||
*/
|
||||
CpuProfilingResult Start(
|
||||
Local<String> title, CpuProfilingMode mode, bool record_samples = false,
|
||||
unsigned max_samples = CpuProfilingOptions::kNoSampleLimit);
|
||||
|
||||
/**
|
||||
* The same as StartProfiling above, but the CpuProfilingMode defaults to
|
||||
* kLeafNodeLineNumbers mode, which was the previous default behavior of the
|
||||
* profiler.
|
||||
*/
|
||||
CpuProfilingResult Start(Local<String> title, bool record_samples = false);
|
||||
|
||||
/**
|
||||
* Starts collecting a CPU profile. Title may be an empty string. Several
|
||||
* profiles may be collected at once. Attempts to start collecting several
|
||||
@ -394,6 +452,7 @@ class V8_EXPORT CpuProfiler {
|
||||
CpuProfilingStatus StartProfiling(
|
||||
Local<String> title, CpuProfilingMode mode, bool record_samples = false,
|
||||
unsigned max_samples = CpuProfilingOptions::kNoSampleLimit);
|
||||
|
||||
/**
|
||||
* The same as StartProfiling above, but the CpuProfilingMode defaults to
|
||||
* kLeafNodeLineNumbers mode, which was the previous default behavior of the
|
||||
@ -402,6 +461,11 @@ class V8_EXPORT CpuProfiler {
|
||||
CpuProfilingStatus StartProfiling(Local<String> title,
|
||||
bool record_samples = false);
|
||||
|
||||
/**
|
||||
* Stops collecting CPU profile with a given id and returns it.
|
||||
*/
|
||||
CpuProfile* Stop(ProfilerId id);
|
||||
|
||||
/**
|
||||
* Stops collecting CPU profile with a given title and returns it.
|
||||
* If the title given is empty, finishes the last profile started.
|
||||
|
@ -9932,15 +9932,22 @@ void CpuProfiler::SetUsePreciseSampling(bool use_precise_sampling) {
|
||||
use_precise_sampling);
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(
|
||||
CpuProfilingResult CpuProfiler::Start(
|
||||
CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
return reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
|
||||
options, std::move(delegate));
|
||||
}
|
||||
|
||||
CpuProfilingResult CpuProfiler::Start(
|
||||
Local<String> title, CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
return reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
|
||||
*Utils::OpenHandle(*title), options, std::move(delegate));
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(Local<String> title,
|
||||
bool record_samples) {
|
||||
CpuProfilingResult CpuProfiler::Start(Local<String> title,
|
||||
bool record_samples) {
|
||||
CpuProfilingOptions options(
|
||||
kLeafNodeLineNumbers,
|
||||
record_samples ? CpuProfilingOptions::kNoSampleLimit : 0);
|
||||
@ -9948,13 +9955,31 @@ CpuProfilingStatus CpuProfiler::StartProfiling(Local<String> title,
|
||||
*Utils::OpenHandle(*title), options);
|
||||
}
|
||||
|
||||
CpuProfilingResult CpuProfiler::Start(Local<String> title,
|
||||
CpuProfilingMode mode,
|
||||
bool record_samples,
|
||||
unsigned max_samples) {
|
||||
CpuProfilingOptions options(mode, record_samples ? max_samples : 0);
|
||||
return reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
|
||||
*Utils::OpenHandle(*title), options);
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(
|
||||
Local<String> title, CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
return Start(title, options, std::move(delegate)).status;
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(Local<String> title,
|
||||
bool record_samples) {
|
||||
return Start(title, record_samples).status;
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(Local<String> title,
|
||||
CpuProfilingMode mode,
|
||||
bool record_samples,
|
||||
unsigned max_samples) {
|
||||
CpuProfilingOptions options(mode, record_samples ? max_samples : 0);
|
||||
return reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
|
||||
*Utils::OpenHandle(*title), options);
|
||||
return Start(title, mode, record_samples, max_samples).status;
|
||||
}
|
||||
|
||||
CpuProfile* CpuProfiler::StopProfiling(Local<String> title) {
|
||||
@ -9963,6 +9988,11 @@ CpuProfile* CpuProfiler::StopProfiling(Local<String> title) {
|
||||
*Utils::OpenHandle(*title)));
|
||||
}
|
||||
|
||||
CpuProfile* CpuProfiler::Stop(ProfilerId id) {
|
||||
return reinterpret_cast<CpuProfile*>(
|
||||
reinterpret_cast<i::CpuProfiler*>(this)->StopProfiling(id));
|
||||
}
|
||||
|
||||
void CpuProfiler::UseDetailedSourcePositionsForProfiling(Isolate* isolate) {
|
||||
reinterpret_cast<i::Isolate*>(isolate)
|
||||
->SetDetailedSourcePositionsForProfiling(true);
|
||||
|
@ -599,25 +599,31 @@ size_t CpuProfiler::GetEstimatedMemoryUsage() const {
|
||||
return code_observer_->GetEstimatedMemoryUsage();
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(
|
||||
CpuProfilingResult CpuProfiler::StartProfiling(
|
||||
CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
return StartProfiling(nullptr, options, std::move(delegate));
|
||||
}
|
||||
|
||||
CpuProfilingResult CpuProfiler::StartProfiling(
|
||||
const char* title, CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
StartProfilingStatus status =
|
||||
CpuProfilingResult result =
|
||||
profiles_->StartProfiling(title, options, std::move(delegate));
|
||||
|
||||
// TODO(nicodubus): Revisit logic for if we want to do anything different for
|
||||
// kAlreadyStarted
|
||||
if (status == CpuProfilingStatus::kStarted ||
|
||||
status == CpuProfilingStatus::kAlreadyStarted) {
|
||||
if (result.status == CpuProfilingStatus::kStarted ||
|
||||
result.status == CpuProfilingStatus::kAlreadyStarted) {
|
||||
TRACE_EVENT0("v8", "CpuProfiler::StartProfiling");
|
||||
AdjustSamplingInterval();
|
||||
StartProcessorIfNotStarted();
|
||||
}
|
||||
|
||||
return status;
|
||||
return result;
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfiler::StartProfiling(
|
||||
CpuProfilingResult CpuProfiler::StartProfiling(
|
||||
String title, CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
return StartProfiling(profiles_->GetName(title), options,
|
||||
@ -651,10 +657,19 @@ void CpuProfiler::StartProcessorIfNotStarted() {
|
||||
}
|
||||
|
||||
CpuProfile* CpuProfiler::StopProfiling(const char* title) {
|
||||
CpuProfile* profile = profiles_->Lookup(title);
|
||||
if (profile) {
|
||||
return StopProfiling(profile->id());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CpuProfile* CpuProfiler::StopProfiling(ProfilerId id) {
|
||||
if (!is_profiling_) return nullptr;
|
||||
const bool last_profile = profiles_->IsLastProfile(title);
|
||||
const bool last_profile = profiles_->IsLastProfileLeft(id);
|
||||
if (last_profile) StopProcessor();
|
||||
CpuProfile* result = profiles_->StopProfiling(title);
|
||||
|
||||
CpuProfile* profile = profiles_->StopProfiling(id);
|
||||
|
||||
AdjustSamplingInterval();
|
||||
|
||||
@ -663,7 +678,7 @@ CpuProfile* CpuProfiler::StopProfiling(const char* title) {
|
||||
DisableLogging();
|
||||
}
|
||||
|
||||
return result;
|
||||
return profile;
|
||||
}
|
||||
|
||||
CpuProfile* CpuProfiler::StopProfiling(String title) {
|
||||
|
@ -336,6 +336,7 @@ class V8_EXPORT_PRIVATE CpuProfiler {
|
||||
static size_t GetAllProfilersMemorySize(Isolate* isolate);
|
||||
|
||||
using ProfilingMode = v8::CpuProfilingMode;
|
||||
using CpuProfilingResult = v8::CpuProfilingResult;
|
||||
using NamingMode = v8::CpuProfilingNamingMode;
|
||||
using LoggingMode = v8::CpuProfilingLoggingMode;
|
||||
using StartProfilingStatus = CpuProfilingStatus;
|
||||
@ -345,15 +346,20 @@ class V8_EXPORT_PRIVATE CpuProfiler {
|
||||
void set_use_precise_sampling(bool);
|
||||
void CollectSample();
|
||||
size_t GetEstimatedMemoryUsage() const;
|
||||
StartProfilingStatus StartProfiling(
|
||||
CpuProfilingResult StartProfiling(
|
||||
CpuProfilingOptions options = {},
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
CpuProfilingResult StartProfiling(
|
||||
const char* title, CpuProfilingOptions options = {},
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
StartProfilingStatus StartProfiling(
|
||||
CpuProfilingResult StartProfiling(
|
||||
String title, CpuProfilingOptions options = {},
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
|
||||
CpuProfile* StopProfiling(const char* title);
|
||||
CpuProfile* StopProfiling(String title);
|
||||
CpuProfile* StopProfiling(ProfilerId id);
|
||||
|
||||
int GetProfilesCount();
|
||||
CpuProfile* GetProfile(int index);
|
||||
void DeleteAllProfiles();
|
||||
|
@ -570,9 +570,7 @@ void ContextFilter::OnMoveEvent(Address from_address, Address to_address) {
|
||||
|
||||
using v8::tracing::TracedValue;
|
||||
|
||||
std::atomic<uint32_t> CpuProfile::last_id_;
|
||||
|
||||
CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
|
||||
CpuProfile::CpuProfile(CpuProfiler* profiler, ProfilerId id, const char* title,
|
||||
CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate)
|
||||
: title_(title),
|
||||
@ -582,7 +580,7 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
|
||||
top_down_(profiler->isolate(), profiler->code_entries()),
|
||||
profiler_(profiler),
|
||||
streaming_next_sample_(0),
|
||||
id_(++last_id_) {
|
||||
id_(id) {
|
||||
// The startTime timestamp is not converted to Perfetto's clock domain and
|
||||
// will get out of sync with other timestamps Perfetto knows about, including
|
||||
// the automatic trace event "ts" timestamp. startTime is included for
|
||||
@ -594,6 +592,9 @@ CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
|
||||
"Profile", id_, "data", std::move(value));
|
||||
|
||||
DisallowHeapAllocation no_gc;
|
||||
if (delegate_) {
|
||||
delegate_->SetId(id_);
|
||||
}
|
||||
if (options_.has_filter_context()) {
|
||||
i::Address raw_filter_context =
|
||||
reinterpret_cast<i::Address>(options_.raw_filter_context());
|
||||
@ -891,42 +892,58 @@ size_t CodeMap::GetEstimatedMemoryUsage() const {
|
||||
}
|
||||
|
||||
CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate)
|
||||
: profiler_(nullptr), current_profiles_semaphore_(1) {}
|
||||
: profiler_(nullptr),
|
||||
current_profiles_semaphore_(1),
|
||||
last_id_(0),
|
||||
isolate_(isolate) {
|
||||
USE(isolate_);
|
||||
}
|
||||
|
||||
CpuProfilingStatus CpuProfilesCollection::StartProfiling(
|
||||
CpuProfilingResult CpuProfilesCollection::StartProfiling(
|
||||
const char* title, CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate) {
|
||||
current_profiles_semaphore_.Wait();
|
||||
|
||||
if (static_cast<int>(current_profiles_.size()) >= kMaxSimultaneousProfiles) {
|
||||
current_profiles_semaphore_.Signal();
|
||||
|
||||
return CpuProfilingStatus::kErrorTooManyProfilers;
|
||||
return {
|
||||
0,
|
||||
CpuProfilingStatus::kErrorTooManyProfilers,
|
||||
};
|
||||
}
|
||||
for (const std::unique_ptr<CpuProfile>& profile : current_profiles_) {
|
||||
if (strcmp(profile->title(), title) == 0) {
|
||||
// Ignore attempts to start profile with the same title...
|
||||
current_profiles_semaphore_.Signal();
|
||||
// ... though return kAlreadyStarted to force it collect a sample.
|
||||
return CpuProfilingStatus::kAlreadyStarted;
|
||||
|
||||
if (title != nullptr) {
|
||||
for (const std::unique_ptr<CpuProfile>& profile : current_profiles_) {
|
||||
if (profile->title() != nullptr && strcmp(profile->title(), title) == 0) {
|
||||
// Ignore attempts to start profile with the same title...
|
||||
current_profiles_semaphore_.Signal();
|
||||
// ... though return kAlreadyStarted to force it collect a sample.
|
||||
return {
|
||||
profile->id(),
|
||||
CpuProfilingStatus::kAlreadyStarted,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
current_profiles_.emplace_back(
|
||||
new CpuProfile(profiler_, title, options, std::move(delegate)));
|
||||
CpuProfile* profile = new CpuProfile(profiler_, ++last_id_, title, options,
|
||||
std::move(delegate));
|
||||
current_profiles_.emplace_back(profile);
|
||||
current_profiles_semaphore_.Signal();
|
||||
return CpuProfilingStatus::kStarted;
|
||||
|
||||
return {
|
||||
profile->id(),
|
||||
CpuProfilingStatus::kStarted,
|
||||
};
|
||||
}
|
||||
|
||||
CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
|
||||
const bool empty_title = (title[0] == '\0');
|
||||
CpuProfile* profile = nullptr;
|
||||
CpuProfile* CpuProfilesCollection::StopProfiling(ProfilerId id) {
|
||||
current_profiles_semaphore_.Wait();
|
||||
CpuProfile* profile = nullptr;
|
||||
|
||||
auto it = std::find_if(current_profiles_.rbegin(), current_profiles_.rend(),
|
||||
[&](const std::unique_ptr<CpuProfile>& p) {
|
||||
return empty_title || strcmp(p->title(), title) == 0;
|
||||
});
|
||||
auto it = std::find_if(
|
||||
current_profiles_.rbegin(), current_profiles_.rend(),
|
||||
[=](const std::unique_ptr<CpuProfile>& p) { return id == p->id(); });
|
||||
|
||||
if (it != current_profiles_.rend()) {
|
||||
(*it)->FinishProfile();
|
||||
@ -935,21 +952,44 @@ CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
|
||||
// Convert reverse iterator to matching forward iterator.
|
||||
current_profiles_.erase(--(it.base()));
|
||||
}
|
||||
|
||||
current_profiles_semaphore_.Signal();
|
||||
return profile;
|
||||
}
|
||||
|
||||
bool CpuProfilesCollection::IsLastProfile(const char* title) {
|
||||
CpuProfile* CpuProfilesCollection::Lookup(const char* title) {
|
||||
// Called from VM thread, and only it can mutate the list,
|
||||
// so no locking is needed here.
|
||||
if (current_profiles_.size() != 1) return false;
|
||||
return title[0] == '\0' || strcmp(current_profiles_[0]->title(), title) == 0;
|
||||
DCHECK_EQ(ThreadId::Current(), isolate_->thread_id());
|
||||
if (title == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
// http://crbug/51594, edge case console.profile may provide an empty title
|
||||
// and must not crash
|
||||
const bool empty_title = title[0] == '\0';
|
||||
auto it = std::find_if(
|
||||
current_profiles_.rbegin(), current_profiles_.rend(),
|
||||
[&](const std::unique_ptr<CpuProfile>& p) {
|
||||
return (empty_title ||
|
||||
(p->title() != nullptr && strcmp(p->title(), title) == 0));
|
||||
});
|
||||
if (it != current_profiles_.rend()) {
|
||||
return it->get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CpuProfilesCollection::IsLastProfileLeft(ProfilerId id) {
|
||||
// Called from VM thread, and only it can mutate the list,
|
||||
// so no locking is needed here.
|
||||
DCHECK_EQ(ThreadId::Current(), isolate_->thread_id());
|
||||
if (current_profiles_.size() != 1) return false;
|
||||
return id == current_profiles_[0]->id();
|
||||
}
|
||||
|
||||
void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
|
||||
// Called from VM thread for a completed profile.
|
||||
DCHECK_EQ(ThreadId::Current(), isolate_->thread_id());
|
||||
auto pos =
|
||||
std::find_if(finished_profiles_.begin(), finished_profiles_.end(),
|
||||
[&](const std::unique_ptr<CpuProfile>& finished_profile) {
|
||||
|
@ -411,7 +411,8 @@ class CpuProfile {
|
||||
};
|
||||
|
||||
V8_EXPORT_PRIVATE CpuProfile(
|
||||
CpuProfiler* profiler, const char* title, CpuProfilingOptions options,
|
||||
CpuProfiler* profiler, ProfilerId id, const char* title,
|
||||
CpuProfilingOptions options,
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
CpuProfile(const CpuProfile&) = delete;
|
||||
CpuProfile& operator=(const CpuProfile&) = delete;
|
||||
@ -440,6 +441,7 @@ class CpuProfile {
|
||||
base::TimeTicks end_time() const { return end_time_; }
|
||||
CpuProfiler* cpu_profiler() const { return profiler_; }
|
||||
ContextFilter& context_filter() { return context_filter_; }
|
||||
ProfilerId id() const { return id_; }
|
||||
|
||||
void UpdateTicksScale();
|
||||
|
||||
@ -458,17 +460,15 @@ class CpuProfile {
|
||||
ProfileTree top_down_;
|
||||
CpuProfiler* const profiler_;
|
||||
size_t streaming_next_sample_;
|
||||
uint32_t id_;
|
||||
const ProfilerId id_;
|
||||
// Number of microseconds worth of profiler ticks that should elapse before
|
||||
// the next sample is recorded.
|
||||
base::TimeDelta next_sample_delta_;
|
||||
|
||||
static std::atomic<uint32_t> last_id_;
|
||||
};
|
||||
|
||||
class CpuProfileMaxSamplesCallbackTask : public v8::Task {
|
||||
public:
|
||||
CpuProfileMaxSamplesCallbackTask(
|
||||
explicit CpuProfileMaxSamplesCallbackTask(
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate)
|
||||
: delegate_(std::move(delegate)) {}
|
||||
|
||||
@ -540,16 +540,18 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
|
||||
CpuProfilesCollection& operator=(const CpuProfilesCollection&) = delete;
|
||||
|
||||
void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; }
|
||||
CpuProfilingStatus StartProfiling(
|
||||
const char* title, CpuProfilingOptions options = {},
|
||||
CpuProfilingResult StartProfiling(
|
||||
const char* title = nullptr, CpuProfilingOptions options = {},
|
||||
std::unique_ptr<DiscardedSamplesDelegate> delegate = nullptr);
|
||||
|
||||
CpuProfile* StopProfiling(const char* title);
|
||||
CpuProfile* StopProfiling(ProfilerId id);
|
||||
bool IsLastProfileLeft(ProfilerId id);
|
||||
CpuProfile* Lookup(const char* title);
|
||||
|
||||
std::vector<std::unique_ptr<CpuProfile>>* profiles() {
|
||||
return &finished_profiles_;
|
||||
}
|
||||
const char* GetName(Name name) { return resource_names_.GetName(name); }
|
||||
bool IsLastProfile(const char* title);
|
||||
void RemoveProfile(CpuProfile* profile);
|
||||
|
||||
// Finds a common sampling interval dividing each CpuProfile's interval,
|
||||
@ -579,6 +581,8 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
|
||||
// Accessed by VM thread and profile generator thread.
|
||||
std::vector<std::unique_ptr<CpuProfile>> current_profiles_;
|
||||
base::Semaphore current_profiles_semaphore_;
|
||||
ProfilerId last_id_;
|
||||
Isolate* isolate_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -250,7 +250,7 @@ TEST(TickEvents) {
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor, code_observer);
|
||||
profiles->StartProfiling("");
|
||||
ProfilerId id = profiles->StartProfiling().id;
|
||||
CHECK(processor->Start());
|
||||
ProfilerListener profiler_listener(isolate, processor,
|
||||
*code_observer->code_entries(),
|
||||
@ -273,7 +273,7 @@ TEST(TickEvents) {
|
||||
|
||||
isolate->logger()->RemoveCodeEventListener(&profiler_listener);
|
||||
processor->StopSynchronously();
|
||||
CpuProfile* profile = profiles->StopProfiling("");
|
||||
CpuProfile* profile = profiles->StopProfiling(id);
|
||||
CHECK(profile);
|
||||
|
||||
// Check call trees.
|
||||
@ -409,7 +409,7 @@ TEST(Issue1398) {
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor, code_observer);
|
||||
profiles->StartProfiling("");
|
||||
ProfilerId id = profiles->StartProfiling("").id;
|
||||
CHECK(processor->Start());
|
||||
ProfilerListener profiler_listener(isolate, processor,
|
||||
*code_observer->code_entries(),
|
||||
@ -428,7 +428,7 @@ TEST(Issue1398) {
|
||||
processor->AddSample(sample);
|
||||
|
||||
processor->StopSynchronously();
|
||||
CpuProfile* profile = profiles->StopProfiling("");
|
||||
CpuProfile* profile = profiles->StopProfiling(id);
|
||||
CHECK(profile);
|
||||
|
||||
unsigned actual_depth = 0;
|
||||
@ -1288,7 +1288,7 @@ static void TickLines(bool optimize) {
|
||||
v8::base::TimeDelta::FromMicroseconds(100), true);
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging, profiles,
|
||||
symbolizer, processor, code_observer);
|
||||
profiles->StartProfiling("");
|
||||
ProfilerId id = profiles->StartProfiling().id;
|
||||
// TODO(delphick): Stop using the CpuProfiler internals here: This forces
|
||||
// LogCompiledFunctions so that source positions are collected everywhere.
|
||||
// This would normally happen automatically with CpuProfiler::StartProfiling
|
||||
@ -1312,7 +1312,7 @@ static void TickLines(bool optimize) {
|
||||
|
||||
processor->StopSynchronously();
|
||||
|
||||
CpuProfile* profile = profiles->StopProfiling("");
|
||||
CpuProfile* profile = profiles->StopProfiling(id);
|
||||
CHECK(profile);
|
||||
|
||||
// Check the state of the symbolizer.
|
||||
@ -3652,7 +3652,7 @@ TEST(ProflilerSubsampling) {
|
||||
symbolizer, processor, code_observer);
|
||||
|
||||
// Create a new CpuProfile that wants samples at 8us.
|
||||
CpuProfile profile(&profiler, "",
|
||||
CpuProfile profile(&profiler, 1, "",
|
||||
{v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 8});
|
||||
// Verify that the first sample is always included.
|
||||
@ -3705,38 +3705,47 @@ TEST(DynamicResampling) {
|
||||
|
||||
// Add a 10us profiler, verify that the base sampling interval is as high as
|
||||
// possible (10us).
|
||||
profiles->StartProfiling("10us",
|
||||
ProfilerId id_10us =
|
||||
profiles
|
||||
->StartProfiling("10us",
|
||||
{v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 10});
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 10})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(10));
|
||||
|
||||
// Add a 5us profiler, verify that the base sampling interval is as high as
|
||||
// possible given a 10us and 5us profiler (5us).
|
||||
profiles->StartProfiling("5us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 5});
|
||||
ProfilerId id_5us =
|
||||
profiles
|
||||
->StartProfiling("5us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 5})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(5));
|
||||
|
||||
// Add a 3us profiler, verify that the base sampling interval is 1us (due to
|
||||
// coprime intervals).
|
||||
profiles->StartProfiling("3us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 3});
|
||||
ProfilerId id_3us =
|
||||
profiles
|
||||
->StartProfiling("3us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 3})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(1));
|
||||
|
||||
// Remove the 5us profiler, verify that the sample interval stays at 1us.
|
||||
profiles->StopProfiling("5us");
|
||||
profiles->StopProfiling(id_5us);
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(1));
|
||||
|
||||
// Remove the 10us profiler, verify that the sample interval becomes 3us.
|
||||
profiles->StopProfiling("10us");
|
||||
profiles->StopProfiling(id_10us);
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(3));
|
||||
|
||||
// Remove the 3us profiler, verify that the sample interval becomes unset.
|
||||
profiles->StopProfiling("3us");
|
||||
profiles->StopProfiling(id_3us);
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(), base::TimeDelta());
|
||||
}
|
||||
|
||||
@ -3767,43 +3776,55 @@ TEST(DynamicResamplingWithBaseInterval) {
|
||||
|
||||
// Add a profiler with an unset sampling interval, verify that the common
|
||||
// sampling interval is equal to the base.
|
||||
profiles->StartProfiling("unset", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit});
|
||||
ProfilerId unset_id =
|
||||
profiles
|
||||
->StartProfiling("unset", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(7));
|
||||
profiles->StopProfiling("unset");
|
||||
profiles->StopProfiling(unset_id);
|
||||
|
||||
// Adding a 8us sampling interval rounds to a 14us base interval.
|
||||
profiles->StartProfiling("8us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 8});
|
||||
ProfilerId id_8us =
|
||||
profiles
|
||||
->StartProfiling("8us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 8})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(14));
|
||||
|
||||
// Adding a 4us sampling interval should cause a lowering to a 7us interval.
|
||||
profiles->StartProfiling("4us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 4});
|
||||
ProfilerId id_4us =
|
||||
profiles
|
||||
->StartProfiling("4us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 4})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(7));
|
||||
|
||||
// Removing the 4us sampling interval should restore the 14us sampling
|
||||
// interval.
|
||||
profiles->StopProfiling("4us");
|
||||
profiles->StopProfiling(id_4us);
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(14));
|
||||
|
||||
// Removing the 8us sampling interval should unset the common sampling
|
||||
// interval.
|
||||
profiles->StopProfiling("8us");
|
||||
profiles->StopProfiling(id_8us);
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(), base::TimeDelta());
|
||||
|
||||
// A sampling interval of 0us should enforce all profiles to have a sampling
|
||||
// interval of 0us (the only multiple of 0).
|
||||
profiler.set_sampling_interval(base::TimeDelta::FromMicroseconds(0));
|
||||
profiles->StartProfiling("5us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 5});
|
||||
ProfilerId id_5us =
|
||||
profiles
|
||||
->StartProfiling("5us", {v8::CpuProfilingMode::kLeafNodeLineNumbers,
|
||||
v8::CpuProfilingOptions::kNoSampleLimit, 5})
|
||||
.id;
|
||||
CHECK_EQ(profiles->GetCommonSamplingInterval(),
|
||||
base::TimeDelta::FromMicroseconds(0));
|
||||
profiles->StopProfiling("5us");
|
||||
profiles->StopProfiling(id_5us);
|
||||
}
|
||||
|
||||
// Tests that functions compiled after a started profiler is stopped are still
|
||||
@ -4388,6 +4409,34 @@ v8::Local<v8::Function> CreateApiCode(LocalContext* env) {
|
||||
return GetFunction(env->local(), foo_name);
|
||||
}
|
||||
|
||||
TEST(CanStartStopProfilerWithTitlesAndIds) {
|
||||
TestSetup test_setup;
|
||||
LocalContext env;
|
||||
i::Isolate* isolate = CcTest::i_isolate();
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
CpuProfiler profiler(isolate, kDebugNaming, kLazyLogging);
|
||||
ProfilerId anonymous_id_1 = profiler.StartProfiling().id;
|
||||
ProfilerId title_id = profiler.StartProfiling("title").id;
|
||||
ProfilerId anonymous_id_2 = profiler.StartProfiling().id;
|
||||
|
||||
CHECK_NE(anonymous_id_1, title_id);
|
||||
CHECK_NE(anonymous_id_1, anonymous_id_2);
|
||||
CHECK_NE(anonymous_id_2, title_id);
|
||||
|
||||
CpuProfile* profile_with_title = profiler.StopProfiling("title");
|
||||
CHECK(profile_with_title);
|
||||
CHECK_EQ(title_id, profile_with_title->id());
|
||||
|
||||
CpuProfile* profile_with_id = profiler.StopProfiling(anonymous_id_1);
|
||||
CHECK(profile_with_id);
|
||||
CHECK_EQ(anonymous_id_1, profile_with_id->id());
|
||||
|
||||
CpuProfile* profile_with_id_2 = profiler.StopProfiling(anonymous_id_2);
|
||||
CHECK(profile_with_id_2);
|
||||
CHECK_EQ(anonymous_id_2, profile_with_id_2->id());
|
||||
}
|
||||
|
||||
TEST(FastApiCPUProfiler) {
|
||||
#if !defined(V8_LITE_MODE) && !defined(USE_SIMULATOR)
|
||||
// None of the following configurations include JSCallReducer.
|
||||
|
@ -461,7 +461,8 @@ TEST(SampleIds) {
|
||||
CpuProfiler profiler(isolate);
|
||||
CpuProfilesCollection profiles(isolate);
|
||||
profiles.set_cpu_profiler(&profiler);
|
||||
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
|
||||
ProfilerId id =
|
||||
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers}).id;
|
||||
CodeEntryStorage storage;
|
||||
CodeMap code_map(storage);
|
||||
Symbolizer symbolizer(&code_map);
|
||||
@ -509,7 +510,7 @@ TEST(SampleIds) {
|
||||
sample3.timestamp, symbolized.stack_trace, symbolized.src_line, true,
|
||||
base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||
|
||||
CpuProfile* profile = profiles.StopProfiling("");
|
||||
CpuProfile* profile = profiles.StopProfiling(id);
|
||||
unsigned nodeId = 1;
|
||||
CheckNodeIds(profile->top_down()->root(), &nodeId);
|
||||
CHECK_EQ(7u, nodeId - 1);
|
||||
@ -521,11 +522,25 @@ TEST(SampleIds) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SampleIds_StopProfilingByProfilerId) {
|
||||
TestSetup test_setup;
|
||||
i::Isolate* isolate = CcTest::i_isolate();
|
||||
CpuProfiler profiler(isolate);
|
||||
CpuProfilesCollection profiles(isolate);
|
||||
profiles.set_cpu_profiler(&profiler);
|
||||
CpuProfilingResult result =
|
||||
profiles.StartProfiling("", {CpuProfilingMode::kLeafNodeLineNumbers});
|
||||
CHECK_EQ(result.status, CpuProfilingStatus::kStarted);
|
||||
|
||||
CpuProfile* profile = profiles.StopProfiling(result.id);
|
||||
CHECK_NE(profile, nullptr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class DiscardedSamplesDelegateImpl : public v8::DiscardedSamplesDelegate {
|
||||
public:
|
||||
DiscardedSamplesDelegateImpl() : DiscardedSamplesDelegate() {}
|
||||
void Notify() override {}
|
||||
void Notify() override { CHECK_GT(GetId(), 0); }
|
||||
};
|
||||
|
||||
class MockPlatform final : public TestPlatform {
|
||||
@ -581,10 +596,13 @@ TEST_WITH_PLATFORM(MaxSamplesCallback, MockPlatform) {
|
||||
std::unique_ptr<DiscardedSamplesDelegateImpl> impl =
|
||||
std::make_unique<DiscardedSamplesDelegateImpl>(
|
||||
DiscardedSamplesDelegateImpl());
|
||||
profiles.StartProfiling("",
|
||||
ProfilerId id =
|
||||
profiles
|
||||
.StartProfiling("",
|
||||
{v8::CpuProfilingMode::kLeafNodeLineNumbers, 1, 1,
|
||||
MaybeLocal<v8::Context>()},
|
||||
std::move(impl));
|
||||
std::move(impl))
|
||||
.id;
|
||||
|
||||
CodeEntryStorage storage;
|
||||
CodeMap code_map(storage);
|
||||
@ -620,7 +638,7 @@ TEST_WITH_PLATFORM(MaxSamplesCallback, MockPlatform) {
|
||||
CHECK_EQ(1, platform.posted_count());
|
||||
|
||||
// Teardown
|
||||
profiles.StopProfiling("");
|
||||
profiles.StopProfiling(id);
|
||||
}
|
||||
|
||||
TEST(NoSamples) {
|
||||
@ -629,7 +647,7 @@ TEST(NoSamples) {
|
||||
CpuProfiler profiler(isolate);
|
||||
CpuProfilesCollection profiles(isolate);
|
||||
profiles.set_cpu_profiler(&profiler);
|
||||
profiles.StartProfiling("");
|
||||
ProfilerId id = profiles.StartProfiling().id;
|
||||
CodeEntryStorage storage;
|
||||
CodeMap code_map(storage);
|
||||
Symbolizer symbolizer(&code_map);
|
||||
@ -647,7 +665,7 @@ TEST(NoSamples) {
|
||||
v8::base::TimeTicks::Now(), symbolized.stack_trace, symbolized.src_line,
|
||||
true, base::TimeDelta(), StateTag::JS, EmbedderStateTag::EMPTY);
|
||||
|
||||
CpuProfile* profile = profiles.StopProfiling("");
|
||||
CpuProfile* profile = profiles.StopProfiling(id);
|
||||
unsigned nodeId = 1;
|
||||
CheckNodeIds(profile->top_down()->root(), &nodeId);
|
||||
CHECK_EQ(3u, nodeId - 1);
|
||||
@ -722,11 +740,11 @@ TEST(Issue51919) {
|
||||
base::Vector<char> title = v8::base::Vector<char>::New(16);
|
||||
base::SNPrintF(title, "%d", i);
|
||||
CHECK_EQ(CpuProfilingStatus::kStarted,
|
||||
collection.StartProfiling(title.begin()));
|
||||
collection.StartProfiling(title.begin()).status);
|
||||
titles[i] = title.begin();
|
||||
}
|
||||
CHECK_EQ(CpuProfilingStatus::kErrorTooManyProfilers,
|
||||
collection.StartProfiling("maximum"));
|
||||
collection.StartProfiling("maximum").status);
|
||||
for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i)
|
||||
i::DeleteArray(titles[i]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user