blob: bcd53765f86039189500e8358df46425cfda8563 [file] [log] [blame]
// 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