[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/750264 Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Alexei Filippov <alph@chromium.org> Cr-Commit-Position: refs/heads/master@{#49236}
This commit is contained in:
parent
7e78506fc2
commit
295c9cc643
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user