blob: 45ae0a4390b3bace04d5ff8c2194996e739783ec [file] [log] [blame]
Bertrand SIMONNET52e5b992015-08-10 15:18:00 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Darin Petkov65b01462010-04-14 13:32:20 -070016
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080017#include "metrics_collector.h"
Darin Petkov65b01462010-04-14 13:32:20 -070018
Steve Funge86591e2014-12-01 13:38:21 -080019#include <sysexits.h>
Luigi Semenzato8accd332011-05-17 16:37:18 -070020#include <time.h>
Darin Petkov65b01462010-04-14 13:32:20 -070021
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -080022#include <memory>
23
Bertrand SIMONNET4b915ae2015-07-28 15:38:14 -070024#include <base/bind.h>
Luigi Semenzato859b3f02014-02-05 15:33:19 -080025#include <base/files/file_path.h>
Ben Chan51bf92a2014-09-05 08:21:06 -070026#include <base/files/file_util.h>
Luigi Semenzato859b3f02014-02-05 15:33:19 -080027#include <base/hash.h>
Darin Petkov65b01462010-04-14 13:32:20 -070028#include <base/logging.h>
Ben Chan2e6543d2014-02-05 23:26:25 -080029#include <base/strings/string_number_conversions.h>
30#include <base/strings/string_split.h>
31#include <base/strings/string_util.h>
32#include <base/strings/stringprintf.h>
Todd Poynorb77ae452016-01-04 14:11:25 -080033#include <brillo/binder_watcher.h>
Bertrand SIMONNETeb697ab2015-10-14 13:26:42 -070034#include <brillo/osrelease_reader.h>
Bertrand SIMONNETbae5dcc2015-08-04 14:12:10 -070035
36#include "constants.h"
Todd Poynorb77ae452016-01-04 14:11:25 -080037#include "metrics_collector_service_impl.h"
Darin Petkov65b01462010-04-14 13:32:20 -070038
Ben Chan2e6543d2014-02-05 23:26:25 -080039using base::FilePath;
40using base::StringPrintf;
Darin Petkovf27f0362010-06-04 13:14:19 -070041using base::Time;
42using base::TimeDelta;
43using base::TimeTicks;
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -080044using chromeos_metrics::PersistentInteger;
Luigi Semenzato8accd332011-05-17 16:37:18 -070045using std::map;
Darin Petkov38d5cb02010-06-24 12:10:26 -070046using std::string;
Luigi Semenzato8accd332011-05-17 16:37:18 -070047using std::vector;
48
Daniel Eratc83975a2014-04-04 08:53:44 -070049namespace {
Darin Petkovf27f0362010-06-04 13:14:19 -070050
Daniel Eratc83975a2014-04-04 08:53:44 -070051const int kSecondsPerMinute = 60;
52const int kMinutesPerHour = 60;
53const int kHoursPerDay = 24;
54const int kMinutesPerDay = kHoursPerDay * kMinutesPerHour;
55const int kSecondsPerDay = kSecondsPerMinute * kMinutesPerDay;
56const int kDaysPerWeek = 7;
57const int kSecondsPerWeek = kSecondsPerDay * kDaysPerWeek;
Darin Petkov41e06232010-05-03 16:45:37 -070058
Daniel Eratc83975a2014-04-04 08:53:44 -070059// Interval between calls to UpdateStats().
Steve Funge86591e2014-12-01 13:38:21 -080060const uint32_t kUpdateStatsIntervalMs = 300000;
Darin Petkov65b01462010-04-14 13:32:20 -070061
Steve Fung2bedc742016-02-02 16:11:43 -080062const char kKernelCrashDetectedFile[] =
63 "/data/misc/crash_reporter/run/kernel-crash-detected";
Daniel Eratc83975a2014-04-04 08:53:44 -070064const char kUncleanShutdownDetectedFile[] =
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -080065 "/var/run/unclean-shutdown-detected";
Ken Mixterccd84c02010-08-16 19:57:13 -070066
Bertrand SIMONNETebbe35c2015-09-08 10:13:35 -070067const int kMetricMeminfoInterval = 30; // seconds
68
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -070069const char kMeminfoFileName[] = "/proc/meminfo";
Bertrand SIMONNET7a964052015-09-29 11:07:24 -070070const char kVmStatFileName[] = "/proc/vmstat";
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -070071
Alex Vakulenko9fc597b2015-12-09 12:34:18 -080072const char kWeaveComponent[] = "metrics";
Alex Vakulenkoba95a942016-01-07 10:10:12 -080073const char kWeaveTrait[] = "_metrics";
Alex Vakulenko9fc597b2015-12-09 12:34:18 -080074
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -070075} // namespace
76
Luigi Semenzato96360192014-06-04 10:53:35 -070077// Zram sysfs entries.
78
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080079const char MetricsCollector::kComprDataSizeName[] = "compr_data_size";
80const char MetricsCollector::kOrigDataSizeName[] = "orig_data_size";
81const char MetricsCollector::kZeroPagesName[] = "zero_pages";
Luigi Semenzato96360192014-06-04 10:53:35 -070082
Luigi Semenzato8accd332011-05-17 16:37:18 -070083// Memory use stats collection intervals. We collect some memory use interval
84// at these intervals after boot, and we stop collecting after the last one,
85// with the assumption that in most cases the memory use won't change much
86// after that.
87static const int kMemuseIntervals[] = {
88 1 * kSecondsPerMinute, // 1 minute mark
89 4 * kSecondsPerMinute, // 5 minute mark
90 25 * kSecondsPerMinute, // 0.5 hour mark
91 120 * kSecondsPerMinute, // 2.5 hour mark
92 600 * kSecondsPerMinute, // 12.5 hour mark
93};
94
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080095MetricsCollector::MetricsCollector()
Steve Funge86591e2014-12-01 13:38:21 -080096 : memuse_final_time_(0),
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -080097 memuse_interval_index_(0) {}
Darin Petkovf1e85e42010-06-10 15:59:53 -070098
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080099MetricsCollector::~MetricsCollector() {
Ken Mixter4c5daa42010-08-26 18:35:06 -0700100}
101
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700102// static
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800103double MetricsCollector::GetActiveTime() {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700104 struct timespec ts;
105 int r = clock_gettime(CLOCK_MONOTONIC, &ts);
106 if (r < 0) {
107 PLOG(WARNING) << "clock_gettime(CLOCK_MONOTONIC) failed";
108 return 0;
109 } else {
Luigi Semenzato4a6c9422014-06-30 18:12:28 -0700110 return ts.tv_sec + static_cast<double>(ts.tv_nsec) / (1000 * 1000 * 1000);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700111 }
112}
113
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800114int MetricsCollector::Run() {
Ken Mixterccd84c02010-08-16 19:57:13 -0700115 if (CheckSystemCrash(kKernelCrashDetectedFile)) {
116 ProcessKernelCrash();
117 }
118
119 if (CheckSystemCrash(kUncleanShutdownDetectedFile)) {
120 ProcessUncleanShutdown();
121 }
122
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800123 // On OS version change, clear version stats (which are reported daily).
Ben Chanf05ab402014-08-07 00:54:59 -0700124 int32_t version = GetOsVersionHash();
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800125 if (version_cycle_->Get() != version) {
126 version_cycle_->Set(version);
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800127 kernel_crashes_version_count_->Set(0);
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700128 version_cumulative_active_use_->Set(0);
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700129 version_cumulative_cpu_use_->Set(0);
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800130 }
131
Todd Poynorb77ae452016-01-04 14:11:25 -0800132 // Start metricscollectorservice
133 android::sp<BnMetricsCollectorServiceImpl> metrics_collector_service =
134 new BnMetricsCollectorServiceImpl(this);
135 android::status_t status = android::defaultServiceManager()->addService(
136 metrics_collector_service->getInterfaceDescriptor(),
137 metrics_collector_service);
138 CHECK(status == android::OK)
139 << "failed to register service metricscollectorservice";
Todd Poynor694553d2015-12-03 11:05:45 -0800140
Todd Poynorb77ae452016-01-04 14:11:25 -0800141 // Watch Binder events in the main loop
142 brillo::BinderWatcher binder_watcher;
143 CHECK(binder_watcher.Init()) << "Binder FD watcher init failed";
Alex Vakulenkoeca14e32016-01-28 14:39:27 -0800144 return brillo::Daemon::Run();
Darin Petkov65b01462010-04-14 13:32:20 -0700145}
146
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800147uint32_t MetricsCollector::GetOsVersionHash() {
Bertrand SIMONNETeb697ab2015-10-14 13:26:42 -0700148 brillo::OsReleaseReader reader;
149 reader.Load();
150 string version;
151 if (!reader.GetString(metrics::kProductVersion, &version)) {
152 LOG(ERROR) << "failed to read the product version.";
153 version = metrics::kDefaultVersion;
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800154 }
Bertrand SIMONNETeb697ab2015-10-14 13:26:42 -0700155
156 uint32_t version_hash = base::Hash(version);
157 if (testing_) {
158 version_hash = 42; // return any plausible value for the hash
159 }
160 return version_hash;
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800161}
162
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800163void MetricsCollector::Init(bool testing, MetricsLibraryInterface* metrics_lib,
164 const string& diskstats_path,
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800165 const base::FilePath& private_metrics_directory,
166 const base::FilePath& shared_metrics_directory) {
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700167 CHECK(metrics_lib);
Darin Petkov65b01462010-04-14 13:32:20 -0700168 testing_ = testing;
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800169 shared_metrics_directory_ = shared_metrics_directory;
Darin Petkovfc91b422010-05-12 13:05:45 -0700170 metrics_lib_ = metrics_lib;
Darin Petkov38d5cb02010-06-24 12:10:26 -0700171
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800172 daily_active_use_.reset(new PersistentInteger("Platform.UseTime.PerDay",
173 private_metrics_directory));
174 version_cumulative_active_use_.reset(new PersistentInteger(
175 "Platform.CumulativeUseTime", private_metrics_directory));
176 version_cumulative_cpu_use_.reset(new PersistentInteger(
177 "Platform.CumulativeCpuTime", private_metrics_directory));
Darin Petkov38d5cb02010-06-24 12:10:26 -0700178
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800179 kernel_crash_interval_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800180 "Platform.KernelCrashInterval", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800181 unclean_shutdown_interval_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800182 "Platform.UncleanShutdownInterval", private_metrics_directory));
183 user_crash_interval_.reset(new PersistentInteger("Platform.UserCrashInterval",
184 private_metrics_directory));
Darin Petkov2ccef012010-05-05 16:06:37 -0700185
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800186 any_crashes_daily_count_.reset(new PersistentInteger(
187 "Platform.AnyCrashes.PerDay", private_metrics_directory));
188 any_crashes_weekly_count_.reset(new PersistentInteger(
189 "Platform.AnyCrashes.PerWeek", private_metrics_directory));
190 user_crashes_daily_count_.reset(new PersistentInteger(
191 "Platform.UserCrashes.PerDay", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800192 user_crashes_weekly_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800193 "Platform.UserCrashes.PerWeek", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800194 kernel_crashes_daily_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800195 "Platform.KernelCrashes.PerDay", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800196 kernel_crashes_weekly_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800197 "Platform.KernelCrashes.PerWeek", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800198 kernel_crashes_version_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800199 "Platform.KernelCrashesSinceUpdate", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800200 unclean_shutdowns_daily_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800201 "Platform.UncleanShutdown.PerDay", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800202 unclean_shutdowns_weekly_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800203 "Platform.UncleanShutdowns.PerWeek", private_metrics_directory));
Darin Petkov38d5cb02010-06-24 12:10:26 -0700204
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800205 daily_cycle_.reset(
206 new PersistentInteger("daily.cycle", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800207 weekly_cycle_.reset(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800208 new PersistentInteger("weekly.cycle", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800209 version_cycle_.reset(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800210 new PersistentInteger("version.cycle", private_metrics_directory));
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800211
Bertrand SIMONNET5658dc52015-09-18 13:38:10 -0700212 disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700213 averaged_stats_collector_.reset(
214 new AveragedStatisticsCollector(metrics_lib_, diskstats_path,
215 kVmStatFileName));
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -0800216 cpu_usage_collector_.reset(new CpuUsageCollector(metrics_lib_));
Steve Funge86591e2014-12-01 13:38:21 -0800217}
218
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800219int MetricsCollector::OnInit() {
Alex Vakulenkoeca14e32016-01-28 14:39:27 -0800220 int return_code = brillo::Daemon::OnInit();
Steve Funge86591e2014-12-01 13:38:21 -0800221 if (return_code != EX_OK)
222 return return_code;
223
Bertrand SIMONNETebbe35c2015-09-08 10:13:35 -0700224 StatsReporterInit();
225
226 // Start collecting meminfo stats.
227 ScheduleMeminfoCallback(kMetricMeminfoInterval);
228 memuse_final_time_ = GetActiveTime() + kMemuseIntervals[0];
229 ScheduleMemuseCallback(kMemuseIntervals[0]);
230
Steve Funge86591e2014-12-01 13:38:21 -0800231 if (testing_)
232 return EX_OK;
Darin Petkov65b01462010-04-14 13:32:20 -0700233
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800234 weave_service_subscription_ = weaved::Service::Connect(
235 brillo::MessageLoop::current(),
236 base::Bind(&MetricsCollector::OnWeaveServiceConnected,
237 weak_ptr_factory_.GetWeakPtr()));
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800238
239 latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
240 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
241 base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800242 weak_ptr_factory_.GetWeakPtr()),
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800243 base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
244
245 return EX_OK;
246}
247
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800248void MetricsCollector::OnWeaveServiceConnected(
249 const std::weak_ptr<weaved::Service>& service) {
250 service_ = service;
251 auto weave_service = service_.lock();
252 if (!weave_service)
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700253 return;
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700254
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800255 weave_service->AddComponent(kWeaveComponent, {kWeaveTrait}, nullptr);
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800256 weave_service->AddCommandHandler(
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800257 kWeaveComponent, kWeaveTrait, "enableAnalyticsReporting",
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800258 base::Bind(&MetricsCollector::OnEnableMetrics,
259 weak_ptr_factory_.GetWeakPtr()));
260 weave_service->AddCommandHandler(
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800261 kWeaveComponent, kWeaveTrait, "disableAnalyticsReporting",
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800262 base::Bind(&MetricsCollector::OnDisableMetrics,
263 weak_ptr_factory_.GetWeakPtr()));
264
265 UpdateWeaveState();
266}
267
268void MetricsCollector::OnEnableMetrics(
269 std::unique_ptr<weaved::Command> command) {
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800270 if (base::WriteFile(
271 shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
272 0) {
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700273 PLOG(ERROR) << "Could not create the consent file.";
Alex Vakulenko35f89632015-10-09 08:18:35 -0700274 command->Abort("metrics_error", "Could not create the consent file",
275 nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700276 return;
277 }
278
Alex Vakulenko82b02de2015-10-09 20:07:47 -0700279 UpdateWeaveState();
Alex Vakulenko35f89632015-10-09 08:18:35 -0700280 command->Complete({}, nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700281}
282
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800283void MetricsCollector::OnDisableMetrics(
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800284 std::unique_ptr<weaved::Command> command) {
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800285 if (!base::DeleteFile(
286 shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
Alex Vakulenko35f89632015-10-09 08:18:35 -0700287 PLOG(ERROR) << "Could not delete the consent file.";
288 command->Abort("metrics_error", "Could not delete the consent file",
289 nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700290 return;
291 }
292
Alex Vakulenko82b02de2015-10-09 20:07:47 -0700293 UpdateWeaveState();
Alex Vakulenko35f89632015-10-09 08:18:35 -0700294 command->Complete({}, nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700295}
296
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800297void MetricsCollector::UpdateWeaveState() {
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800298 auto weave_service = service_.lock();
299 if (!weave_service)
Alex Vakulenko82b02de2015-10-09 20:07:47 -0700300 return;
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700301
Alex Vakulenko9fc597b2015-12-09 12:34:18 -0800302 std::string enabled =
303 metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700304
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800305 if (!weave_service->SetStateProperty(kWeaveComponent, kWeaveTrait,
Alex Vakulenkoeca14e32016-01-28 14:39:27 -0800306 "analyticsReportingState",
307 *brillo::ToValue(enabled),
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800308 nullptr)) {
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700309 LOG(ERROR) << "failed to update weave's state";
310 }
311}
312
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800313void MetricsCollector::ProcessUserCrash() {
Daniel Eratc83975a2014-04-04 08:53:44 -0700314 // Counts the active time up to now.
315 UpdateStats(TimeTicks::Now(), Time::Now());
Darin Petkov1bb904e2010-06-16 15:58:06 -0700316
317 // Reports the active use time since the last crash and resets it.
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700318 SendAndResetCrashIntervalSample(user_crash_interval_);
Ken Mixterccd84c02010-08-16 19:57:13 -0700319
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800320 any_crashes_daily_count_->Add(1);
321 any_crashes_weekly_count_->Add(1);
322 user_crashes_daily_count_->Add(1);
323 user_crashes_weekly_count_->Add(1);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700324}
325
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800326void MetricsCollector::ProcessKernelCrash() {
Daniel Eratc83975a2014-04-04 08:53:44 -0700327 // Counts the active time up to now.
328 UpdateStats(TimeTicks::Now(), Time::Now());
Darin Petkov38d5cb02010-06-24 12:10:26 -0700329
330 // Reports the active use time since the last crash and resets it.
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700331 SendAndResetCrashIntervalSample(kernel_crash_interval_);
Ken Mixterccd84c02010-08-16 19:57:13 -0700332
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800333 any_crashes_daily_count_->Add(1);
334 any_crashes_weekly_count_->Add(1);
335 kernel_crashes_daily_count_->Add(1);
336 kernel_crashes_weekly_count_->Add(1);
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800337
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800338 kernel_crashes_version_count_->Add(1);
Darin Petkov38d5cb02010-06-24 12:10:26 -0700339}
340
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800341void MetricsCollector::ProcessUncleanShutdown() {
Daniel Eratc83975a2014-04-04 08:53:44 -0700342 // Counts the active time up to now.
343 UpdateStats(TimeTicks::Now(), Time::Now());
Ken Mixterccd84c02010-08-16 19:57:13 -0700344
345 // Reports the active use time since the last crash and resets it.
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700346 SendAndResetCrashIntervalSample(unclean_shutdown_interval_);
Ken Mixterccd84c02010-08-16 19:57:13 -0700347
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800348 unclean_shutdowns_daily_count_->Add(1);
349 unclean_shutdowns_weekly_count_->Add(1);
350 any_crashes_daily_count_->Add(1);
351 any_crashes_weekly_count_->Add(1);
Ken Mixterccd84c02010-08-16 19:57:13 -0700352}
353
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800354bool MetricsCollector::CheckSystemCrash(const string& crash_file) {
Darin Petkov38d5cb02010-06-24 12:10:26 -0700355 FilePath crash_detected(crash_file);
Ben Chan2e6543d2014-02-05 23:26:25 -0800356 if (!base::PathExists(crash_detected))
Ken Mixterccd84c02010-08-16 19:57:13 -0700357 return false;
Darin Petkov38d5cb02010-06-24 12:10:26 -0700358
359 // Deletes the crash-detected file so that the daemon doesn't report
360 // another kernel crash in case it's restarted.
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800361 base::DeleteFile(crash_detected, false); // not recursive
Ken Mixterccd84c02010-08-16 19:57:13 -0700362 return true;
Darin Petkov38d5cb02010-06-24 12:10:26 -0700363}
364
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800365void MetricsCollector::StatsReporterInit() {
Bertrand SIMONNET5658dc52015-09-18 13:38:10 -0700366 disk_usage_collector_->Schedule();
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700367
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -0800368 cpu_usage_collector_->Init();
369 cpu_usage_collector_->Schedule();
370
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700371 // Don't start a collection cycle during the first run to avoid delaying the
372 // boot.
373 averaged_stats_collector_->ScheduleWait();
Luigi Semenzatoc88e42d2011-02-17 10:21:16 -0800374}
375
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800376void MetricsCollector::ScheduleMeminfoCallback(int wait) {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700377 if (testing_) {
378 return;
379 }
Steve Funge86591e2014-12-01 13:38:21 -0800380 base::TimeDelta waitDelta = base::TimeDelta::FromSeconds(wait);
381 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800382 base::Bind(&MetricsCollector::MeminfoCallback,
383 weak_ptr_factory_.GetWeakPtr(), waitDelta),
Steve Funge86591e2014-12-01 13:38:21 -0800384 waitDelta);
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700385}
386
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800387void MetricsCollector::MeminfoCallback(base::TimeDelta wait) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700388 string meminfo_raw;
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700389 const FilePath meminfo_path(kMeminfoFileName);
Ben Chan2e6543d2014-02-05 23:26:25 -0800390 if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700391 LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
Steve Funge86591e2014-12-01 13:38:21 -0800392 return;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700393 }
Luigi Semenzato96360192014-06-04 10:53:35 -0700394 // Make both calls even if the first one fails.
Bertrand SIMONNETebbe35c2015-09-08 10:13:35 -0700395 if (ProcessMeminfo(meminfo_raw)) {
Steve Funge86591e2014-12-01 13:38:21 -0800396 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800397 base::Bind(&MetricsCollector::MeminfoCallback,
398 weak_ptr_factory_.GetWeakPtr(), wait),
Steve Funge86591e2014-12-01 13:38:21 -0800399 wait);
400 }
Luigi Semenzato96360192014-06-04 10:53:35 -0700401}
402
403// static
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800404bool MetricsCollector::ReadFileToUint64(const base::FilePath& path,
405 uint64_t* value) {
Luigi Semenzato96360192014-06-04 10:53:35 -0700406 std::string content;
407 if (!base::ReadFileToString(path, &content)) {
408 PLOG(WARNING) << "cannot read " << path.MaybeAsASCII();
409 return false;
410 }
Luigi Semenzato4a6c9422014-06-30 18:12:28 -0700411 // Remove final newline.
412 base::TrimWhitespaceASCII(content, base::TRIM_TRAILING, &content);
Luigi Semenzato96360192014-06-04 10:53:35 -0700413 if (!base::StringToUint64(content, value)) {
414 LOG(WARNING) << "invalid integer: " << content;
415 return false;
416 }
417 return true;
418}
419
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800420bool MetricsCollector::ReportZram(const base::FilePath& zram_dir) {
Luigi Semenzato96360192014-06-04 10:53:35 -0700421 // Data sizes are in bytes. |zero_pages| is in number of pages.
Ben Chanf05ab402014-08-07 00:54:59 -0700422 uint64_t compr_data_size, orig_data_size, zero_pages;
Luigi Semenzato96360192014-06-04 10:53:35 -0700423 const size_t page_size = 4096;
424
425 if (!ReadFileToUint64(zram_dir.Append(kComprDataSizeName),
426 &compr_data_size) ||
427 !ReadFileToUint64(zram_dir.Append(kOrigDataSizeName), &orig_data_size) ||
428 !ReadFileToUint64(zram_dir.Append(kZeroPagesName), &zero_pages)) {
429 return false;
430 }
431
432 // |orig_data_size| does not include zero-filled pages.
433 orig_data_size += zero_pages * page_size;
434
435 const int compr_data_size_mb = compr_data_size >> 20;
436 const int savings_mb = (orig_data_size - compr_data_size) >> 20;
437 const int zero_ratio_percent = zero_pages * page_size * 100 / orig_data_size;
438
439 // Report compressed size in megabytes. 100 MB or less has little impact.
440 SendSample("Platform.ZramCompressedSize", compr_data_size_mb, 100, 4000, 50);
441 SendSample("Platform.ZramSavings", savings_mb, 100, 4000, 50);
442 // The compression ratio is multiplied by 100 for better resolution. The
443 // ratios of interest are between 1 and 6 (100% and 600% as reported). We
444 // don't want samples when very little memory is being compressed.
445 if (compr_data_size_mb >= 1) {
446 SendSample("Platform.ZramCompressionRatioPercent",
447 orig_data_size * 100 / compr_data_size, 100, 600, 50);
448 }
449 // The values of interest for zero_pages are between 1MB and 1GB. The units
450 // are number of pages.
451 SendSample("Platform.ZramZeroPages", zero_pages, 256, 256 * 1024, 50);
452 SendSample("Platform.ZramZeroRatioPercent", zero_ratio_percent, 1, 50, 50);
453
454 return true;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700455}
456
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800457bool MetricsCollector::ProcessMeminfo(const string& meminfo_raw) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700458 static const MeminfoRecord fields_array[] = {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700459 { "MemTotal", "MemTotal" }, // SPECIAL CASE: total system memory
460 { "MemFree", "MemFree" },
461 { "Buffers", "Buffers" },
462 { "Cached", "Cached" },
463 // { "SwapCached", "SwapCached" },
464 { "Active", "Active" },
465 { "Inactive", "Inactive" },
466 { "ActiveAnon", "Active(anon)" },
467 { "InactiveAnon", "Inactive(anon)" },
468 { "ActiveFile" , "Active(file)" },
469 { "InactiveFile", "Inactive(file)" },
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800470 { "Unevictable", "Unevictable", kMeminfoOp_HistLog },
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700471 // { "Mlocked", "Mlocked" },
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800472 { "SwapTotal", "SwapTotal", kMeminfoOp_SwapTotal },
473 { "SwapFree", "SwapFree", kMeminfoOp_SwapFree },
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700474 // { "Dirty", "Dirty" },
475 // { "Writeback", "Writeback" },
476 { "AnonPages", "AnonPages" },
477 { "Mapped", "Mapped" },
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800478 { "Shmem", "Shmem", kMeminfoOp_HistLog },
479 { "Slab", "Slab", kMeminfoOp_HistLog },
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700480 // { "SReclaimable", "SReclaimable" },
481 // { "SUnreclaim", "SUnreclaim" },
482 };
Luigi Semenzato8accd332011-05-17 16:37:18 -0700483 vector<MeminfoRecord> fields(fields_array,
484 fields_array + arraysize(fields_array));
485 if (!FillMeminfo(meminfo_raw, &fields)) {
486 return false;
487 }
488 int total_memory = fields[0].value;
489 if (total_memory == 0) {
490 // this "cannot happen"
491 LOG(WARNING) << "borked meminfo parser";
492 return false;
493 }
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800494 int swap_total = 0;
495 int swap_free = 0;
Luigi Semenzato8accd332011-05-17 16:37:18 -0700496 // Send all fields retrieved, except total memory.
497 for (unsigned int i = 1; i < fields.size(); i++) {
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800498 string metrics_name = base::StringPrintf("Platform.Meminfo%s",
499 fields[i].name);
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800500 int percent;
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800501 switch (fields[i].op) {
502 case kMeminfoOp_HistPercent:
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800503 // report value as percent of total memory
504 percent = fields[i].value * 100 / total_memory;
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800505 SendLinearSample(metrics_name, percent, 100, 101);
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800506 break;
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800507 case kMeminfoOp_HistLog:
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800508 // report value in kbytes, log scale, 4Gb max
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800509 SendSample(metrics_name, fields[i].value, 1, 4 * 1000 * 1000, 100);
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800510 break;
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800511 case kMeminfoOp_SwapTotal:
512 swap_total = fields[i].value;
513 case kMeminfoOp_SwapFree:
514 swap_free = fields[i].value;
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800515 break;
Luigi Semenzato8accd332011-05-17 16:37:18 -0700516 }
517 }
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800518 if (swap_total > 0) {
519 int swap_used = swap_total - swap_free;
520 int swap_used_percent = swap_used * 100 / swap_total;
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800521 SendSample("Platform.MeminfoSwapUsed", swap_used, 1, 8 * 1000 * 1000, 100);
Bertrand SIMONNET008fb7e2015-09-21 16:48:01 -0700522 SendLinearSample("Platform.MeminfoSwapUsed.Percent", swap_used_percent,
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800523 100, 101);
524 }
Luigi Semenzato8accd332011-05-17 16:37:18 -0700525 return true;
526}
527
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800528bool MetricsCollector::FillMeminfo(const string& meminfo_raw,
529 vector<MeminfoRecord>* fields) {
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800530 vector<std::string> lines =
531 base::SplitString(meminfo_raw, "\n", base::KEEP_WHITESPACE,
532 base::SPLIT_WANT_NONEMPTY);
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700533
534 // Scan meminfo output and collect field values. Each field name has to
535 // match a meminfo entry (case insensitive) after removing non-alpha
536 // characters from the entry.
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800537 size_t ifield = 0;
538 for (size_t iline = 0;
539 iline < lines.size() && ifield < fields->size();
Luigi Semenzato8accd332011-05-17 16:37:18 -0700540 iline++) {
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800541 vector<string> tokens =
542 base::SplitString(lines[iline], ": ", base::KEEP_WHITESPACE,
543 base::SPLIT_WANT_NONEMPTY);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700544 if (strcmp((*fields)[ifield].match, tokens[0].c_str()) == 0) {
545 // Name matches. Parse value and save.
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700546 if (!base::StringToInt(tokens[1], &(*fields)[ifield].value)) {
547 LOG(WARNING) << "Cound not convert " << tokens[1] << " to int";
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700548 return false;
549 }
Luigi Semenzato8accd332011-05-17 16:37:18 -0700550 ifield++;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700551 }
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700552 }
Luigi Semenzato8accd332011-05-17 16:37:18 -0700553 if (ifield < fields->size()) {
554 // End of input reached while scanning.
555 LOG(WARNING) << "cannot find field " << (*fields)[ifield].match
556 << " and following";
557 return false;
558 }
559 return true;
560}
561
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800562void MetricsCollector::ScheduleMemuseCallback(double interval) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700563 if (testing_) {
564 return;
565 }
Steve Funge86591e2014-12-01 13:38:21 -0800566 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800567 base::Bind(&MetricsCollector::MemuseCallback,
568 weak_ptr_factory_.GetWeakPtr()),
Steve Funge86591e2014-12-01 13:38:21 -0800569 base::TimeDelta::FromSeconds(interval));
Luigi Semenzato8accd332011-05-17 16:37:18 -0700570}
571
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800572void MetricsCollector::MemuseCallback() {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700573 // Since we only care about active time (i.e. uptime minus sleep time) but
574 // the callbacks are driven by real time (uptime), we check if we should
575 // reschedule this callback due to intervening sleep periods.
576 double now = GetActiveTime();
Luigi Semenzato0d9a9c92013-12-05 15:55:12 -0800577 // Avoid intervals of less than one second.
578 double remaining_time = ceil(memuse_final_time_ - now);
579 if (remaining_time > 0) {
580 ScheduleMemuseCallback(remaining_time);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700581 } else {
Luigi Semenzato0d9a9c92013-12-05 15:55:12 -0800582 // Report stats and advance the measurement interval unless there are
583 // errors or we've completed the last interval.
Luigi Semenzato8accd332011-05-17 16:37:18 -0700584 if (MemuseCallbackWork() &&
Luigi Semenzato0d9a9c92013-12-05 15:55:12 -0800585 memuse_interval_index_ < arraysize(kMemuseIntervals)) {
586 double interval = kMemuseIntervals[memuse_interval_index_++];
587 memuse_final_time_ = now + interval;
588 ScheduleMemuseCallback(interval);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700589 }
590 }
591}
592
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800593bool MetricsCollector::MemuseCallbackWork() {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700594 string meminfo_raw;
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700595 const FilePath meminfo_path(kMeminfoFileName);
Ben Chan2e6543d2014-02-05 23:26:25 -0800596 if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700597 LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
598 return false;
599 }
600 return ProcessMemuse(meminfo_raw);
601}
602
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800603bool MetricsCollector::ProcessMemuse(const string& meminfo_raw) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700604 static const MeminfoRecord fields_array[] = {
605 { "MemTotal", "MemTotal" }, // SPECIAL CASE: total system memory
606 { "ActiveAnon", "Active(anon)" },
607 { "InactiveAnon", "Inactive(anon)" },
608 };
609 vector<MeminfoRecord> fields(fields_array,
610 fields_array + arraysize(fields_array));
611 if (!FillMeminfo(meminfo_raw, &fields)) {
612 return false;
613 }
614 int total = fields[0].value;
615 int active_anon = fields[1].value;
616 int inactive_anon = fields[2].value;
617 if (total == 0) {
618 // this "cannot happen"
619 LOG(WARNING) << "borked meminfo parser";
620 return false;
621 }
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800622 string metrics_name = base::StringPrintf("Platform.MemuseAnon%d",
623 memuse_interval_index_);
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800624 SendLinearSample(metrics_name, (active_anon + inactive_anon) * 100 / total,
Luigi Semenzato8accd332011-05-17 16:37:18 -0700625 100, 101);
626 return true;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700627}
628
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800629void MetricsCollector::SendSample(const string& name, int sample,
630 int min, int max, int nbuckets) {
Darin Petkovfc91b422010-05-12 13:05:45 -0700631 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
Darin Petkov65b01462010-04-14 13:32:20 -0700632}
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700633
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800634void MetricsCollector::SendKernelCrashesCumulativeCountStats() {
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800635 // Report the number of crashes for this OS version, but don't clear the
636 // counter. It is cleared elsewhere on version change.
Ben Chanf05ab402014-08-07 00:54:59 -0700637 int64_t crashes_count = kernel_crashes_version_count_->Get();
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800638 SendSample(kernel_crashes_version_count_->Name(),
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700639 crashes_count,
640 1, // value of first bucket
641 500, // value of last bucket
642 100); // number of buckets
643
644
Ben Chanf05ab402014-08-07 00:54:59 -0700645 int64_t cpu_use_ms = version_cumulative_cpu_use_->Get();
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700646 SendSample(version_cumulative_cpu_use_->Name(),
647 cpu_use_ms / 1000, // stat is in seconds
648 1, // device may be used very little...
649 8 * 1000 * 1000, // ... or a lot (a little over 90 days)
650 100);
651
652 // On the first run after an autoupdate, cpu_use_ms and active_use_seconds
653 // can be zero. Avoid division by zero.
654 if (cpu_use_ms > 0) {
655 // Send the crash frequency since update in number of crashes per CPU year.
656 SendSample("Logging.KernelCrashesPerCpuYear",
657 crashes_count * kSecondsPerDay * 365 * 1000 / cpu_use_ms,
658 1,
659 1000 * 1000, // about one crash every 30s of CPU time
660 100);
661 }
662
Ben Chanf05ab402014-08-07 00:54:59 -0700663 int64_t active_use_seconds = version_cumulative_active_use_->Get();
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700664 if (active_use_seconds > 0) {
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700665 SendSample(version_cumulative_active_use_->Name(),
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700666 active_use_seconds,
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700667 1, // device may be used very little...
668 8 * 1000 * 1000, // ... or a lot (about 90 days)
669 100);
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700670 // Same as above, but per year of active time.
671 SendSample("Logging.KernelCrashesPerActiveYear",
672 crashes_count * kSecondsPerDay * 365 / active_use_seconds,
673 1,
674 1000 * 1000, // about one crash every 30s of active time
675 100);
676 }
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800677}
678
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800679void MetricsCollector::SendAndResetDailyUseSample(
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800680 const unique_ptr<PersistentInteger>& use) {
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700681 SendSample(use->Name(),
682 use->GetAndClear(),
683 1, // value of first bucket
684 kSecondsPerDay, // value of last bucket
685 50); // number of buckets
686}
687
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800688void MetricsCollector::SendAndResetCrashIntervalSample(
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800689 const unique_ptr<PersistentInteger>& interval) {
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800690 SendSample(interval->Name(),
691 interval->GetAndClear(),
692 1, // value of first bucket
693 4 * kSecondsPerWeek, // value of last bucket
694 50); // number of buckets
695}
696
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800697void MetricsCollector::SendAndResetCrashFrequencySample(
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800698 const unique_ptr<PersistentInteger>& frequency) {
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800699 SendSample(frequency->Name(),
700 frequency->GetAndClear(),
701 1, // value of first bucket
702 100, // value of last bucket
703 50); // number of buckets
704}
705
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800706void MetricsCollector::SendLinearSample(const string& name, int sample,
707 int max, int nbuckets) {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700708 // TODO(semenzato): add a proper linear histogram to the Chrome external
709 // metrics API.
710 LOG_IF(FATAL, nbuckets != max + 1) << "unsupported histogram scale";
711 metrics_lib_->SendEnumToUMA(name, sample, max);
712}
Daniel Eratc83975a2014-04-04 08:53:44 -0700713
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800714void MetricsCollector::UpdateStats(TimeTicks now_ticks,
715 Time now_wall_time) {
Daniel Eratc83975a2014-04-04 08:53:44 -0700716 const int elapsed_seconds = (now_ticks - last_update_stats_time_).InSeconds();
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700717 daily_active_use_->Add(elapsed_seconds);
718 version_cumulative_active_use_->Add(elapsed_seconds);
Daniel Eratc83975a2014-04-04 08:53:44 -0700719 user_crash_interval_->Add(elapsed_seconds);
720 kernel_crash_interval_->Add(elapsed_seconds);
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -0800721 TimeDelta cpu_use = cpu_usage_collector_->GetCumulativeCpuUse();
722 version_cumulative_cpu_use_->Add(
723 (cpu_use - latest_cpu_use_microseconds_).InMilliseconds());
724 latest_cpu_use_microseconds_ = cpu_use;
Daniel Eratc83975a2014-04-04 08:53:44 -0700725 last_update_stats_time_ = now_ticks;
726
727 const TimeDelta since_epoch = now_wall_time - Time::UnixEpoch();
728 const int day = since_epoch.InDays();
729 const int week = day / 7;
730
731 if (daily_cycle_->Get() != day) {
732 daily_cycle_->Set(day);
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700733 SendAndResetDailyUseSample(daily_active_use_);
734 SendAndResetCrashFrequencySample(any_crashes_daily_count_);
735 SendAndResetCrashFrequencySample(user_crashes_daily_count_);
736 SendAndResetCrashFrequencySample(kernel_crashes_daily_count_);
737 SendAndResetCrashFrequencySample(unclean_shutdowns_daily_count_);
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700738 SendKernelCrashesCumulativeCountStats();
Daniel Eratc83975a2014-04-04 08:53:44 -0700739 }
740
741 if (weekly_cycle_->Get() != week) {
742 weekly_cycle_->Set(week);
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700743 SendAndResetCrashFrequencySample(any_crashes_weekly_count_);
744 SendAndResetCrashFrequencySample(user_crashes_weekly_count_);
745 SendAndResetCrashFrequencySample(kernel_crashes_weekly_count_);
746 SendAndResetCrashFrequencySample(unclean_shutdowns_weekly_count_);
Daniel Eratc83975a2014-04-04 08:53:44 -0700747 }
748}
749
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800750void MetricsCollector::HandleUpdateStatsTimeout() {
Steve Funge86591e2014-12-01 13:38:21 -0800751 UpdateStats(TimeTicks::Now(), Time::Now());
752 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800753 base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800754 weak_ptr_factory_.GetWeakPtr()),
Steve Funge86591e2014-12-01 13:38:21 -0800755 base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
Daniel Eratc83975a2014-04-04 08:53:44 -0700756}