Commit 295c9cc6 authored by Alexei Filippov's avatar Alexei Filippov Committed by Commit Bot

[cpu-profiler] Add static CollectSample method to the CpuProfiler API.

The method forces all running profilers attached to the provided isolate
to collect a sample with the current stack.

It is going to be used to synchronize trace events generated by embedder with the samples
collected by the profiler.

Also it will finally allow us to break dependency of isolate on CPU profiler.

BUG=chromium:721099

Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I81a0f8a463f837b5201bc8edaf2eb4f3761e3ff8
Reviewed-on: https://chromium-review.googlesource.com/750264Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Alexei Filippov <alph@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49236}
parent 7e78506f
......@@ -286,6 +286,13 @@ class V8_EXPORT CpuProfiler {
*/
static CpuProfiler* New(Isolate* isolate);
/**
* Synchronously collect current stack sample in all profilers attached to
* the |isolate|. The call does not affect number of ticks recorded for
* the current top node.
*/
static void CollectSample(Isolate* isolate);
/**
* Disposes the CPU profiler object.
*/
......
......@@ -10508,6 +10508,11 @@ CpuProfiler* CpuProfiler::New(Isolate* isolate) {
void CpuProfiler::Dispose() { delete reinterpret_cast<i::CpuProfiler*>(this); }
// static
void CpuProfiler::CollectSample(Isolate* isolate) {
i::CpuProfiler::CollectSample(reinterpret_cast<i::Isolate*>(isolate));
}
void CpuProfiler::SetSamplingInterval(int us) {
DCHECK_GE(us, 0);
return reinterpret_cast<i::CpuProfiler*>(this)->set_sampling_interval(
......
......@@ -4,6 +4,9 @@
#include "src/profiler/cpu-profiler.h"
#include "src/base/lazy-instance.h"
#include "src/base/platform/mutex.h"
#include "src/base/template-utils.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
#include "src/frames-inl.h"
......@@ -241,14 +244,50 @@ void CpuProfiler::CodeEventHandler(const CodeEventsContainer& evt_rec) {
}
}
namespace {
class CpuProfilersManager {
public:
void AddProfiler(Isolate* isolate, CpuProfiler* profiler) {
base::LockGuard<base::Mutex> lock(&mutex_);
auto result = profilers_.insert(
std::pair<Isolate*, std::unique_ptr<std::set<CpuProfiler*>>>(
isolate, base::make_unique<std::set<CpuProfiler*>>()));
result.first->second->insert(profiler);
}
void RemoveProfiler(Isolate* isolate, CpuProfiler* profiler) {
base::LockGuard<base::Mutex> lock(&mutex_);
auto it = profilers_.find(isolate);
DCHECK(it != profilers_.end());
it->second->erase(profiler);
if (it->second->empty()) {
profilers_.erase(it);
}
}
void CallCollectSample(Isolate* isolate) {
base::LockGuard<base::Mutex> lock(&mutex_);
auto profilers = profilers_.find(isolate);
if (profilers == profilers_.end()) return;
for (auto it : *profilers->second) {
it->CollectSample();
}
}
private:
std::map<Isolate*, std::unique_ptr<std::set<CpuProfiler*>>> profilers_;
base::Mutex mutex_;
};
base::LazyInstance<CpuProfilersManager>::type g_profilers_manager =
LAZY_INSTANCE_INITIALIZER;
} // namespace
CpuProfiler::CpuProfiler(Isolate* isolate)
: isolate_(isolate),
sampling_interval_(base::TimeDelta::FromMicroseconds(
FLAG_cpu_profiler_sampling_interval)),
profiles_(new CpuProfilesCollection(isolate)),
is_profiling_(false) {
profiles_->set_cpu_profiler(this);
}
: CpuProfiler(isolate, new CpuProfilesCollection(isolate), nullptr,
nullptr) {}
CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles,
ProfileGenerator* test_generator,
......@@ -261,10 +300,12 @@ CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles,
processor_(test_processor),
is_profiling_(false) {
profiles_->set_cpu_profiler(this);
g_profilers_manager.Pointer()->AddProfiler(isolate, this);
}
CpuProfiler::~CpuProfiler() {
DCHECK(!is_profiling_);
g_profilers_manager.Pointer()->RemoveProfiler(isolate_, this);
}
void CpuProfiler::set_sampling_interval(base::TimeDelta value) {
......@@ -292,6 +333,11 @@ void CpuProfiler::CreateEntriesForRuntimeCallStats() {
}
}
// static
void CpuProfiler::CollectSample(Isolate* isolate) {
g_profilers_manager.Pointer()->CallCollectSample(isolate);
}
void CpuProfiler::CollectSample() {
if (processor_) {
processor_->AddCurrentStack(isolate_);
......
......@@ -195,6 +195,8 @@ class CpuProfiler : public CodeEventObserver {
~CpuProfiler() override;
static void CollectSample(Isolate* isolate);
void set_sampling_interval(base::TimeDelta value);
void CollectSample();
void StartProfiling(const char* title, bool record_samples = false);
......
......@@ -2227,6 +2227,44 @@ TEST(Issue763073) {
cpu_profiler->Dispose();
}
static const char* js_collect_sample_api_source =
"%NeverOptimizeFunction(start);\n"
"function start() {\n"
" CallStaticCollectSample();\n"
"}";
static void CallStaticCollectSample(
const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CpuProfiler::CollectSample(info.GetIsolate());
}
TEST(StaticCollectSampleAPI) {
i::FLAG_allow_natives_syntax = true;
LocalContext env;
v8::HandleScope scope(env->GetIsolate());
v8::Local<v8::FunctionTemplate> func_template =
v8::FunctionTemplate::New(env->GetIsolate(), CallStaticCollectSample);
v8::Local<v8::Function> func =
func_template->GetFunction(env.local()).ToLocalChecked();
func->SetName(v8_str("CallStaticCollectSample"));
env->Global()
->Set(env.local(), v8_str("CallStaticCollectSample"), func)
.FromJust();
CompileRun(js_collect_sample_api_source);
v8::Local<v8::Function> function = GetFunction(env.local(), "start");
ProfilerHelper helper(env.local());
v8::CpuProfile* profile = helper.Run(function, nullptr, 0, 100);
const v8::CpuProfileNode* root = profile->GetTopDownRoot();
const v8::CpuProfileNode* start_node = GetChild(env.local(), root, "start");
GetChild(env.local(), start_node, "CallStaticCollectSample");
profile->Delete();
}
} // namespace test_cpu_profiler
} // namespace internal
} // namespace v8
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