1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "flutter/shell/profiling/sampling_profiler.h" |
6 | |
7 | namespace flutter { |
8 | |
9 | SamplingProfiler::SamplingProfiler( |
10 | const char* thread_label, |
11 | fml::RefPtr<fml::TaskRunner> profiler_task_runner, |
12 | Sampler sampler, |
13 | int num_samples_per_sec) |
14 | : thread_label_(thread_label), |
15 | profiler_task_runner_(profiler_task_runner), |
16 | sampler_(std::move(sampler)), |
17 | num_samples_per_sec_(num_samples_per_sec) {} |
18 | |
19 | void SamplingProfiler::Start() const { |
20 | if (!profiler_task_runner_) { |
21 | return; |
22 | } |
23 | FML_CHECK(num_samples_per_sec_ > 0) |
24 | << "number of samples must be a positive integer, got: " |
25 | << num_samples_per_sec_; |
26 | double delay_between_samples = 1.0 / num_samples_per_sec_; |
27 | auto task_delay = fml::TimeDelta::FromSecondsF(delay_between_samples); |
28 | UpdateObservatoryThreadName(); |
29 | SampleRepeatedly(task_delay); |
30 | } |
31 | |
32 | void SamplingProfiler::SampleRepeatedly(fml::TimeDelta task_delay) const { |
33 | profiler_task_runner_->PostDelayedTask( |
34 | [profiler = this, task_delay = task_delay, sampler = sampler_]() { |
35 | // TODO(kaushikiska): consider buffering these every n seconds to |
36 | // avoid spamming the trace buffer. |
37 | const ProfileSample usage = sampler(); |
38 | if (usage.cpu_usage) { |
39 | const auto& cpu_usage = usage.cpu_usage; |
40 | std::string total_cpu_usage = |
41 | std::to_string(cpu_usage->total_cpu_usage); |
42 | std::string num_threads = std::to_string(cpu_usage->num_threads); |
43 | TRACE_EVENT_INSTANT2("flutter::profiling" , "CpuUsage" , |
44 | "total_cpu_usage" , total_cpu_usage.c_str(), |
45 | "num_threads" , num_threads.c_str()); |
46 | } |
47 | if (usage.memory_usage) { |
48 | std::string dirty_memory_usage = |
49 | std::to_string(usage.memory_usage->dirty_memory_usage); |
50 | std::string owned_shared_memory_usage = |
51 | std::to_string(usage.memory_usage->owned_shared_memory_usage); |
52 | TRACE_EVENT_INSTANT2("flutter::profiling" , "MemoryUsage" , |
53 | "dirty_memory_usage" , dirty_memory_usage.c_str(), |
54 | "owned_shared_memory_usage" , |
55 | owned_shared_memory_usage.c_str()); |
56 | } |
57 | if (usage.gpu_usage) { |
58 | std::string gpu_usage = |
59 | std::to_string(usage.gpu_usage->percent_usage); |
60 | TRACE_EVENT_INSTANT1("flutter::profiling" , "GpuUsage" , "gpu_usage" , |
61 | gpu_usage.c_str()); |
62 | } |
63 | profiler->SampleRepeatedly(task_delay); |
64 | }, |
65 | task_delay); |
66 | } |
67 | |
68 | void SamplingProfiler::UpdateObservatoryThreadName() const { |
69 | FML_CHECK(profiler_task_runner_); |
70 | |
71 | profiler_task_runner_->PostTask( |
72 | [label = thread_label_ + std::string{".profiler" }]() { |
73 | Dart_SetThreadName(label.c_str()); |
74 | }); |
75 | } |
76 | |
77 | } // namespace flutter |
78 | |