blob: e52512dc561c347708db073c75642e03cf6d0539 [file] [log] [blame]
// Copyright 2024 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/js_profiler/profiler_group.h"
#include "cobalt/js_profiler/profiler_trace_builder.h"
#include "cobalt/web/context.h"
#include "cobalt/web/environment_settings_helper.h"
namespace {
v8::Local<v8::String> toV8String(v8::Isolate* isolate,
const std::string& string) {
if (string.empty()) return v8::String::Empty(isolate);
return v8::String::NewFromUtf8(isolate, string.c_str(),
v8::NewStringType::kNormal, string.length())
.ToLocalChecked();
}
} // namespace
namespace cobalt {
namespace js_profiler {
ProfilerGroup* ProfilerGroup::From(
script::EnvironmentSettings* environment_settings) {
web::Context* context = web::get_context(environment_settings);
if (!context->profiler_group()) {
script::GlobalEnvironment* global_env =
web::get_global_environment(environment_settings);
context->set_profiler_group(
std::make_unique<ProfilerGroup>(global_env->isolate()));
}
return context->profiler_group();
}
v8::CpuProfilingStatus ProfilerGroup::ProfilerStart(
const scoped_refptr<Profiler>& profiler,
script::EnvironmentSettings* settings, v8::CpuProfilingOptions options) {
if (!cpu_profiler_) {
cpu_profiler_ = v8::CpuProfiler::New(isolate_);
cpu_profiler_->SetSamplingInterval(
cobalt::js_profiler::Profiler::kBaseSampleIntervalMs *
base::Time::kMicrosecondsPerMillisecond);
}
profilers_.push_back(profiler);
num_active_profilers_++;
return cpu_profiler_->StartProfiling(
toV8String(isolate_, profiler->ProfilerId()), options,
std::make_unique<ProfilerMaxSamplesDelegate>(this,
profiler->ProfilerId()));
}
ProfilerTrace ProfilerGroup::ProfilerStop(Profiler* profiler) {
auto profile = cpu_profiler_->StopProfiling(
toV8String(isolate_, profiler->ProfilerId()));
this->PopProfiler(profiler->ProfilerId());
auto trace =
ProfilerTraceBuilder::FromProfile(profile, profiler->time_origin());
if (profile) {
profile->Delete();
}
if (cpu_profiler_ && num_active_profilers_ == 0) {
cpu_profiler_->Dispose();
cpu_profiler_ = nullptr;
}
return trace;
}
std::string ProfilerGroup::NextProfilerId() {
auto id = "cobalt::profiler[" + std::to_string(next_profiler_id_) + "]";
next_profiler_id_++;
return id;
}
void ProfilerGroup::DispatchSampleBufferFullEvent(std::string profiler_id) {
auto profiler = GetProfiler(profiler_id);
if (profiler) {
profiler->DispatchSampleBufferFullEvent();
}
}
Profiler* ProfilerGroup::GetProfiler(std::string profiler_id) {
auto profiler =
std::find_if(profilers_.begin(), profilers_.end(),
[&profiler_id](const scoped_refptr<Profiler>& profiler) {
return profiler->ProfilerId() == profiler_id;
});
if (profiler == profilers_.end()) {
return nullptr;
}
return profiler->get();
}
void ProfilerGroup::PopProfiler(std::string profiler_id) {
auto profiler = std::find_if(profilers_.begin(), profilers_.end(),
[&profiler_id](const Profiler* profiler) {
return profiler->ProfilerId() == profiler_id;
});
if (profiler != profilers_.end()) {
profilers_.erase(profiler);
}
num_active_profilers_--;
}
void ProfilerGroup::WillDestroyCurrentMessageLoop() {
while (!profilers_.empty()) {
Profiler* profiler = profilers_[0];
DCHECK(profiler);
profiler->Cancel();
DCHECK(profiler->stopped());
}
DCHECK_EQ(num_active_profilers_, 0);
if (cpu_profiler_) {
cpu_profiler_->Dispose();
cpu_profiler_ = nullptr;
}
}
void ProfilerMaxSamplesDelegate::Notify() {
if (profiler_group_.Get()) {
profiler_group_->DispatchSampleBufferFullEvent(profiler_id_);
}
}
} // namespace js_profiler
} // namespace cobalt