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 | #ifndef FLUTTER_SHELL_PROFILING_SAMPLING_PROFILER_H_ |
6 | #define FLUTTER_SHELL_PROFILING_SAMPLING_PROFILER_H_ |
7 | |
8 | #include <functional> |
9 | #include <memory> |
10 | #include <optional> |
11 | #include <string> |
12 | |
13 | #include "flutter/fml/task_runner.h" |
14 | #include "flutter/fml/trace_event.h" |
15 | |
16 | namespace flutter { |
17 | |
18 | /** |
19 | * @brief CPU usage stats. `num_threads` is the number of threads owned by the |
20 | * process. It is to be noted that this is not per shell, there can be multiple |
21 | * shells within the process. `total_cpu_usage` is the percentage (between [0, |
22 | * 100]) cpu usage of the application. This is across all the cores, for example |
23 | * an application using 100% of all the core will report `total_cpu_usage` as |
24 | * `100`, if it has 100% across 2 cores and 0% across the other cores, embedder |
25 | * must report `total_cpu_usage` as `50`. |
26 | */ |
27 | struct CpuUsageInfo { |
28 | uint32_t num_threads; |
29 | double total_cpu_usage; |
30 | }; |
31 | |
32 | /** |
33 | * @brief Memory usage stats. `dirty_memory_usage` is the the memory usage (in |
34 | * MB) such that the app uses its physical memory for dirty memory. Dirty memory |
35 | * is the memory data that cannot be paged to disk. `owned_shared_memory_usage` |
36 | * is the memory usage (in MB) such that the app uses its physicaal memory for |
37 | * shared memory, including loaded frameworks and executables. On iOS, it's |
38 | * `physical memory - dirty memory`. |
39 | */ |
40 | struct MemoryUsageInfo { |
41 | double dirty_memory_usage; |
42 | double owned_shared_memory_usage; |
43 | }; |
44 | |
45 | /** |
46 | * @brief Polled information related to the usage of the GPU. |
47 | */ |
48 | struct GpuUsageInfo { |
49 | double percent_usage; |
50 | }; |
51 | |
52 | /** |
53 | * @brief Container for the metrics we collect during each run of `Sampler`. |
54 | * This currently holds `CpuUsageInfo` and `MemoryUsageInfo` but the intent |
55 | * is to expand it to other metrics. |
56 | * |
57 | * @see flutter::Sampler |
58 | */ |
59 | struct ProfileSample { |
60 | std::optional<CpuUsageInfo> cpu_usage; |
61 | std::optional<MemoryUsageInfo> memory_usage; |
62 | std::optional<GpuUsageInfo> gpu_usage; |
63 | }; |
64 | |
65 | /** |
66 | * @brief Sampler is run during `SamplingProfiler::SampleRepeatedly`. Each |
67 | * platform should implement its version of a `Sampler` if they decide to |
68 | * participate in gathering profiling metrics. |
69 | * |
70 | * @see flutter::SamplingProfiler::SampleRepeatedly |
71 | */ |
72 | using Sampler = std::function<ProfileSample(void)>; |
73 | |
74 | /** |
75 | * @brief a Sampling Profiler that runs peridically and calls the `Sampler` |
76 | * which servers as a value function to gather various profiling metrics as |
77 | * represented by `ProfileSample`. These profiling metrics are then posted to |
78 | * the observatory timeline. |
79 | * |
80 | */ |
81 | class SamplingProfiler { |
82 | public: |
83 | /** |
84 | * @brief Construct a new Sampling Profiler object |
85 | * |
86 | * @param thread_label observatory prefix to be set for the profiling task |
87 | * runner. |
88 | * @param profiler_task_runner the task runner to service sampling requests. |
89 | * @param sampler the value function to collect the profiling metrics. |
90 | * @param num_samples_per_sec number of times you wish to run the sampler per |
91 | * second. |
92 | * |
93 | * @see fml::TaskRunner |
94 | */ |
95 | SamplingProfiler(const char* thread_label, |
96 | fml::RefPtr<fml::TaskRunner> profiler_task_runner, |
97 | Sampler sampler, |
98 | int num_samples_per_sec); |
99 | |
100 | /** |
101 | * @brief Starts the SamplingProfiler by triggering `SampleRepeatedly`. |
102 | * |
103 | */ |
104 | void Start() const; |
105 | |
106 | private: |
107 | const std::string thread_label_; |
108 | const fml::RefPtr<fml::TaskRunner> profiler_task_runner_; |
109 | const Sampler sampler_; |
110 | const uint32_t num_samples_per_sec_; |
111 | |
112 | void SampleRepeatedly(fml::TimeDelta task_delay) const; |
113 | |
114 | /** |
115 | * @brief This doesn't update the underlying OS thread name for the thread |
116 | * backing `profiler_task_runner_`. Instead, this is just additional metadata |
117 | * for the Observatory to show the thread name of the isolate. |
118 | * |
119 | */ |
120 | void UpdateObservatoryThreadName() const; |
121 | |
122 | FML_DISALLOW_COPY_AND_ASSIGN(SamplingProfiler); |
123 | }; |
124 | |
125 | } // namespace flutter |
126 | |
127 | #endif // FLUTTER_SHELL_PROFILING_SAMPLING_PROFILER_H_ |
128 | |