blob: c6058b76cd4c7539ccdc0d22e8f54c9c4f004187 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/profiling/sampling_profiler.h"
#include <utility>
namespace flutter {
SamplingProfiler::SamplingProfiler(
const char* thread_label,
fml::RefPtr<fml::TaskRunner> profiler_task_runner,
Sampler sampler,
int num_samples_per_sec)
: thread_label_(thread_label),
profiler_task_runner_(std::move(profiler_task_runner)),
sampler_(std::move(sampler)),
num_samples_per_sec_(num_samples_per_sec) {}
SamplingProfiler::~SamplingProfiler() {
if (is_running_) {
Stop();
}
}
void SamplingProfiler::Start() {
if (!profiler_task_runner_) {
return;
}
FML_CHECK(num_samples_per_sec_ > 0)
<< "number of samples must be a positive integer, got: "
<< num_samples_per_sec_;
double delay_between_samples = 1.0 / num_samples_per_sec_;
auto task_delay = fml::TimeDelta::FromSecondsF(delay_between_samples);
UpdateObservatoryThreadName();
is_running_ = true;
SampleRepeatedly(task_delay);
}
void SamplingProfiler::Stop() {
FML_DCHECK(is_running_);
auto latch = std::make_unique<fml::AutoResetWaitableEvent>();
shutdown_latch_.store(latch.get());
latch->Wait();
shutdown_latch_.store(nullptr);
is_running_ = false;
}
void SamplingProfiler::SampleRepeatedly(fml::TimeDelta task_delay) const {
profiler_task_runner_->PostDelayedTask(
[profiler = this, task_delay = task_delay, sampler = sampler_,
&shutdown_latch = shutdown_latch_]() {
// TODO(kaushikiska): consider buffering these every n seconds to
// avoid spamming the trace buffer.
const ProfileSample usage = sampler();
if (usage.cpu_usage) {
const auto& cpu_usage = usage.cpu_usage;
std::string total_cpu_usage =
std::to_string(cpu_usage->total_cpu_usage);
std::string num_threads = std::to_string(cpu_usage->num_threads);
TRACE_EVENT_INSTANT2("flutter::profiling", "CpuUsage",
"total_cpu_usage", total_cpu_usage.c_str(),
"num_threads", num_threads.c_str());
}
if (usage.memory_usage) {
std::string dirty_memory_usage =
std::to_string(usage.memory_usage->dirty_memory_usage);
std::string owned_shared_memory_usage =
std::to_string(usage.memory_usage->owned_shared_memory_usage);
TRACE_EVENT_INSTANT2("flutter::profiling", "MemoryUsage",
"dirty_memory_usage", dirty_memory_usage.c_str(),
"owned_shared_memory_usage",
owned_shared_memory_usage.c_str());
}
if (usage.gpu_usage) {
std::string gpu_usage =
std::to_string(usage.gpu_usage->percent_usage);
TRACE_EVENT_INSTANT1("flutter::profiling", "GpuUsage", "gpu_usage",
gpu_usage.c_str());
}
if (shutdown_latch.load()) {
shutdown_latch.load()->Signal();
} else {
profiler->SampleRepeatedly(task_delay);
}
},
task_delay);
}
void SamplingProfiler::UpdateObservatoryThreadName() const {
FML_CHECK(profiler_task_runner_);
profiler_task_runner_->PostTask(
[label = thread_label_ + std::string{".profiler"}]() {
Dart_SetThreadName(label.c_str());
});
}
} // namespace flutter