Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: metrics_daemon.cc

Issue 6486021: Collect some disk statistics. (Closed) Base URL: http://git.chromium.org/git/metrics.git@master
Patch Set: Fixed style and added tests Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "metrics_daemon.h" 5 #include "metrics_daemon.h"
6 6
7 #include <fcntl.h>
7 #include <string.h> 8 #include <string.h>
8 9
9 #include <base/file_util.h> 10 #include <base/file_util.h>
10 #include <base/logging.h> 11 #include <base/logging.h>
11 #include <dbus/dbus-glib-lowlevel.h> 12 #include <dbus/dbus-glib-lowlevel.h>
12 13
13 #include "counter.h" 14 #include "counter.h"
14 15
15 using base::Time; 16 using base::Time;
16 using base::TimeDelta; 17 using base::TimeDelta;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 const char MetricsDaemon::kMetricUncleanShutdownsWeeklyName[] = 78 const char MetricsDaemon::kMetricUncleanShutdownsWeeklyName[] =
78 "Logging.UncleanShutdownsWeekly"; 79 "Logging.UncleanShutdownsWeekly";
79 const char MetricsDaemon::kMetricUserCrashesDailyName[] = 80 const char MetricsDaemon::kMetricUserCrashesDailyName[] =
80 "Logging.UserCrashesDaily"; 81 "Logging.UserCrashesDaily";
81 const char MetricsDaemon::kMetricUserCrashesWeeklyName[] = 82 const char MetricsDaemon::kMetricUserCrashesWeeklyName[] =
82 "Logging.UserCrashesWeekly"; 83 "Logging.UserCrashesWeekly";
83 const char MetricsDaemon::kMetricCrashFrequencyMin = 1; 84 const char MetricsDaemon::kMetricCrashFrequencyMin = 1;
84 const char MetricsDaemon::kMetricCrashFrequencyMax = 100; 85 const char MetricsDaemon::kMetricCrashFrequencyMax = 100;
85 const char MetricsDaemon::kMetricCrashFrequencyBuckets = 50; 86 const char MetricsDaemon::kMetricCrashFrequencyBuckets = 50;
86 87
88 // disk stats metrics
89
90 // The {Read,Write}Sectors numbers are in sectors/second.
91 // A sector is usually 512 bytes.
92
93 const char MetricsDaemon::kMetricReadSectorsLongName[] =
94 "Filesystem.ReadSectorsLong";
95 const char MetricsDaemon::kMetricWriteSectorsLongName[] =
96 "Filesystem.WriteSectorsLong";
97 const char MetricsDaemon::kMetricReadSectorsShortName[] =
98 "Filesystem.ReadSectorsShort";
99 const char MetricsDaemon::kMetricWriteSectorsShortName[] =
100 "Filesystem.WriteSectorsShort";
101
102 const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds
103 const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds
104
105 // Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
106 // sectors.
107 const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second
108 const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets
109
110 // Path to disk stats.
111 const char MetricsDaemon::kMetricsDiskStatsPath[] = "/sys/class/block/sda/stat";
petkov 2011/02/12 05:34:45 Unused? It seems that the current revision won't w
petkov 2011/02/13 17:28:47 Isn't this something like /sys/block/mmcblk0 on AR
Luigi Semenzato 2011/02/14 18:43:43 That path exists on my kaen, but the stats there s
112
87 // persistent metrics path 113 // persistent metrics path
88 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics"; 114 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics";
89 115
90 116
91 // static 117 // static
92 const char* MetricsDaemon::kDBusMatches_[] = { 118 const char* MetricsDaemon::kDBusMatches_[] = {
93 "type='signal'," 119 "type='signal',"
94 "interface='" DBUS_IFACE_CRASH_REPORTER "'," 120 "interface='" DBUS_IFACE_CRASH_REPORTER "',"
95 "path='/'," 121 "path='/',"
96 "member='UserCrash'", 122 "member='UserCrash'",
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 DeleteFrequencyCounters(); 237 DeleteFrequencyCounters();
212 ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName); 238 ConfigureCrashFrequencyReporter(kMetricAnyCrashesDailyName);
213 ConfigureCrashFrequencyReporter(kMetricAnyCrashesWeeklyName); 239 ConfigureCrashFrequencyReporter(kMetricAnyCrashesWeeklyName);
214 ConfigureCrashFrequencyReporter(kMetricKernelCrashesDailyName); 240 ConfigureCrashFrequencyReporter(kMetricKernelCrashesDailyName);
215 ConfigureCrashFrequencyReporter(kMetricKernelCrashesWeeklyName); 241 ConfigureCrashFrequencyReporter(kMetricKernelCrashesWeeklyName);
216 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsDailyName); 242 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsDailyName);
217 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName); 243 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName);
218 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName); 244 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName);
219 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName); 245 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName);
220 246
247 DiskStatsReporterInit();
248
221 // Don't setup D-Bus and GLib in test mode. 249 // Don't setup D-Bus and GLib in test mode.
222 if (testing) 250 if (testing)
223 return; 251 return;
224 252
225 g_thread_init(NULL); 253 g_thread_init(NULL);
226 g_type_init(); 254 g_type_init();
227 dbus_g_thread_init(); 255 dbus_g_thread_init();
228 256
229 DBusError error; 257 DBusError error;
230 dbus_error_init(&error); 258 dbus_error_init(&error);
(...skipping 12 matching lines...) Expand all
243 LOG_IF(FATAL, dbus_error_is_set(&error)) << 271 LOG_IF(FATAL, dbus_error_is_set(&error)) <<
244 "unable to add a match: " << SAFE_MESSAGE(error); 272 "unable to add a match: " << SAFE_MESSAGE(error);
245 } 273 }
246 274
247 // Adds the D-Bus filter routine to be called back whenever one of 275 // Adds the D-Bus filter routine to be called back whenever one of
248 // the registered D-Bus matches is successful. The daemon is not 276 // the registered D-Bus matches is successful. The daemon is not
249 // activated for D-Bus messages that don't match. 277 // activated for D-Bus messages that don't match.
250 CHECK(dbus_connection_add_filter(connection, MessageFilter, this, NULL)); 278 CHECK(dbus_connection_add_filter(connection, MessageFilter, this, NULL));
251 } 279 }
252 280
281 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib,
282 const char* diskstats_path) {
283 diskstats_path_ = diskstats_path;
284 Init(testing, metrics_lib);
285 }
286
253 void MetricsDaemon::Loop() { 287 void MetricsDaemon::Loop() {
254 GMainLoop* loop = g_main_loop_new(NULL, false); 288 GMainLoop* loop = g_main_loop_new(NULL, false);
255 g_main_loop_run(loop); 289 g_main_loop_run(loop);
256 } 290 }
257 291
258 // static 292 // static
259 DBusHandlerResult MetricsDaemon::MessageFilter(DBusConnection* connection, 293 DBusHandlerResult MetricsDaemon::MessageFilter(DBusConnection* connection,
260 DBusMessage* message, 294 DBusMessage* message,
261 void* user_data) { 295 void* user_data) {
262 Time now = Time::Now(); 296 Time now = Time::Now();
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
487 // If there's a use monitor scheduled already, destroys it. 521 // If there's a use monitor scheduled already, destroys it.
488 if (usemon_source_ == NULL) 522 if (usemon_source_ == NULL)
489 return; 523 return;
490 524
491 DLOG(INFO) << "destroying use monitor"; 525 DLOG(INFO) << "destroying use monitor";
492 g_source_destroy(usemon_source_); 526 g_source_destroy(usemon_source_);
493 usemon_source_ = NULL; 527 usemon_source_ = NULL;
494 usemon_interval_ = 0; 528 usemon_interval_ = 0;
495 } 529 }
496 530
531 void MetricsDaemon::DiskStatsReporterInit() {
532 DiskStatsReadStats(&read_sectors_, &write_sectors_);
533 // The first time around just run the long stat, so we don't delay boot.
534 diskstats_state_ = kDiskStatsLong;
535 ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval);
536 }
537
538 void MetricsDaemon::ScheduleDiskStatsCallback(int wait) {
539 if (testing_) {
540 return;
541 }
542 g_timeout_add_seconds(wait, DiskStatsCallbackStatic, this);
543 }
544
545 void MetricsDaemon::DiskStatsReadStats(long int* read_sectors,
546 long int* write_sectors) {
547 int nchars;
548 int nitems;
549 char line[200];
550 int file = HANDLE_EINTR(open(diskstats_path_, O_RDONLY));
551 if (file < 0) {
552 PLOG(WARNING) << "cannot open " << diskstats_path_;
553 return;
554 }
555 nchars = HANDLE_EINTR(read(file, line, sizeof(line)));
556 if (nchars < 0) {
557 PLOG(WARNING) << "cannot read from " << diskstats_path_;
558 goto close_file;
petkov 2011/02/12 05:34:45 goto is a bit evil. I'd suggestion two options: -
Luigi Semenzato 2011/02/14 18:43:43 And a third option: an else clause. (It doesn't s
559 }
560 LOG_IF(WARNING, nchars == sizeof(line)) << "line too long in "
561 << diskstats_path_;
562 line[nchars] = '\0';
563 nitems = sscanf(line, "%*d %*d %ld %*d %*d %*d %ld",
564 read_sectors, write_sectors);
565 LOG_IF(WARNING, nitems != 2) << "found " << nitems << " items in "
566 << diskstats_path_ << ", expected 2";
567 close_file:
568 HANDLE_EINTR(close(file));
569 }
570
571 // static
572 gboolean MetricsDaemon::DiskStatsCallbackStatic(void* handle) {
573 (static_cast<MetricsDaemon*>(handle))->DiskStatsCallback();
574 return false; // one-time callback
575 }
576
577 void MetricsDaemon::DiskStatsCallback() {
578 long int read_sectors_now, write_sectors_now;
579 DiskStatsReadStats(&read_sectors_now, &write_sectors_now);
580
581 switch (diskstats_state_) {
582
petkov 2011/02/12 05:34:45 remove blank line?
583 case kDiskStatsShort:
584 SendMetric(kMetricReadSectorsShortName,
585 (int) (read_sectors_now - read_sectors_) /
586 kMetricDiskStatsShortInterval,
587 0,
petkov 2011/02/12 05:34:45 I think 0 is invalid minimum for some reason-- min
588 kMetricSectorsIOMax,
589 kMetricSectorsBuckets);
590 SendMetric(kMetricWriteSectorsShortName,
591 (int) (write_sectors_now - write_sectors_) /
592 kMetricDiskStatsShortInterval,
593 0,
594 kMetricSectorsIOMax,
595 kMetricSectorsBuckets);
596 // Schedule long callback.
597 diskstats_state_ = kDiskStatsLong;
598 ScheduleDiskStatsCallback(kMetricDiskStatsLongInterval -
599 kMetricDiskStatsShortInterval);
600 break;
601
602 case kDiskStatsLong:
603 SendMetric(kMetricReadSectorsLongName,
604 (int) (read_sectors_now - read_sectors_) /
605 kMetricDiskStatsLongInterval,
606 0,
607 kMetricSectorsIOMax,
608 kMetricSectorsBuckets);
609 SendMetric(kMetricWriteSectorsLongName,
610 (int) (write_sectors_now - write_sectors_) /
611 kMetricDiskStatsLongInterval,
612 0,
613 kMetricSectorsIOMax,
614 kMetricSectorsBuckets);
615 // Reset sector counters
616 read_sectors_ = read_sectors_now;
617 write_sectors_ = write_sectors_now;
618
619 // Schedule short callback.
620 diskstats_state_ = kDiskStatsShort;
621 ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval);
622 break;
623
624 default:
625 LOG(FATAL) << "Invalid disk stats state";
626 }
627 }
628
497 // static 629 // static
498 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) { 630 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) {
499 if (count <= 0) 631 if (count <= 0)
500 return; 632 return;
501 633
502 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); 634 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
503 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; 635 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute;
504 daemon->SendMetric(kMetricDailyUseTimeName, minutes, 636 daemon->SendMetric(kMetricDailyUseTimeName, minutes,
505 kMetricDailyUseTimeMin, 637 kMetricDailyUseTimeMin,
506 kMetricDailyUseTimeMax, 638 kMetricDailyUseTimeMax,
507 kMetricDailyUseTimeBuckets); 639 kMetricDailyUseTimeBuckets);
508 } 640 }
509 641
510 void MetricsDaemon::SendMetric(const string& name, int sample, 642 void MetricsDaemon::SendMetric(const string& name, int sample,
511 int min, int max, int nbuckets) { 643 int min, int max, int nbuckets) {
512 DLOG(INFO) << "received metric: " << name << " " << sample << " " 644 DLOG(INFO) << "received metric: " << name << " " << sample << " "
513 << min << " " << max << " " << nbuckets; 645 << min << " " << max << " " << nbuckets;
514 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); 646 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
515 } 647 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698