| // 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. | |
| #ifndef FLUTTER_SHELL_PROFILING_SAMPLING_PROFILER_H_ | |
| #define FLUTTER_SHELL_PROFILING_SAMPLING_PROFILER_H_ | |
| #include <functional> | |
| #include <memory> | |
| #include <optional> | |
| #include <string> | |
| #include "flutter/fml/synchronization/count_down_latch.h" | |
| #include "flutter/fml/task_runner.h" | |
| #include "flutter/fml/trace_event.h" | |
| namespace flutter { | |
| /** | |
| * @brief CPU usage stats. `num_threads` is the number of threads owned by the | |
| * process. It is to be noted that this is not per shell, there can be multiple | |
| * shells within the process. `total_cpu_usage` is the percentage (between [0, | |
| * 100]) cpu usage of the application. This is across all the cores, for example | |
| * an application using 100% of all the core will report `total_cpu_usage` as | |
| * `100`, if it has 100% across 2 cores and 0% across the other cores, embedder | |
| * must report `total_cpu_usage` as `50`. | |
| */ | |
| struct CpuUsageInfo { | |
| uint32_t num_threads; | |
| double total_cpu_usage; | |
| }; | |
| /** | |
| * @brief Memory usage stats. `dirty_memory_usage` is the memory usage (in | |
| * MB) such that the app uses its physical memory for dirty memory. Dirty memory | |
| * is the memory data that cannot be paged to disk. `owned_shared_memory_usage` | |
| * is the memory usage (in MB) such that the app uses its physical memory for | |
| * shared memory, including loaded frameworks and executables. On iOS, it's | |
| * `physical memory - dirty memory`. | |
| */ | |
| struct MemoryUsageInfo { | |
| double dirty_memory_usage; | |
| double owned_shared_memory_usage; | |
| }; | |
| /** | |
| * @brief Polled information related to the usage of the GPU. | |
| */ | |
| struct GpuUsageInfo { | |
| double percent_usage; | |
| }; | |
| /** | |
| * @brief Container for the metrics we collect during each run of `Sampler`. | |
| * This currently holds `CpuUsageInfo` and `MemoryUsageInfo` but the intent | |
| * is to expand it to other metrics. | |
| * | |
| * @see flutter::Sampler | |
| */ | |
| struct ProfileSample { | |
| std::optional<CpuUsageInfo> cpu_usage; | |
| std::optional<MemoryUsageInfo> memory_usage; | |
| std::optional<GpuUsageInfo> gpu_usage; | |
| }; | |
| /** | |
| * @brief Sampler is run during `SamplingProfiler::SampleRepeatedly`. Each | |
| * platform should implement its version of a `Sampler` if they decide to | |
| * participate in gathering profiling metrics. | |
| * | |
| * @see flutter::SamplingProfiler::SampleRepeatedly | |
| */ | |
| using Sampler = std::function<ProfileSample(void)>; | |
| /** | |
| * @brief a Sampling Profiler that runs peridically and calls the `Sampler` | |
| * which servers as a value function to gather various profiling metrics as | |
| * represented by `ProfileSample`. These profiling metrics are then posted to | |
| * the Dart VM Service timeline. | |
| * | |
| */ | |
| class SamplingProfiler { | |
| public: | |
| /** | |
| * @brief Construct a new Sampling Profiler object | |
| * | |
| * @param thread_label Dart VM Service prefix to be set for the profiling task | |
| * runner. | |
| * @param profiler_task_runner the task runner to service sampling requests. | |
| * @param sampler the value function to collect the profiling metrics. | |
| * @param num_samples_per_sec number of times you wish to run the sampler per | |
| * second. | |
| * | |
| * @see fml::TaskRunner | |
| */ | |
| SamplingProfiler(const char* thread_label, | |
| fml::RefPtr<fml::TaskRunner> profiler_task_runner, | |
| Sampler sampler, | |
| int num_samples_per_sec); | |
| ~SamplingProfiler(); | |
| /** | |
| * @brief Starts the SamplingProfiler by triggering `SampleRepeatedly`. | |
| * | |
| */ | |
| void Start(); | |
| void Stop(); | |
| private: | |
| const std::string thread_label_; | |
| const fml::RefPtr<fml::TaskRunner> profiler_task_runner_; | |
| const Sampler sampler_; | |
| const uint32_t num_samples_per_sec_; | |
| bool is_running_ = false; | |
| std::atomic<fml::AutoResetWaitableEvent*> shutdown_latch_ = nullptr; | |
| void SampleRepeatedly(fml::TimeDelta task_delay) const; | |
| /** | |
| * @brief This doesn't update the underlying OS thread name for the thread | |
| * backing `profiler_task_runner_`. Instead, this is just additional metadata | |
| * for the VM Service to show the thread name of the isolate. | |
| * | |
| */ | |
| void UpdateDartVMServiceThreadName() const; | |
| FML_DISALLOW_COPY_AND_ASSIGN(SamplingProfiler); | |
| }; | |
| } // namespace flutter | |
| #endif // FLUTTER_SHELL_PROFILING_SAMPLING_PROFILER_H_ |