| // Copyright 2019 The Chromium 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 "chrome/browser/performance_monitor/system_monitor.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/feature_list.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/task/post_task.h" |
| #include "base/task_runner_util.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/performance_monitor/system_monitor_metrics_logger.h" |
| |
| #if defined(OS_WIN) |
| #include "chrome/browser/performance_monitor/metric_evaluator_helper_win.h" |
| #elif defined(OS_POSIX) |
| #include "chrome/browser/performance_monitor/metric_evaluator_helper_posix.h" |
| #endif |
| |
| namespace performance_monitor { |
| |
| namespace { |
| |
| using MetricRefreshFrequencies = |
| SystemMonitor::SystemObserver::MetricRefreshFrequencies; |
| |
| // The global instance. |
| SystemMonitor* g_system_metrics_monitor = nullptr; |
| |
| // The default interval at which the metrics are refreshed. |
| constexpr base::TimeDelta kDefaultRefreshInterval = |
| base::TimeDelta::FromSeconds(2); |
| |
| const base::Feature kSystemMonitorMetricLogger{ |
| "SystemMonitorMetricLogger", base::FEATURE_DISABLED_BY_DEFAULT}; |
| |
| std::unique_ptr<MetricEvaluatorsHelper> CreateMetricEvaluatorsHelper() { |
| #if defined(OS_WIN) |
| MetricEvaluatorsHelper* helper = new MetricEvaluatorsHelperWin(); |
| #elif defined(OS_POSIX) |
| MetricEvaluatorsHelper* helper = new MetricEvaluatorsHelperPosix(); |
| #else |
| #error Unsupported platform |
| #endif |
| return base::WrapUnique(helper); |
| } |
| |
| } // namespace |
| |
| SystemMonitor::SystemMonitor( |
| std::unique_ptr<MetricEvaluatorsHelper> metric_evaluators_helper) |
| : blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits( |
| {base::MayBlock(), |
| base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), |
| metric_evaluators_helper_( |
| metric_evaluators_helper.release(), |
| base::OnTaskRunnerDeleter(blocking_task_runner_)), |
| metric_evaluators_metadata_(CreateMetricMetadataArray()), |
| weak_factory_(this) { |
| DCHECK(!g_system_metrics_monitor); |
| g_system_metrics_monitor = this; |
| |
| if (base::FeatureList::IsEnabled(kSystemMonitorMetricLogger)) { |
| // This has to be created after initializing |g_system_metrics_monitor|. |
| metrics_logger_ = std::make_unique<SystemMonitorMetricsLogger>(); |
| } |
| } |
| |
| SystemMonitor::~SystemMonitor() { |
| DCHECK_EQ(this, g_system_metrics_monitor); |
| g_system_metrics_monitor = nullptr; |
| } |
| |
| // static |
| std::unique_ptr<SystemMonitor> SystemMonitor::Create() { |
| DCHECK(!g_system_metrics_monitor); |
| return base::WrapUnique(new SystemMonitor(CreateMetricEvaluatorsHelper())); |
| } |
| |
| // static |
| SystemMonitor* SystemMonitor::Get() { |
| return g_system_metrics_monitor; |
| } |
| |
| SystemMonitor::SystemObserver::~SystemObserver() { |
| if (g_system_metrics_monitor) { |
| // This is a no-op if the observer has already been removed. |
| g_system_metrics_monitor->RemoveObserver(this); |
| } |
| } |
| |
| void SystemMonitor::SystemObserver::OnFreePhysicalMemoryMbSample( |
| int free_phys_memory_mb) { |
| NOTREACHED(); |
| } |
| |
| void SystemMonitor::SystemObserver::OnDiskIdleTimePercent( |
| float disk_idle_time_percent) { |
| NOTREACHED(); |
| } |
| |
| void SystemMonitor::SystemObserver::OnSystemMetricsStruct( |
| const base::SystemMetrics& system_metrics) { |
| NOTREACHED(); |
| } |
| |
| void SystemMonitor::AddOrUpdateObserver( |
| SystemMonitor::SystemObserver* observer, |
| MetricRefreshFrequencies metrics_and_frequencies) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (!observers_.HasObserver(observer)) |
| observers_.AddObserver(observer); |
| observer_metrics_[observer] = std::move(metrics_and_frequencies); |
| UpdateObservedMetrics(); |
| } |
| |
| void SystemMonitor::RemoveObserver(SystemMonitor::SystemObserver* observer) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| observers_.RemoveObserver(observer); |
| if (observer_metrics_.erase(observer)) |
| UpdateObservedMetrics(); |
| } |
| |
| SystemMonitor::MetricVector SystemMonitor::GetMetricsToEvaluate() const { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| SystemMonitor::MetricVector metrics_to_evaluate; |
| |
| for (size_t i = 0; i < metrics_refresh_frequencies_.size(); ++i) { |
| if (metrics_refresh_frequencies_[i] == SamplingFrequency::kNoSampling) |
| continue; |
| metrics_to_evaluate.emplace_back( |
| metric_evaluators_metadata_[i].create_metric_evaluator_function( |
| metric_evaluators_helper_.get())); |
| } |
| return metrics_to_evaluate; |
| } |
| |
| // static |
| SystemMonitor::MetricVector SystemMonitor::EvaluateMetrics( |
| SystemMonitor::MetricVector metrics_to_evaluate) { |
| for (auto& metric : metrics_to_evaluate) |
| metric->Evaluate(); |
| |
| return metrics_to_evaluate; |
| } |
| |
| SystemMonitor::MetricMetadataArray SystemMonitor::CreateMetricMetadataArray() { |
| #define CREATE_METRIC_METADATA(metric_type, value_type, helper_function, \ |
| notify_function, metric_freq_field) \ |
| MetricMetadata( \ |
| [](MetricEvaluatorsHelper* helper) { \ |
| std::unique_ptr<MetricEvaluator> metric = \ |
| base::WrapUnique(new MetricEvaluatorImpl<value_type>( \ |
| MetricEvaluator::Type::metric_type, \ |
| base::BindOnce(&MetricEvaluatorsHelper::helper_function, \ |
| base::Unretained(helper)), \ |
| &SystemObserver::notify_function)); \ |
| return metric; \ |
| }, \ |
| [](const SystemObserver::MetricRefreshFrequencies& \ |
| metric_refresh_frequencies) { \ |
| return metric_refresh_frequencies.metric_freq_field; \ |
| }) |
| |
| return { |
| CREATE_METRIC_METADATA(kFreeMemoryMb, int, GetFreePhysicalMemoryMb, |
| OnFreePhysicalMemoryMbSample, |
| free_phys_memory_mb_frequency), |
| CREATE_METRIC_METADATA(kDiskIdleTimePercent, float, |
| GetDiskIdleTimePercent, OnDiskIdleTimePercent, |
| disk_idle_time_percent_frequency), |
| CREATE_METRIC_METADATA(kSystemMetricsStruct, base::SystemMetrics, |
| GetSystemMetricsStruct, OnSystemMetricsStruct, |
| system_metrics_sampling_frequency), |
| }; |
| |
| #undef CREATE_METRIC_METADATA |
| } // namespace performance_monitor |
| |
| void SystemMonitor::UpdateObservedMetrics() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| base::TimeDelta refresh_interval = base::TimeDelta::Max(); |
| // Iterates over the |observer_metrics_| list to find the highest refresh |
| // frequency for each metric. |
| for (size_t i = 0; i < metrics_refresh_frequencies_.size(); ++i) { |
| metrics_refresh_frequencies_[i] = SamplingFrequency::kNoSampling; |
| for (const auto& obs_iter : observer_metrics_) { |
| metrics_refresh_frequencies_[i] = std::max( |
| metrics_refresh_frequencies_[i], |
| metric_evaluators_metadata_[i].get_refresh_frequency_field_function( |
| obs_iter.second)); |
| } |
| if (metrics_refresh_frequencies_[i] != SamplingFrequency::kNoSampling) |
| refresh_interval = kDefaultRefreshInterval; |
| } |
| |
| if (refresh_interval.is_max()) { |
| refresh_timer_.Stop(); |
| } else if (!refresh_timer_.IsRunning() || |
| refresh_interval != refresh_timer_.GetCurrentDelay()) { |
| refresh_timer_.Start(FROM_HERE, refresh_interval, |
| base::BindRepeating(&SystemMonitor::RefreshCallback, |
| base::Unretained(this))); |
| } |
| } |
| |
| void SystemMonitor::RefreshCallback() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| base::PostTaskAndReplyWithResult( |
| blocking_task_runner_.get(), FROM_HERE, |
| base::BindOnce(&SystemMonitor::EvaluateMetrics, GetMetricsToEvaluate()), |
| base::BindOnce(&SystemMonitor::NotifyObservers, |
| weak_factory_.GetWeakPtr())); |
| |
| refresh_timer_.Start(FROM_HERE, refresh_timer_.GetCurrentDelay(), |
| base::BindRepeating(&SystemMonitor::RefreshCallback, |
| base::Unretained(this))); |
| } |
| |
| void SystemMonitor::NotifyObservers(SystemMonitor::MetricVector metrics) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // Iterate over the observers and notify them if a metric has been refreshed |
| // at the requested frequency. |
| for (const auto& metric : metrics) { |
| if (!metric->has_value()) |
| continue; |
| for (auto& observer : observers_) { |
| const auto& iter = observer_metrics_.find(&observer); |
| DCHECK(iter != observer_metrics_.end()); |
| if (metric_evaluators_metadata_[static_cast<size_t>(metric->type())] |
| .get_refresh_frequency_field_function(iter->second) != |
| SystemMonitor::SamplingFrequency::kNoSampling) { |
| metric->NotifyObserver(iter->first); |
| } |
| } |
| } |
| } |
| |
| SystemMonitor::MetricEvaluator::MetricEvaluator(Type type) : type_(type) {} |
| SystemMonitor::MetricEvaluator::~MetricEvaluator() = default; |
| |
| template <typename T> |
| SystemMonitor::MetricEvaluatorImpl<T>::MetricEvaluatorImpl( |
| Type type, |
| base::OnceCallback<base::Optional<T>()> evaluate_function, |
| void (SystemObserver::*notify_function)(ObserverArgType)) |
| : MetricEvaluator(type), |
| evaluate_function_(std::move(evaluate_function)), |
| notify_function_(notify_function) {} |
| |
| template <typename T> |
| SystemMonitor::MetricEvaluatorImpl<T>::~MetricEvaluatorImpl() = default; |
| |
| SystemMonitor::MetricMetadata::MetricMetadata( |
| std::unique_ptr<MetricEvaluator> (*create_function)( |
| MetricEvaluatorsHelper* helper), |
| SamplingFrequency (*get_refresh_field_function)( |
| const SystemMonitor::SystemObserver::MetricRefreshFrequencies&)) |
| : create_metric_evaluator_function(create_function), |
| get_refresh_frequency_field_function(get_refresh_field_function) {} |
| |
| template <typename T> |
| void SystemMonitor::MetricEvaluatorImpl<T>::NotifyObserver( |
| SystemObserver* observer) { |
| DCHECK(value()); |
| (observer->*notify_function_)(value().value()); |
| } |
| |
| template <typename T> |
| void SystemMonitor::MetricEvaluatorImpl<T>::Evaluate() { |
| DCHECK(evaluate_function_); |
| value_ = std::move(evaluate_function_).Run(); |
| } |
| |
| base::Optional<base::SystemMetrics> |
| MetricEvaluatorsHelper::GetSystemMetricsStruct() { |
| return base::SystemMetrics::Sample(); |
| } |
| |
| } // namespace performance_monitor |