| // 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 |