Commit 89ed6b76 authored by Andrew Comminos's avatar Andrew Comminos Committed by Commit Bot

[cpu-profiler] Add parameter to limit profiler samples taken

To prevent OOMs for leaked CPU profilers, add the option to limit the
maximum number of samples that are included in a CPU profile.

Bug: chromium:956688
Change-Id: I119d0622e7d39c187f8e09e2d49dec91fd724ecb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1588412
Commit-Queue: Andrew Comminos <acomminos@fb.com>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarAlexei Filippov <alph@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61352}
parent 7275c9c8
......@@ -5,6 +5,7 @@
#ifndef V8_V8_PROFILER_H_
#define V8_V8_PROFILER_H_
#include <limits.h>
#include <unordered_set>
#include <vector>
#include "v8.h" // NOLINT(build/include)
......@@ -312,6 +313,9 @@ enum CpuProfilingNamingMode {
*/
class V8_EXPORT CpuProfiler {
public:
// Indicates that the sample buffer size should not be explicitly limited.
static const unsigned kNoSampleLimit = UINT_MAX;
/**
* Creates a new CPU profiler for the |isolate|. The isolate must be
* initialized. The profiler object must be disposed after use by calling
......@@ -358,9 +362,14 @@ class V8_EXPORT CpuProfiler {
*
* |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.
*/
void StartProfiling(Local<String> title, CpuProfilingMode mode,
bool record_samples = false);
bool record_samples = false,
unsigned max_samples = kNoSampleLimit);
/**
* The same as StartProfiling above, but the CpuProfilingMode defaults to
* kLeafNodeLineNumbers mode, which was the previous default behavior of the
......
......@@ -10135,13 +10135,14 @@ void CpuProfiler::CollectSample() {
void CpuProfiler::StartProfiling(Local<String> title, bool record_samples) {
reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
*Utils::OpenHandle(*title), record_samples, kLeafNodeLineNumbers);
*Utils::OpenHandle(*title), record_samples, kLeafNodeLineNumbers,
kNoSampleLimit);
}
void CpuProfiler::StartProfiling(Local<String> title, CpuProfilingMode mode,
bool record_samples) {
bool record_samples, unsigned max_samples) {
reinterpret_cast<i::CpuProfiler*>(this)->StartProfiling(
*Utils::OpenHandle(*title), record_samples, mode);
*Utils::OpenHandle(*title), record_samples, mode, max_samples);
}
CpuProfile* CpuProfiler::StopProfiling(Local<String> title) {
......
......@@ -377,16 +377,16 @@ void CpuProfiler::CollectSample() {
}
void CpuProfiler::StartProfiling(const char* title, bool record_samples,
ProfilingMode mode) {
if (profiles_->StartProfiling(title, record_samples, mode)) {
ProfilingMode mode, unsigned max_samples) {
if (profiles_->StartProfiling(title, record_samples, mode, max_samples)) {
TRACE_EVENT0("v8", "CpuProfiler::StartProfiling");
StartProcessorIfNotStarted();
}
}
void CpuProfiler::StartProfiling(String title, bool record_samples,
ProfilingMode mode) {
StartProfiling(profiles_->GetName(title), record_samples, mode);
ProfilingMode mode, unsigned max_samples) {
StartProfiling(profiles_->GetName(title), record_samples, mode, max_samples);
isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler);
}
......
......@@ -255,8 +255,10 @@ class V8_EXPORT_PRIVATE CpuProfiler {
void set_use_precise_sampling(bool);
void CollectSample();
void StartProfiling(const char* title, bool record_samples = false,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
void StartProfiling(String title, bool record_samples, ProfilingMode mode);
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers,
unsigned max_samples = v8::CpuProfiler::kNoSampleLimit);
void StartProfiling(String title, bool record_samples, ProfilingMode mode,
unsigned max_samples);
CpuProfile* StopProfiling(const char* title);
CpuProfile* StopProfiling(String title);
int GetProfilesCount();
......
......@@ -474,10 +474,12 @@ using v8::tracing::TracedValue;
std::atomic<uint32_t> CpuProfile::last_id_;
CpuProfile::CpuProfile(CpuProfiler* profiler, const char* title,
bool record_samples, ProfilingMode mode)
bool record_samples, ProfilingMode mode,
unsigned max_samples)
: title_(title),
record_samples_(record_samples),
mode_(mode),
max_samples_(max_samples),
start_time_(base::TimeTicks::HighResolutionNow()),
top_down_(profiler->isolate()),
profiler_(profiler),
......@@ -496,9 +498,13 @@ void CpuProfile::AddPath(base::TimeTicks timestamp,
ProfileNode* top_frame_node =
top_down_.AddPathFromEnd(path, src_line, update_stats, mode_);
if (record_samples_ && !timestamp.IsNull()) {
bool should_record_sample =
record_samples_ && !timestamp.IsNull() &&
(max_samples_ == v8::CpuProfiler::kNoSampleLimit ||
samples_.size() < max_samples_);
if (should_record_sample)
samples_.push_back({top_frame_node, timestamp, src_line});
}
const int kSamplesFlushCount = 100;
const int kNodesFlushCount = 10;
......@@ -698,7 +704,8 @@ CpuProfilesCollection::CpuProfilesCollection(Isolate* isolate)
bool CpuProfilesCollection::StartProfiling(const char* title,
bool record_samples,
ProfilingMode mode) {
ProfilingMode mode,
unsigned max_samples) {
current_profiles_semaphore_.Wait();
if (static_cast<int>(current_profiles_.size()) >= kMaxSimultaneousProfiles) {
current_profiles_semaphore_.Signal();
......@@ -713,12 +720,11 @@ bool CpuProfilesCollection::StartProfiling(const char* title,
}
}
current_profiles_.emplace_back(
new CpuProfile(profiler_, title, record_samples, mode));
new CpuProfile(profiler_, title, record_samples, mode, max_samples));
current_profiles_semaphore_.Signal();
return true;
}
CpuProfile* CpuProfilesCollection::StopProfiling(const char* title) {
const bool empty_title = (title[0] == '\0');
CpuProfile* profile = nullptr;
......
......@@ -367,7 +367,7 @@ class CpuProfile {
};
CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples,
ProfilingMode mode);
ProfilingMode mode, unsigned max_samples);
// Add pc -> ... -> main() call path to the profile.
void AddPath(base::TimeTicks timestamp, const ProfileStackTrace& path,
......@@ -394,6 +394,7 @@ class CpuProfile {
const char* title_;
bool record_samples_;
ProfilingMode mode_;
const unsigned max_samples_;
base::TimeTicks start_time_;
base::TimeTicks end_time_;
std::deque<SampleInfo> samples_;
......@@ -451,7 +452,8 @@ class V8_EXPORT_PRIVATE CpuProfilesCollection {
void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; }
bool StartProfiling(const char* title, bool record_samples,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers,
unsigned max_samples = v8::CpuProfiler::kNoSampleLimit);
CpuProfile* StopProfiling(const char* title);
std::vector<std::unique_ptr<CpuProfile>>* profiles() {
return &finished_profiles_;
......
......@@ -441,7 +441,8 @@ class ProfilerHelper {
unsigned min_js_samples = 0,
unsigned min_external_samples = 0,
bool collect_samples = false,
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers);
ProfilingMode mode = ProfilingMode::kLeafNodeLineNumbers,
unsigned max_samples = v8::CpuProfiler::kNoSampleLimit);
v8::CpuProfiler* profiler() { return profiler_; }
......@@ -454,11 +455,12 @@ v8::CpuProfile* ProfilerHelper::Run(v8::Local<v8::Function> function,
v8::Local<v8::Value> argv[], int argc,
unsigned min_js_samples,
unsigned min_external_samples,
bool collect_samples, ProfilingMode mode) {
bool collect_samples, ProfilingMode mode,
unsigned max_samples) {
v8::Local<v8::String> profile_name = v8_str("my_profile");
profiler_->SetSamplingInterval(100);
profiler_->StartProfiling(profile_name, mode, collect_samples);
profiler_->StartProfiling(profile_name, mode, collect_samples, max_samples);
v8::internal::CpuProfiler* iprofiler =
reinterpret_cast<v8::internal::CpuProfiler*>(profiler_);
......@@ -2957,6 +2959,31 @@ TEST(DebugNaming) {
profiler->Dispose();
}
TEST(SampleLimit) {
LocalContext env;
i::Isolate* isolate = CcTest::i_isolate();
i::HandleScope scope(isolate);
CompileRun(R"(
function start() {
let val = 1;
for (let i = 0; i < 10e3; i++) {
val = (val * 2) % 3;
}
return val;
}
)");
// Take 100 samples of `start`, but set the max samples to 50.
v8::Local<v8::Function> function = GetFunction(env.local(), "start");
ProfilerHelper helper(env.local());
v8::CpuProfile* profile =
helper.Run(function, nullptr, 0, 100, 0, true,
v8::CpuProfilingMode::kLeafNodeLineNumbers, 50);
CHECK_EQ(profile->GetSamplesCount(), 50);
}
enum class EntryCountMode { kAll, kOnlyInlined };
// Count the number of unique source positions.
......
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