Commit ca51ae3a authored by Corentin Pescheloche's avatar Corentin Pescheloche Committed by V8 LUCI CQ

[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: 's avatarNicolas Dubus <nicodubus@fb.com>
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3522896Reviewed-by: 's avatarCamillo 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}
parent 6cf7330a
......@@ -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]);
}
......
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