blob: c3f42dcbf21d9c28c15fb404e94608612b473545 [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
Luigi Semenzatoc5a92342014-02-14 15:05:51 -080062const char kKernelCrashDetectedFile[] = "/var/run/kernel-crash-detected";
Daniel Eratc83975a2014-04-04 08:53:44 -070063const char kUncleanShutdownDetectedFile[] =
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -080064 "/var/run/unclean-shutdown-detected";
Ken Mixterccd84c02010-08-16 19:57:13 -070065
Bertrand SIMONNETebbe35c2015-09-08 10:13:35 -070066const int kMetricMeminfoInterval = 30; // seconds
67
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -070068const char kMeminfoFileName[] = "/proc/meminfo";
Bertrand SIMONNET7a964052015-09-29 11:07:24 -070069const char kVmStatFileName[] = "/proc/vmstat";
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -070070
Alex Vakulenko9fc597b2015-12-09 12:34:18 -080071const char kWeaveComponent[] = "metrics";
Alex Vakulenkoba95a942016-01-07 10:10:12 -080072const char kWeaveTrait[] = "_metrics";
Alex Vakulenko9fc597b2015-12-09 12:34:18 -080073
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -070074} // namespace
75
Luigi Semenzato96360192014-06-04 10:53:35 -070076// Zram sysfs entries.
77
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080078const char MetricsCollector::kComprDataSizeName[] = "compr_data_size";
79const char MetricsCollector::kOrigDataSizeName[] = "orig_data_size";
80const char MetricsCollector::kZeroPagesName[] = "zero_pages";
Luigi Semenzato96360192014-06-04 10:53:35 -070081
Luigi Semenzato8accd332011-05-17 16:37:18 -070082// Memory use stats collection intervals. We collect some memory use interval
83// at these intervals after boot, and we stop collecting after the last one,
84// with the assumption that in most cases the memory use won't change much
85// after that.
86static const int kMemuseIntervals[] = {
87 1 * kSecondsPerMinute, // 1 minute mark
88 4 * kSecondsPerMinute, // 5 minute mark
89 25 * kSecondsPerMinute, // 0.5 hour mark
90 120 * kSecondsPerMinute, // 2.5 hour mark
91 600 * kSecondsPerMinute, // 12.5 hour mark
92};
93
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080094MetricsCollector::MetricsCollector()
Steve Funge86591e2014-12-01 13:38:21 -080095 : memuse_final_time_(0),
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -080096 memuse_interval_index_(0) {}
Darin Petkovf1e85e42010-06-10 15:59:53 -070097
Bertrand SIMONNET608e4282015-11-12 17:52:17 -080098MetricsCollector::~MetricsCollector() {
Ken Mixter4c5daa42010-08-26 18:35:06 -070099}
100
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700101// static
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800102double MetricsCollector::GetActiveTime() {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700103 struct timespec ts;
104 int r = clock_gettime(CLOCK_MONOTONIC, &ts);
105 if (r < 0) {
106 PLOG(WARNING) << "clock_gettime(CLOCK_MONOTONIC) failed";
107 return 0;
108 } else {
Luigi Semenzato4a6c9422014-06-30 18:12:28 -0700109 return ts.tv_sec + static_cast<double>(ts.tv_nsec) / (1000 * 1000 * 1000);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700110 }
111}
112
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800113int MetricsCollector::Run() {
Ken Mixterccd84c02010-08-16 19:57:13 -0700114 if (CheckSystemCrash(kKernelCrashDetectedFile)) {
115 ProcessKernelCrash();
116 }
117
118 if (CheckSystemCrash(kUncleanShutdownDetectedFile)) {
119 ProcessUncleanShutdown();
120 }
121
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800122 // On OS version change, clear version stats (which are reported daily).
Ben Chanf05ab402014-08-07 00:54:59 -0700123 int32_t version = GetOsVersionHash();
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800124 if (version_cycle_->Get() != version) {
125 version_cycle_->Set(version);
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800126 kernel_crashes_version_count_->Set(0);
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700127 version_cumulative_active_use_->Set(0);
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700128 version_cumulative_cpu_use_->Set(0);
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800129 }
130
Todd Poynorb77ae452016-01-04 14:11:25 -0800131 // Start metricscollectorservice
132 android::sp<BnMetricsCollectorServiceImpl> metrics_collector_service =
133 new BnMetricsCollectorServiceImpl(this);
134 android::status_t status = android::defaultServiceManager()->addService(
135 metrics_collector_service->getInterfaceDescriptor(),
136 metrics_collector_service);
137 CHECK(status == android::OK)
138 << "failed to register service metricscollectorservice";
Todd Poynor694553d2015-12-03 11:05:45 -0800139
Todd Poynorb77ae452016-01-04 14:11:25 -0800140 // Watch Binder events in the main loop
141 brillo::BinderWatcher binder_watcher;
142 CHECK(binder_watcher.Init()) << "Binder FD watcher init failed";
Alex Vakulenkoeca14e32016-01-28 14:39:27 -0800143 return brillo::Daemon::Run();
Darin Petkov65b01462010-04-14 13:32:20 -0700144}
145
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800146uint32_t MetricsCollector::GetOsVersionHash() {
Bertrand SIMONNETeb697ab2015-10-14 13:26:42 -0700147 brillo::OsReleaseReader reader;
148 reader.Load();
149 string version;
150 if (!reader.GetString(metrics::kProductVersion, &version)) {
151 LOG(ERROR) << "failed to read the product version.";
152 version = metrics::kDefaultVersion;
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800153 }
Bertrand SIMONNETeb697ab2015-10-14 13:26:42 -0700154
155 uint32_t version_hash = base::Hash(version);
156 if (testing_) {
157 version_hash = 42; // return any plausible value for the hash
158 }
159 return version_hash;
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800160}
161
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800162void MetricsCollector::Init(bool testing, MetricsLibraryInterface* metrics_lib,
163 const string& diskstats_path,
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800164 const base::FilePath& private_metrics_directory,
165 const base::FilePath& shared_metrics_directory) {
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700166 CHECK(metrics_lib);
Darin Petkov65b01462010-04-14 13:32:20 -0700167 testing_ = testing;
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800168 shared_metrics_directory_ = shared_metrics_directory;
Darin Petkovfc91b422010-05-12 13:05:45 -0700169 metrics_lib_ = metrics_lib;
Darin Petkov38d5cb02010-06-24 12:10:26 -0700170
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800171 daily_active_use_.reset(new PersistentInteger("Platform.UseTime.PerDay",
172 private_metrics_directory));
173 version_cumulative_active_use_.reset(new PersistentInteger(
174 "Platform.CumulativeUseTime", private_metrics_directory));
175 version_cumulative_cpu_use_.reset(new PersistentInteger(
176 "Platform.CumulativeCpuTime", private_metrics_directory));
Darin Petkov38d5cb02010-06-24 12:10:26 -0700177
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800178 kernel_crash_interval_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800179 "Platform.KernelCrashInterval", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800180 unclean_shutdown_interval_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800181 "Platform.UncleanShutdownInterval", private_metrics_directory));
182 user_crash_interval_.reset(new PersistentInteger("Platform.UserCrashInterval",
183 private_metrics_directory));
Darin Petkov2ccef012010-05-05 16:06:37 -0700184
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800185 any_crashes_daily_count_.reset(new PersistentInteger(
186 "Platform.AnyCrashes.PerDay", private_metrics_directory));
187 any_crashes_weekly_count_.reset(new PersistentInteger(
188 "Platform.AnyCrashes.PerWeek", private_metrics_directory));
189 user_crashes_daily_count_.reset(new PersistentInteger(
190 "Platform.UserCrashes.PerDay", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800191 user_crashes_weekly_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800192 "Platform.UserCrashes.PerWeek", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800193 kernel_crashes_daily_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800194 "Platform.KernelCrashes.PerDay", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800195 kernel_crashes_weekly_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800196 "Platform.KernelCrashes.PerWeek", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800197 kernel_crashes_version_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800198 "Platform.KernelCrashesSinceUpdate", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800199 unclean_shutdowns_daily_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800200 "Platform.UncleanShutdown.PerDay", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800201 unclean_shutdowns_weekly_count_.reset(new PersistentInteger(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800202 "Platform.UncleanShutdowns.PerWeek", private_metrics_directory));
Darin Petkov38d5cb02010-06-24 12:10:26 -0700203
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800204 daily_cycle_.reset(
205 new PersistentInteger("daily.cycle", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800206 weekly_cycle_.reset(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800207 new PersistentInteger("weekly.cycle", private_metrics_directory));
Bertrand SIMONNETa7bc1c12015-11-25 13:29:48 -0800208 version_cycle_.reset(
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800209 new PersistentInteger("version.cycle", private_metrics_directory));
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800210
Bertrand SIMONNET5658dc52015-09-18 13:38:10 -0700211 disk_usage_collector_.reset(new DiskUsageCollector(metrics_lib_));
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700212 averaged_stats_collector_.reset(
213 new AveragedStatisticsCollector(metrics_lib_, diskstats_path,
214 kVmStatFileName));
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -0800215 cpu_usage_collector_.reset(new CpuUsageCollector(metrics_lib_));
Steve Funge86591e2014-12-01 13:38:21 -0800216}
217
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800218int MetricsCollector::OnInit() {
Alex Vakulenkoeca14e32016-01-28 14:39:27 -0800219 int return_code = brillo::Daemon::OnInit();
Steve Funge86591e2014-12-01 13:38:21 -0800220 if (return_code != EX_OK)
221 return return_code;
222
Bertrand SIMONNETebbe35c2015-09-08 10:13:35 -0700223 StatsReporterInit();
224
225 // Start collecting meminfo stats.
226 ScheduleMeminfoCallback(kMetricMeminfoInterval);
227 memuse_final_time_ = GetActiveTime() + kMemuseIntervals[0];
228 ScheduleMemuseCallback(kMemuseIntervals[0]);
229
Steve Funge86591e2014-12-01 13:38:21 -0800230 if (testing_)
231 return EX_OK;
Darin Petkov65b01462010-04-14 13:32:20 -0700232
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800233 weave_service_subscription_ = weaved::Service::Connect(
234 brillo::MessageLoop::current(),
235 base::Bind(&MetricsCollector::OnWeaveServiceConnected,
236 weak_ptr_factory_.GetWeakPtr()));
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800237
238 latest_cpu_use_microseconds_ = cpu_usage_collector_->GetCumulativeCpuUse();
239 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
240 base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800241 weak_ptr_factory_.GetWeakPtr()),
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800242 base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
243
244 return EX_OK;
245}
246
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800247void MetricsCollector::OnWeaveServiceConnected(
248 const std::weak_ptr<weaved::Service>& service) {
249 service_ = service;
250 auto weave_service = service_.lock();
251 if (!weave_service)
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700252 return;
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700253
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800254 weave_service->AddComponent(kWeaveComponent, {kWeaveTrait}, nullptr);
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800255 weave_service->AddCommandHandler(
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800256 kWeaveComponent, kWeaveTrait, "enableAnalyticsReporting",
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800257 base::Bind(&MetricsCollector::OnEnableMetrics,
258 weak_ptr_factory_.GetWeakPtr()));
259 weave_service->AddCommandHandler(
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800260 kWeaveComponent, kWeaveTrait, "disableAnalyticsReporting",
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800261 base::Bind(&MetricsCollector::OnDisableMetrics,
262 weak_ptr_factory_.GetWeakPtr()));
263
264 UpdateWeaveState();
265}
266
267void MetricsCollector::OnEnableMetrics(
268 std::unique_ptr<weaved::Command> command) {
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800269 if (base::WriteFile(
270 shared_metrics_directory_.Append(metrics::kConsentFileName), "", 0) !=
271 0) {
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700272 PLOG(ERROR) << "Could not create the consent file.";
Alex Vakulenko35f89632015-10-09 08:18:35 -0700273 command->Abort("metrics_error", "Could not create the consent file",
274 nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700275 return;
276 }
277
Alex Vakulenko82b02de2015-10-09 20:07:47 -0700278 UpdateWeaveState();
Alex Vakulenko35f89632015-10-09 08:18:35 -0700279 command->Complete({}, nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700280}
281
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800282void MetricsCollector::OnDisableMetrics(
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800283 std::unique_ptr<weaved::Command> command) {
Bertrand SIMONNET9d3a4ae2015-11-25 13:49:12 -0800284 if (!base::DeleteFile(
285 shared_metrics_directory_.Append(metrics::kConsentFileName), false)) {
Alex Vakulenko35f89632015-10-09 08:18:35 -0700286 PLOG(ERROR) << "Could not delete the consent file.";
287 command->Abort("metrics_error", "Could not delete the consent file",
288 nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700289 return;
290 }
291
Alex Vakulenko82b02de2015-10-09 20:07:47 -0700292 UpdateWeaveState();
Alex Vakulenko35f89632015-10-09 08:18:35 -0700293 command->Complete({}, nullptr);
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700294}
295
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800296void MetricsCollector::UpdateWeaveState() {
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800297 auto weave_service = service_.lock();
298 if (!weave_service)
Alex Vakulenko82b02de2015-10-09 20:07:47 -0700299 return;
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700300
Alex Vakulenko9fc597b2015-12-09 12:34:18 -0800301 std::string enabled =
302 metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled";
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700303
Alex Vakulenkoba95a942016-01-07 10:10:12 -0800304 if (!weave_service->SetStateProperty(kWeaveComponent, kWeaveTrait,
Alex Vakulenkoeca14e32016-01-28 14:39:27 -0800305 "analyticsReportingState",
306 *brillo::ToValue(enabled),
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800307 nullptr)) {
Bertrand SIMONNET59890e22015-10-02 16:45:18 -0700308 LOG(ERROR) << "failed to update weave's state";
309 }
310}
311
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800312void MetricsCollector::ProcessUserCrash() {
Daniel Eratc83975a2014-04-04 08:53:44 -0700313 // Counts the active time up to now.
314 UpdateStats(TimeTicks::Now(), Time::Now());
Darin Petkov1bb904e2010-06-16 15:58:06 -0700315
316 // Reports the active use time since the last crash and resets it.
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700317 SendAndResetCrashIntervalSample(user_crash_interval_);
Ken Mixterccd84c02010-08-16 19:57:13 -0700318
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800319 any_crashes_daily_count_->Add(1);
320 any_crashes_weekly_count_->Add(1);
321 user_crashes_daily_count_->Add(1);
322 user_crashes_weekly_count_->Add(1);
Darin Petkov1bb904e2010-06-16 15:58:06 -0700323}
324
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800325void MetricsCollector::ProcessKernelCrash() {
Daniel Eratc83975a2014-04-04 08:53:44 -0700326 // Counts the active time up to now.
327 UpdateStats(TimeTicks::Now(), Time::Now());
Darin Petkov38d5cb02010-06-24 12:10:26 -0700328
329 // Reports the active use time since the last crash and resets it.
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700330 SendAndResetCrashIntervalSample(kernel_crash_interval_);
Ken Mixterccd84c02010-08-16 19:57:13 -0700331
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800332 any_crashes_daily_count_->Add(1);
333 any_crashes_weekly_count_->Add(1);
334 kernel_crashes_daily_count_->Add(1);
335 kernel_crashes_weekly_count_->Add(1);
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800336
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800337 kernel_crashes_version_count_->Add(1);
Darin Petkov38d5cb02010-06-24 12:10:26 -0700338}
339
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800340void MetricsCollector::ProcessUncleanShutdown() {
Daniel Eratc83975a2014-04-04 08:53:44 -0700341 // Counts the active time up to now.
342 UpdateStats(TimeTicks::Now(), Time::Now());
Ken Mixterccd84c02010-08-16 19:57:13 -0700343
344 // Reports the active use time since the last crash and resets it.
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700345 SendAndResetCrashIntervalSample(unclean_shutdown_interval_);
Ken Mixterccd84c02010-08-16 19:57:13 -0700346
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800347 unclean_shutdowns_daily_count_->Add(1);
348 unclean_shutdowns_weekly_count_->Add(1);
349 any_crashes_daily_count_->Add(1);
350 any_crashes_weekly_count_->Add(1);
Ken Mixterccd84c02010-08-16 19:57:13 -0700351}
352
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800353bool MetricsCollector::CheckSystemCrash(const string& crash_file) {
Darin Petkov38d5cb02010-06-24 12:10:26 -0700354 FilePath crash_detected(crash_file);
Ben Chan2e6543d2014-02-05 23:26:25 -0800355 if (!base::PathExists(crash_detected))
Ken Mixterccd84c02010-08-16 19:57:13 -0700356 return false;
Darin Petkov38d5cb02010-06-24 12:10:26 -0700357
358 // Deletes the crash-detected file so that the daemon doesn't report
359 // another kernel crash in case it's restarted.
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800360 base::DeleteFile(crash_detected, false); // not recursive
Ken Mixterccd84c02010-08-16 19:57:13 -0700361 return true;
Darin Petkov38d5cb02010-06-24 12:10:26 -0700362}
363
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800364void MetricsCollector::StatsReporterInit() {
Bertrand SIMONNET5658dc52015-09-18 13:38:10 -0700365 disk_usage_collector_->Schedule();
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700366
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -0800367 cpu_usage_collector_->Init();
368 cpu_usage_collector_->Schedule();
369
Bertrand SIMONNET7a964052015-09-29 11:07:24 -0700370 // Don't start a collection cycle during the first run to avoid delaying the
371 // boot.
372 averaged_stats_collector_->ScheduleWait();
Luigi Semenzatoc88e42d2011-02-17 10:21:16 -0800373}
374
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800375void MetricsCollector::ScheduleMeminfoCallback(int wait) {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700376 if (testing_) {
377 return;
378 }
Steve Funge86591e2014-12-01 13:38:21 -0800379 base::TimeDelta waitDelta = base::TimeDelta::FromSeconds(wait);
380 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800381 base::Bind(&MetricsCollector::MeminfoCallback,
382 weak_ptr_factory_.GetWeakPtr(), waitDelta),
Steve Funge86591e2014-12-01 13:38:21 -0800383 waitDelta);
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700384}
385
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800386void MetricsCollector::MeminfoCallback(base::TimeDelta wait) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700387 string meminfo_raw;
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700388 const FilePath meminfo_path(kMeminfoFileName);
Ben Chan2e6543d2014-02-05 23:26:25 -0800389 if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700390 LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
Steve Funge86591e2014-12-01 13:38:21 -0800391 return;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700392 }
Luigi Semenzato96360192014-06-04 10:53:35 -0700393 // Make both calls even if the first one fails.
Bertrand SIMONNETebbe35c2015-09-08 10:13:35 -0700394 if (ProcessMeminfo(meminfo_raw)) {
Steve Funge86591e2014-12-01 13:38:21 -0800395 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800396 base::Bind(&MetricsCollector::MeminfoCallback,
397 weak_ptr_factory_.GetWeakPtr(), wait),
Steve Funge86591e2014-12-01 13:38:21 -0800398 wait);
399 }
Luigi Semenzato96360192014-06-04 10:53:35 -0700400}
401
402// static
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800403bool MetricsCollector::ReadFileToUint64(const base::FilePath& path,
404 uint64_t* value) {
Luigi Semenzato96360192014-06-04 10:53:35 -0700405 std::string content;
406 if (!base::ReadFileToString(path, &content)) {
407 PLOG(WARNING) << "cannot read " << path.MaybeAsASCII();
408 return false;
409 }
Luigi Semenzato4a6c9422014-06-30 18:12:28 -0700410 // Remove final newline.
411 base::TrimWhitespaceASCII(content, base::TRIM_TRAILING, &content);
Luigi Semenzato96360192014-06-04 10:53:35 -0700412 if (!base::StringToUint64(content, value)) {
413 LOG(WARNING) << "invalid integer: " << content;
414 return false;
415 }
416 return true;
417}
418
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800419bool MetricsCollector::ReportZram(const base::FilePath& zram_dir) {
Luigi Semenzato96360192014-06-04 10:53:35 -0700420 // Data sizes are in bytes. |zero_pages| is in number of pages.
Ben Chanf05ab402014-08-07 00:54:59 -0700421 uint64_t compr_data_size, orig_data_size, zero_pages;
Luigi Semenzato96360192014-06-04 10:53:35 -0700422 const size_t page_size = 4096;
423
424 if (!ReadFileToUint64(zram_dir.Append(kComprDataSizeName),
425 &compr_data_size) ||
426 !ReadFileToUint64(zram_dir.Append(kOrigDataSizeName), &orig_data_size) ||
427 !ReadFileToUint64(zram_dir.Append(kZeroPagesName), &zero_pages)) {
428 return false;
429 }
430
431 // |orig_data_size| does not include zero-filled pages.
432 orig_data_size += zero_pages * page_size;
433
434 const int compr_data_size_mb = compr_data_size >> 20;
435 const int savings_mb = (orig_data_size - compr_data_size) >> 20;
436 const int zero_ratio_percent = zero_pages * page_size * 100 / orig_data_size;
437
438 // Report compressed size in megabytes. 100 MB or less has little impact.
439 SendSample("Platform.ZramCompressedSize", compr_data_size_mb, 100, 4000, 50);
440 SendSample("Platform.ZramSavings", savings_mb, 100, 4000, 50);
441 // The compression ratio is multiplied by 100 for better resolution. The
442 // ratios of interest are between 1 and 6 (100% and 600% as reported). We
443 // don't want samples when very little memory is being compressed.
444 if (compr_data_size_mb >= 1) {
445 SendSample("Platform.ZramCompressionRatioPercent",
446 orig_data_size * 100 / compr_data_size, 100, 600, 50);
447 }
448 // The values of interest for zero_pages are between 1MB and 1GB. The units
449 // are number of pages.
450 SendSample("Platform.ZramZeroPages", zero_pages, 256, 256 * 1024, 50);
451 SendSample("Platform.ZramZeroRatioPercent", zero_ratio_percent, 1, 50, 50);
452
453 return true;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700454}
455
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800456bool MetricsCollector::ProcessMeminfo(const string& meminfo_raw) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700457 static const MeminfoRecord fields_array[] = {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700458 { "MemTotal", "MemTotal" }, // SPECIAL CASE: total system memory
459 { "MemFree", "MemFree" },
460 { "Buffers", "Buffers" },
461 { "Cached", "Cached" },
462 // { "SwapCached", "SwapCached" },
463 { "Active", "Active" },
464 { "Inactive", "Inactive" },
465 { "ActiveAnon", "Active(anon)" },
466 { "InactiveAnon", "Inactive(anon)" },
467 { "ActiveFile" , "Active(file)" },
468 { "InactiveFile", "Inactive(file)" },
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800469 { "Unevictable", "Unevictable", kMeminfoOp_HistLog },
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700470 // { "Mlocked", "Mlocked" },
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800471 { "SwapTotal", "SwapTotal", kMeminfoOp_SwapTotal },
472 { "SwapFree", "SwapFree", kMeminfoOp_SwapFree },
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700473 // { "Dirty", "Dirty" },
474 // { "Writeback", "Writeback" },
475 { "AnonPages", "AnonPages" },
476 { "Mapped", "Mapped" },
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800477 { "Shmem", "Shmem", kMeminfoOp_HistLog },
478 { "Slab", "Slab", kMeminfoOp_HistLog },
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700479 // { "SReclaimable", "SReclaimable" },
480 // { "SUnreclaim", "SUnreclaim" },
481 };
Luigi Semenzato8accd332011-05-17 16:37:18 -0700482 vector<MeminfoRecord> fields(fields_array,
483 fields_array + arraysize(fields_array));
484 if (!FillMeminfo(meminfo_raw, &fields)) {
485 return false;
486 }
487 int total_memory = fields[0].value;
488 if (total_memory == 0) {
489 // this "cannot happen"
490 LOG(WARNING) << "borked meminfo parser";
491 return false;
492 }
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800493 int swap_total = 0;
494 int swap_free = 0;
Luigi Semenzato8accd332011-05-17 16:37:18 -0700495 // Send all fields retrieved, except total memory.
496 for (unsigned int i = 1; i < fields.size(); i++) {
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800497 string metrics_name = base::StringPrintf("Platform.Meminfo%s",
498 fields[i].name);
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800499 int percent;
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800500 switch (fields[i].op) {
501 case kMeminfoOp_HistPercent:
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800502 // report value as percent of total memory
503 percent = fields[i].value * 100 / total_memory;
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800504 SendLinearSample(metrics_name, percent, 100, 101);
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800505 break;
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800506 case kMeminfoOp_HistLog:
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800507 // report value in kbytes, log scale, 4Gb max
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800508 SendSample(metrics_name, fields[i].value, 1, 4 * 1000 * 1000, 100);
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800509 break;
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800510 case kMeminfoOp_SwapTotal:
511 swap_total = fields[i].value;
512 case kMeminfoOp_SwapFree:
513 swap_free = fields[i].value;
Luigi Semenzato3ccca062013-02-04 19:50:45 -0800514 break;
Luigi Semenzato8accd332011-05-17 16:37:18 -0700515 }
516 }
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800517 if (swap_total > 0) {
518 int swap_used = swap_total - swap_free;
519 int swap_used_percent = swap_used * 100 / swap_total;
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800520 SendSample("Platform.MeminfoSwapUsed", swap_used, 1, 8 * 1000 * 1000, 100);
Bertrand SIMONNET008fb7e2015-09-21 16:48:01 -0700521 SendLinearSample("Platform.MeminfoSwapUsed.Percent", swap_used_percent,
Luigi Semenzato942cbab2013-02-12 13:17:07 -0800522 100, 101);
523 }
Luigi Semenzato8accd332011-05-17 16:37:18 -0700524 return true;
525}
526
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800527bool MetricsCollector::FillMeminfo(const string& meminfo_raw,
528 vector<MeminfoRecord>* fields) {
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800529 vector<std::string> lines =
530 base::SplitString(meminfo_raw, "\n", base::KEEP_WHITESPACE,
531 base::SPLIT_WANT_NONEMPTY);
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700532
533 // Scan meminfo output and collect field values. Each field name has to
534 // match a meminfo entry (case insensitive) after removing non-alpha
535 // characters from the entry.
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800536 size_t ifield = 0;
537 for (size_t iline = 0;
538 iline < lines.size() && ifield < fields->size();
Luigi Semenzato8accd332011-05-17 16:37:18 -0700539 iline++) {
Alex Vakulenkoea05ff92016-01-20 07:53:57 -0800540 vector<string> tokens =
541 base::SplitString(lines[iline], ": ", base::KEEP_WHITESPACE,
542 base::SPLIT_WANT_NONEMPTY);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700543 if (strcmp((*fields)[ifield].match, tokens[0].c_str()) == 0) {
544 // Name matches. Parse value and save.
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700545 if (!base::StringToInt(tokens[1], &(*fields)[ifield].value)) {
546 LOG(WARNING) << "Cound not convert " << tokens[1] << " to int";
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700547 return false;
548 }
Luigi Semenzato8accd332011-05-17 16:37:18 -0700549 ifield++;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700550 }
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700551 }
Luigi Semenzato8accd332011-05-17 16:37:18 -0700552 if (ifield < fields->size()) {
553 // End of input reached while scanning.
554 LOG(WARNING) << "cannot find field " << (*fields)[ifield].match
555 << " and following";
556 return false;
557 }
558 return true;
559}
560
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800561void MetricsCollector::ScheduleMemuseCallback(double interval) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700562 if (testing_) {
563 return;
564 }
Steve Funge86591e2014-12-01 13:38:21 -0800565 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800566 base::Bind(&MetricsCollector::MemuseCallback,
567 weak_ptr_factory_.GetWeakPtr()),
Steve Funge86591e2014-12-01 13:38:21 -0800568 base::TimeDelta::FromSeconds(interval));
Luigi Semenzato8accd332011-05-17 16:37:18 -0700569}
570
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800571void MetricsCollector::MemuseCallback() {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700572 // Since we only care about active time (i.e. uptime minus sleep time) but
573 // the callbacks are driven by real time (uptime), we check if we should
574 // reschedule this callback due to intervening sleep periods.
575 double now = GetActiveTime();
Luigi Semenzato0d9a9c92013-12-05 15:55:12 -0800576 // Avoid intervals of less than one second.
577 double remaining_time = ceil(memuse_final_time_ - now);
578 if (remaining_time > 0) {
579 ScheduleMemuseCallback(remaining_time);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700580 } else {
Luigi Semenzato0d9a9c92013-12-05 15:55:12 -0800581 // Report stats and advance the measurement interval unless there are
582 // errors or we've completed the last interval.
Luigi Semenzato8accd332011-05-17 16:37:18 -0700583 if (MemuseCallbackWork() &&
Luigi Semenzato0d9a9c92013-12-05 15:55:12 -0800584 memuse_interval_index_ < arraysize(kMemuseIntervals)) {
585 double interval = kMemuseIntervals[memuse_interval_index_++];
586 memuse_final_time_ = now + interval;
587 ScheduleMemuseCallback(interval);
Luigi Semenzato8accd332011-05-17 16:37:18 -0700588 }
589 }
590}
591
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800592bool MetricsCollector::MemuseCallbackWork() {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700593 string meminfo_raw;
Bertrand SIMONNET675a10c2015-08-25 14:11:43 -0700594 const FilePath meminfo_path(kMeminfoFileName);
Ben Chan2e6543d2014-02-05 23:26:25 -0800595 if (!base::ReadFileToString(meminfo_path, &meminfo_raw)) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700596 LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
597 return false;
598 }
599 return ProcessMemuse(meminfo_raw);
600}
601
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800602bool MetricsCollector::ProcessMemuse(const string& meminfo_raw) {
Luigi Semenzato8accd332011-05-17 16:37:18 -0700603 static const MeminfoRecord fields_array[] = {
604 { "MemTotal", "MemTotal" }, // SPECIAL CASE: total system memory
605 { "ActiveAnon", "Active(anon)" },
606 { "InactiveAnon", "Inactive(anon)" },
607 };
608 vector<MeminfoRecord> fields(fields_array,
609 fields_array + arraysize(fields_array));
610 if (!FillMeminfo(meminfo_raw, &fields)) {
611 return false;
612 }
613 int total = fields[0].value;
614 int active_anon = fields[1].value;
615 int inactive_anon = fields[2].value;
616 if (total == 0) {
617 // this "cannot happen"
618 LOG(WARNING) << "borked meminfo parser";
619 return false;
620 }
Luigi Semenzato859b3f02014-02-05 15:33:19 -0800621 string metrics_name = base::StringPrintf("Platform.MemuseAnon%d",
622 memuse_interval_index_);
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800623 SendLinearSample(metrics_name, (active_anon + inactive_anon) * 100 / total,
Luigi Semenzato8accd332011-05-17 16:37:18 -0700624 100, 101);
625 return true;
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700626}
627
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800628void MetricsCollector::SendSample(const string& name, int sample,
629 int min, int max, int nbuckets) {
Darin Petkovfc91b422010-05-12 13:05:45 -0700630 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
Darin Petkov65b01462010-04-14 13:32:20 -0700631}
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700632
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800633void MetricsCollector::SendKernelCrashesCumulativeCountStats() {
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800634 // Report the number of crashes for this OS version, but don't clear the
635 // counter. It is cleared elsewhere on version change.
Ben Chanf05ab402014-08-07 00:54:59 -0700636 int64_t crashes_count = kernel_crashes_version_count_->Get();
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800637 SendSample(kernel_crashes_version_count_->Name(),
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700638 crashes_count,
639 1, // value of first bucket
640 500, // value of last bucket
641 100); // number of buckets
642
643
Ben Chanf05ab402014-08-07 00:54:59 -0700644 int64_t cpu_use_ms = version_cumulative_cpu_use_->Get();
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700645 SendSample(version_cumulative_cpu_use_->Name(),
646 cpu_use_ms / 1000, // stat is in seconds
647 1, // device may be used very little...
648 8 * 1000 * 1000, // ... or a lot (a little over 90 days)
649 100);
650
651 // On the first run after an autoupdate, cpu_use_ms and active_use_seconds
652 // can be zero. Avoid division by zero.
653 if (cpu_use_ms > 0) {
654 // Send the crash frequency since update in number of crashes per CPU year.
655 SendSample("Logging.KernelCrashesPerCpuYear",
656 crashes_count * kSecondsPerDay * 365 * 1000 / cpu_use_ms,
657 1,
658 1000 * 1000, // about one crash every 30s of CPU time
659 100);
660 }
661
Ben Chanf05ab402014-08-07 00:54:59 -0700662 int64_t active_use_seconds = version_cumulative_active_use_->Get();
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700663 if (active_use_seconds > 0) {
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700664 SendSample(version_cumulative_active_use_->Name(),
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700665 active_use_seconds,
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700666 1, // device may be used very little...
667 8 * 1000 * 1000, // ... or a lot (about 90 days)
668 100);
Luigi Semenzatoba0c65d2014-03-17 12:28:38 -0700669 // Same as above, but per year of active time.
670 SendSample("Logging.KernelCrashesPerActiveYear",
671 crashes_count * kSecondsPerDay * 365 / active_use_seconds,
672 1,
673 1000 * 1000, // about one crash every 30s of active time
674 100);
675 }
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800676}
677
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800678void MetricsCollector::SendAndResetDailyUseSample(
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800679 const unique_ptr<PersistentInteger>& use) {
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700680 SendSample(use->Name(),
681 use->GetAndClear(),
682 1, // value of first bucket
683 kSecondsPerDay, // value of last bucket
684 50); // number of buckets
685}
686
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800687void MetricsCollector::SendAndResetCrashIntervalSample(
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800688 const unique_ptr<PersistentInteger>& interval) {
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800689 SendSample(interval->Name(),
690 interval->GetAndClear(),
691 1, // value of first bucket
692 4 * kSecondsPerWeek, // value of last bucket
693 50); // number of buckets
694}
695
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800696void MetricsCollector::SendAndResetCrashFrequencySample(
Bertrand SIMONNET6c9fbb92015-12-21 14:56:40 -0800697 const unique_ptr<PersistentInteger>& frequency) {
Luigi Semenzato2fd51cc2014-02-26 11:53:16 -0800698 SendSample(frequency->Name(),
699 frequency->GetAndClear(),
700 1, // value of first bucket
701 100, // value of last bucket
702 50); // number of buckets
703}
704
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800705void MetricsCollector::SendLinearSample(const string& name, int sample,
706 int max, int nbuckets) {
Luigi Semenzato29c7ef92011-04-12 14:12:35 -0700707 // TODO(semenzato): add a proper linear histogram to the Chrome external
708 // metrics API.
709 LOG_IF(FATAL, nbuckets != max + 1) << "unsupported histogram scale";
710 metrics_lib_->SendEnumToUMA(name, sample, max);
711}
Daniel Eratc83975a2014-04-04 08:53:44 -0700712
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800713void MetricsCollector::UpdateStats(TimeTicks now_ticks,
714 Time now_wall_time) {
Daniel Eratc83975a2014-04-04 08:53:44 -0700715 const int elapsed_seconds = (now_ticks - last_update_stats_time_).InSeconds();
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700716 daily_active_use_->Add(elapsed_seconds);
717 version_cumulative_active_use_->Add(elapsed_seconds);
Daniel Eratc83975a2014-04-04 08:53:44 -0700718 user_crash_interval_->Add(elapsed_seconds);
719 kernel_crash_interval_->Add(elapsed_seconds);
Bertrand SIMONNET0ada2ca2015-11-02 14:08:44 -0800720 TimeDelta cpu_use = cpu_usage_collector_->GetCumulativeCpuUse();
721 version_cumulative_cpu_use_->Add(
722 (cpu_use - latest_cpu_use_microseconds_).InMilliseconds());
723 latest_cpu_use_microseconds_ = cpu_use;
Daniel Eratc83975a2014-04-04 08:53:44 -0700724 last_update_stats_time_ = now_ticks;
725
726 const TimeDelta since_epoch = now_wall_time - Time::UnixEpoch();
727 const int day = since_epoch.InDays();
728 const int week = day / 7;
729
730 if (daily_cycle_->Get() != day) {
731 daily_cycle_->Set(day);
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700732 SendAndResetDailyUseSample(daily_active_use_);
733 SendAndResetCrashFrequencySample(any_crashes_daily_count_);
734 SendAndResetCrashFrequencySample(user_crashes_daily_count_);
735 SendAndResetCrashFrequencySample(kernel_crashes_daily_count_);
736 SendAndResetCrashFrequencySample(unclean_shutdowns_daily_count_);
Luigi Semenzatoe5883fa2014-04-18 17:00:35 -0700737 SendKernelCrashesCumulativeCountStats();
Daniel Eratc83975a2014-04-04 08:53:44 -0700738 }
739
740 if (weekly_cycle_->Get() != week) {
741 weekly_cycle_->Set(week);
Bertrand SIMONNET2d037832015-09-16 17:11:51 -0700742 SendAndResetCrashFrequencySample(any_crashes_weekly_count_);
743 SendAndResetCrashFrequencySample(user_crashes_weekly_count_);
744 SendAndResetCrashFrequencySample(kernel_crashes_weekly_count_);
745 SendAndResetCrashFrequencySample(unclean_shutdowns_weekly_count_);
Daniel Eratc83975a2014-04-04 08:53:44 -0700746 }
747}
748
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800749void MetricsCollector::HandleUpdateStatsTimeout() {
Steve Funge86591e2014-12-01 13:38:21 -0800750 UpdateStats(TimeTicks::Now(), Time::Now());
751 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
Bertrand SIMONNET608e4282015-11-12 17:52:17 -0800752 base::Bind(&MetricsCollector::HandleUpdateStatsTimeout,
Alex Vakulenko53ca76f2015-12-29 15:02:00 -0800753 weak_ptr_factory_.GetWeakPtr()),
Steve Funge86591e2014-12-01 13:38:21 -0800754 base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
Daniel Eratc83975a2014-04-04 08:53:44 -0700755}