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

Side by Side Diff: metrics_daemon.cc

Issue 6804014: Add meminfo UMA collection. (Closed) Base URL: http://git.chromium.org/git/metrics.git@master
Patch Set: more fixes Created 9 years, 8 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
« no previous file with comments | « metrics_daemon.h ('k') | metrics_daemon_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <fcntl.h>
8 #include <string.h> 8 #include <string.h>
9 9
10 #include <base/file_util.h> 10 #include <base/file_util.h>
11 #include <base/logging.h> 11 #include <base/logging.h>
12 #include <base/string_util.h>
12 #include <dbus/dbus-glib-lowlevel.h> 13 #include <dbus/dbus-glib-lowlevel.h>
13 14
14 #include "counter.h" 15 #include "counter.h"
15 16
16 using base::Time; 17 using base::Time;
17 using base::TimeDelta; 18 using base::TimeDelta;
18 using base::TimeTicks; 19 using base::TimeTicks;
19 using std::string; 20 using std::string;
20 21
21 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error") 22 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error")
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 const char MetricsDaemon::kMetricWriteSectorsLongName[] = 96 const char MetricsDaemon::kMetricWriteSectorsLongName[] =
96 "Platform.WriteSectorsLong"; 97 "Platform.WriteSectorsLong";
97 const char MetricsDaemon::kMetricReadSectorsShortName[] = 98 const char MetricsDaemon::kMetricReadSectorsShortName[] =
98 "Platform.ReadSectorsShort"; 99 "Platform.ReadSectorsShort";
99 const char MetricsDaemon::kMetricWriteSectorsShortName[] = 100 const char MetricsDaemon::kMetricWriteSectorsShortName[] =
100 "Platform.WriteSectorsShort"; 101 "Platform.WriteSectorsShort";
101 102
102 const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds 103 const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds
103 const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds 104 const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds
104 105
106 const int MetricsDaemon::kMetricMeminfoInterval = 30; // seconds
107
105 // Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte 108 // Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
106 // sectors. 109 // sectors.
107 const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second 110 const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second
108 const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets 111 const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets
109 112
110 // persistent metrics path 113 // persistent metrics path
111 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics"; 114 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics";
112 115
113 116
114 // static 117 // static
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName); 244 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName);
242 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName); 245 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName);
243 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName); 246 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName);
244 247
245 // Don't attempt to collect disk stats if there is no disk stats file. 248 // Don't attempt to collect disk stats if there is no disk stats file.
246 if (!diskstats_path.empty()) { 249 if (!diskstats_path.empty()) {
247 diskstats_path_ = diskstats_path; 250 diskstats_path_ = diskstats_path;
248 DiskStatsReporterInit(); 251 DiskStatsReporterInit();
249 } 252 }
250 253
254 // Start collecting meminfo stats.
255 ScheduleMeminfoCallback(kMetricMeminfoInterval);
256
251 // Don't setup D-Bus and GLib in test mode. 257 // Don't setup D-Bus and GLib in test mode.
252 if (testing) 258 if (testing)
253 return; 259 return;
254 260
255 g_thread_init(NULL); 261 g_thread_init(NULL);
256 g_type_init(); 262 g_type_init();
257 dbus_g_thread_init(); 263 dbus_g_thread_init();
258 264
259 DBusError error; 265 DBusError error;
260 dbus_error_init(&error); 266 dbus_error_init(&error);
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 write_sectors_ = write_sectors_now; 616 write_sectors_ = write_sectors_now;
611 // Schedule short callback. 617 // Schedule short callback.
612 diskstats_state_ = kDiskStatsShort; 618 diskstats_state_ = kDiskStatsShort;
613 ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval); 619 ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval);
614 break; 620 break;
615 default: 621 default:
616 LOG(FATAL) << "Invalid disk stats state"; 622 LOG(FATAL) << "Invalid disk stats state";
617 } 623 }
618 } 624 }
619 625
626 void MetricsDaemon::ScheduleMeminfoCallback(int wait) {
627 if (testing_) {
628 return;
629 }
630 g_timeout_add_seconds(wait, MeminfoCallbackStatic, this);
631 }
632
633 // static
634 gboolean MetricsDaemon::MeminfoCallbackStatic(void* handle) {
635 return (static_cast<MetricsDaemon*>(handle))->MeminfoCallback();
636 }
637
638 gboolean MetricsDaemon::MeminfoCallback() {
639 std::string meminfo;
640 const FilePath meminfo_path("/proc/meminfo");
641 if (!file_util::ReadFileToString(meminfo_path, &meminfo)) {
642 LOG(WARNING) << "cannot read " << meminfo_path.value().c_str();
643 return false;
644 }
645 return ProcessMeminfo(meminfo);
646 }
647
648 gboolean MetricsDaemon::ProcessMeminfo(std::string meminfo) {
649 // This array has one element for every item of /proc/meminfo that we want to
650 // report to UMA. They must be listed in the same order in which
651 // /proc/meminfo prints them.
652 struct {
653 const char* name; // print name
654 const char* match; // string to match in output of /proc/meminfo
655 int log_scale; // report with log scale instead of linear percent
656 } fields[] = {
657 { "MemTotal", "MemTotal" }, // SPECIAL CASE: total system memory
658 { "MemFree", "MemFree" },
659 { "Buffers", "Buffers" },
660 { "Cached", "Cached" },
661 // { "SwapCached", "SwapCached" },
662 { "Active", "Active" },
663 { "Inactive", "Inactive" },
664 { "ActiveAnon", "Active(anon)" },
665 { "InactiveAnon", "Inactive(anon)" },
666 { "ActiveFile" , "Active(file)" },
667 { "InactiveFile", "Inactive(file)" },
668 { "Unevictable", "Unevictable", 1 },
669 // { "Mlocked", "Mlocked" },
670 // { "SwapTotal", "SwapTotal" },
671 // { "SwapFree", "SwapFree" },
672 // { "Dirty", "Dirty" },
673 // { "Writeback", "Writeback" },
674 { "AnonPages", "AnonPages" },
675 { "Mapped", "Mapped" },
676 { "Shmem", "Shmem", 1 },
677 { "Slab", "Slab", 1 },
678 // { "SReclaimable", "SReclaimable" },
679 // { "SUnreclaim", "SUnreclaim" },
680 };
681 // arraysize doesn't work here, probably can't handle anonymous structs
682 const int nfields = sizeof(fields) / sizeof(fields[0]);
683 int total_memory = 0;
684 std::vector<std::string> lines;
685 int nlines = Tokenize(meminfo, "\n", &lines);
686
687 // Scan meminfo output and collect field values. Each field name has to
688 // match a meminfo entry (case insensitive) after removing non-alpha
689 // characters from the entry.
690 int i = 0;
691 int iline = 0;
692 for (;;) {
693 if (i == nfields) {
694 // all fields are matched
695 return true;
696 }
697 if (iline == nlines) {
698 // end of input reached while scanning
699 LOG(WARNING) << "cannot find field " << fields[i].match
700 << " and following";
701 return false;
702 }
703
704 std::vector<std::string> tokens;
705 Tokenize(lines[iline], ": ", &tokens);
706
707 if (strcmp(fields[i].match, tokens[0].c_str()) == 0) {
708 // name matches: parse value and report
709 int meminfo_value;
710 char metrics_name[128];
711 char* rest;
712 meminfo_value = static_cast<int>(strtol(tokens[1].c_str(), &rest, 10));
713 if (*rest != '\0') {
714 LOG(WARNING) << "missing meminfo value";
715 return false;
716 }
717 if (i == 0) {
718 // special case: total memory
719 total_memory = meminfo_value;
720 } else {
721 snprintf(metrics_name, sizeof(metrics_name),
722 "Platform.Meminfo%s", fields[i].name);
723 if (fields[i].log_scale) {
724 // report value in kbytes, log scale, 4Gb max
725 SendMetric(metrics_name, meminfo_value, 1, 4 * 1000 * 1000, 100);
726 } else {
727 // report value as percent of total memory
728 if (total_memory == 0) {
729 // this "cannot happen"
730 LOG(WARNING) << "borked meminfo parser";
731 return false;
732 }
733 int percent = meminfo_value * 100 / total_memory;
734 SendLinearMetric(metrics_name, percent, 100, 101);
735 }
736 }
737 // start looking for next field
738 i++;
739 }
740 iline++;
741 }
742 }
743
620 // static 744 // static
621 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) { 745 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) {
622 if (count <= 0) 746 if (count <= 0)
623 return; 747 return;
624 748
625 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); 749 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
626 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; 750 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute;
627 daemon->SendMetric(kMetricDailyUseTimeName, minutes, 751 daemon->SendMetric(kMetricDailyUseTimeName, minutes,
628 kMetricDailyUseTimeMin, 752 kMetricDailyUseTimeMin,
629 kMetricDailyUseTimeMax, 753 kMetricDailyUseTimeMax,
630 kMetricDailyUseTimeBuckets); 754 kMetricDailyUseTimeBuckets);
631 } 755 }
632 756
633 void MetricsDaemon::SendMetric(const string& name, int sample, 757 void MetricsDaemon::SendMetric(const string& name, int sample,
634 int min, int max, int nbuckets) { 758 int min, int max, int nbuckets) {
635 DLOG(INFO) << "received metric: " << name << " " << sample << " " 759 DLOG(INFO) << "received metric: " << name << " " << sample << " "
636 << min << " " << max << " " << nbuckets; 760 << min << " " << max << " " << nbuckets;
637 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); 761 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
638 } 762 }
763
764 void MetricsDaemon::SendLinearMetric(const string& name, int sample,
765 int max, int nbuckets) {
766 DLOG(INFO) << "received linear metric: " << name << " " << sample << " "
767 << max << " " << nbuckets;
768 // TODO(semenzato): add a proper linear histogram to the Chrome external
769 // metrics API.
770 LOG_IF(FATAL, nbuckets != max + 1) << "unsupported histogram scale";
771 metrics_lib_->SendEnumToUMA(name, sample, max);
772 }
OLDNEW
« no previous file with comments | « metrics_daemon.h ('k') | metrics_daemon_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698