| // Copyright 2015 The Chromium OS 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 "thermald/metrics_reporter.h" |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/logging.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "metrics/metrics_library.h" |
| |
| #include "thermald/key_value_publisher.h" |
| #include "thermald/temperature_monitor_interface.h" |
| |
| using std::make_pair; |
| using std::map; |
| using std::string; |
| using std::vector; |
| |
| namespace thermald { |
| |
| static const int kTemperatureUnknown = -273150; |
| static const int kTemperatureHistogramMinBucket = 0; |
| static const int kTemperatureHistogramMaxBucket = 150; |
| static const int kTemperatureHistogramNumberOfBuckets = 50; |
| static const int kThermalStateHistogramMinBucket = 1; |
| static const int kThermalStateHistogramMaxBucket = 10; |
| |
| MetricsReporter::MetricsReporter(const std::string &uma_metric_prefix, |
| KeyValuePublisher *output_publisher, |
| MetricsLibraryInterface *metrics_lib, |
| base::TimeDelta reporting_period) |
| : histogram_prefix_(uma_metric_prefix), |
| metrics_lib_(metrics_lib), |
| reporting_period_(reporting_period), |
| timer_(new base::RepeatingTimer()), |
| weak_ptr_factory_(this) { |
| subscription_outputs_ = output_publisher->Subscribe(base::Bind( |
| &MetricsReporter::OnOutputChanged, weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void MetricsReporter::AddTemperature( |
| const string &name, TemperatureMonitorInterface *temperature_monitor) { |
| TemperatureMetricsData tm; |
| tm.current_value = kTemperatureUnknown; |
| tm.histogram = histogram_prefix_ + ".Thermal.Temperature." + name; |
| temperature_metrics_data_.insert(make_pair(name, tm)); |
| |
| temperature_monitor_subscriptions_.push_back(temperature_monitor->Subscribe( |
| base::Bind(&MetricsReporter::OnTemperatureChanged, |
| weak_ptr_factory_.GetWeakPtr(), name))); |
| } |
| |
| void MetricsReporter::Start() { |
| if (timer_->IsRunning()) { |
| LOG(WARNING) << "Metrics reporter already running"; |
| return; |
| } |
| |
| timer_->Start(FROM_HERE, reporting_period_, |
| base::Bind(&MetricsReporter::ReportMetrics, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void MetricsReporter::Stop() { |
| if (!timer_->IsRunning()) { |
| LOG(WARNING) << "Metrics reporter is not running"; |
| return; |
| } |
| |
| timer_->Stop(); |
| } |
| |
| void MetricsReporter::ReportMetrics() { |
| for (const auto &it : temperature_metrics_data_) { |
| if (it.second.current_value == kTemperatureUnknown) { |
| continue; |
| } |
| |
| metrics_lib_->SendToUMA(it.second.histogram, |
| it.second.current_value / 1000, |
| kTemperatureHistogramMinBucket, |
| kTemperatureHistogramMaxBucket, |
| kTemperatureHistogramNumberOfBuckets); |
| } |
| |
| for (const auto &it : thermal_state_metrics_data_) { |
| metrics_lib_->SendToUMA(it.second.histogram, |
| it.second.current_state, |
| kThermalStateHistogramMinBucket, |
| kThermalStateHistogramMaxBucket, |
| kThermalStateHistogramMaxBucket - |
| kThermalStateHistogramMinBucket + 1); |
| } |
| } |
| |
| void MetricsReporter::OnTemperatureChanged(const string &name, int value) { |
| temperature_metrics_data_[name].current_value = value; |
| } |
| |
| void MetricsReporter::OnOutputChanged(const string &key, int value) { |
| // The only type of output we are handling are state changes in the thermal |
| // zones. Check if this is a state change, if so extract the name of the |
| // thermal zone from the key. The format of the key is: |
| // thermal_zone.<zone>.state |
| vector<string> key_parts = |
| base::SplitString(key, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); |
| if (key_parts.size() != 3 || key_parts[0] != "thermal_zone" || |
| key_parts[1].empty() || key_parts[2] != "state") { |
| return; |
| } |
| |
| const string zone(key_parts[1]); |
| auto it = thermal_state_metrics_data_.find(zone); |
| if (it != thermal_state_metrics_data_.end()) { |
| it->second.current_state = value; |
| } else { |
| ThermalStateMetricsData metrics_data; |
| metrics_data.histogram = histogram_prefix_ + ".Thermal.Zone." + zone + |
| ".States"; |
| metrics_data.current_state = value; |
| thermal_state_metrics_data_.insert(make_pair(zone, metrics_data)); |
| } |
| } |
| |
| } // namespace thermald |