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

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: 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>
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 const char MetricsDaemon::kMetricWriteSectorsLongName[] = 95 const char MetricsDaemon::kMetricWriteSectorsLongName[] =
96 "Platform.WriteSectorsLong"; 96 "Platform.WriteSectorsLong";
97 const char MetricsDaemon::kMetricReadSectorsShortName[] = 97 const char MetricsDaemon::kMetricReadSectorsShortName[] =
98 "Platform.ReadSectorsShort"; 98 "Platform.ReadSectorsShort";
99 const char MetricsDaemon::kMetricWriteSectorsShortName[] = 99 const char MetricsDaemon::kMetricWriteSectorsShortName[] =
100 "Platform.WriteSectorsShort"; 100 "Platform.WriteSectorsShort";
101 101
102 const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds 102 const int MetricsDaemon::kMetricDiskStatsShortInterval = 1; // seconds
103 const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds 103 const int MetricsDaemon::kMetricDiskStatsLongInterval = 30; // seconds
104 104
105 const int MetricsDaemon::kMetricMeminfoInterval = 30; // seconds
106
105 // Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte 107 // Assume a max rate of 250Mb/s for reads (worse for writes) and 512 byte
106 // sectors. 108 // sectors.
107 const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second 109 const int MetricsDaemon::kMetricSectorsIOMax = 500000; // sectors/second
108 const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets 110 const int MetricsDaemon::kMetricSectorsBuckets = 50; // buckets
109 111
110 // persistent metrics path 112 // persistent metrics path
111 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics"; 113 const char MetricsDaemon::kMetricsPath[] = "/var/log/metrics";
112 114
113 115
114 // static 116 // static
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName); 243 ConfigureCrashFrequencyReporter(kMetricUncleanShutdownsWeeklyName);
242 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName); 244 ConfigureCrashFrequencyReporter(kMetricUserCrashesDailyName);
243 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName); 245 ConfigureCrashFrequencyReporter(kMetricUserCrashesWeeklyName);
244 246
245 // Don't attempt to collect disk stats if there is no disk stats file. 247 // Don't attempt to collect disk stats if there is no disk stats file.
246 if (!diskstats_path.empty()) { 248 if (!diskstats_path.empty()) {
247 diskstats_path_ = diskstats_path; 249 diskstats_path_ = diskstats_path;
248 DiskStatsReporterInit(); 250 DiskStatsReporterInit();
249 } 251 }
250 252
253 // Start collecting meminfo stats.
254 ScheduleMeminfoCallback(kMetricMeminfoInterval);
255
251 // Don't setup D-Bus and GLib in test mode. 256 // Don't setup D-Bus and GLib in test mode.
252 if (testing) 257 if (testing)
253 return; 258 return;
254 259
255 g_thread_init(NULL); 260 g_thread_init(NULL);
256 g_type_init(); 261 g_type_init();
257 dbus_g_thread_init(); 262 dbus_g_thread_init();
258 263
259 DBusError error; 264 DBusError error;
260 dbus_error_init(&error); 265 dbus_error_init(&error);
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 write_sectors_ = write_sectors_now; 615 write_sectors_ = write_sectors_now;
611 // Schedule short callback. 616 // Schedule short callback.
612 diskstats_state_ = kDiskStatsShort; 617 diskstats_state_ = kDiskStatsShort;
613 ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval); 618 ScheduleDiskStatsCallback(kMetricDiskStatsShortInterval);
614 break; 619 break;
615 default: 620 default:
616 LOG(FATAL) << "Invalid disk stats state"; 621 LOG(FATAL) << "Invalid disk stats state";
617 } 622 }
618 } 623 }
619 624
625 void MetricsDaemon::ScheduleMeminfoCallback(int wait) {
626 if (testing_) {
627 return;
628 }
629 g_timeout_add_seconds(wait, MeminfoCallbackStatic, this);
630 }
631
632 // static
633 gboolean MetricsDaemon::MeminfoCallbackStatic(void* handle) {
634 return (static_cast<MetricsDaemon*>(handle))->MeminfoCallback();
635 }
636
637 gboolean MetricsDaemon::MeminfoCallback() {
638 char meminfo[4096];
639 int nchars;
640 const char* meminfo_path = "/proc/meminfo";
641 int file = HANDLE_EINTR(open(meminfo_path, O_RDONLY));
642 if (file < 0) {
643 PLOG(WARNING) << "cannot open " << meminfo_path;
644 return false;
645 }
646 nchars = HANDLE_EINTR(read(file, meminfo, sizeof(meminfo)));
647 HANDLE_EINTR(close(file));
648
649 if (nchars < 0) {
650 LOG(WARNING) << "cannot read from " << meminfo_path;
651 return false;
652 }
653 if (nchars == sizeof(meminfo)) {
654 LOG(WARNING) << meminfo_path << " was truncated";
655 nchars -= 1;
656 }
657 meminfo[nchars] = '\0';
658 return ProcessMeminfo(meminfo);
659 }
660
661 gboolean MetricsDaemon::ProcessMeminfo(const char* meminfo) {
662 /* This array has one string for every item of /proc/meminfo that we want to
663 * report to UMA. They must be listed in the same order in which
664 * /proc/meminfo prints them.
665 */
666 struct {
667 const char* name;
668 const char* match;
669 } fields[] = {
670 { "MemTotal", "MemTotal" }, // SPECIAL CASE: total system memory
671 { "MemFree", "MemFree" },
672 { "Buffers", "Buffers" },
673 { "Cached", "Cached" },
674 // { "SwapCached", "SwapCached" },
675 { "Active", "Active" },
676 { "Inactive", "Inactive" },
677 { "ActiveAnon", "Active(anon)" },
678 { "InactiveAnon", "Inactive(anon)" },
679 { "ActiveFile" , "Active(file)" },
680 { "InactiveFile", "Inactive(file)" },
681 // { "Unevictable", "Unevictable" },
Mandeep Singh Baines 2011/04/06 22:35:26 Want this. Not percentage.
682 // { "Mlocked", "Mlocked" },
683 // { "SwapTotal", "SwapTotal" },
684 // { "SwapFree", "SwapFree" },
685 // { "Dirty", "Dirty" },
686 // { "Writeback", "Writeback" },
687 { "AnonPages", "AnonPages" },
688 { "Mapped", "Mapped" },
689 // { "Shmem", "Shmem" },
Mandeep Singh Baines 2011/04/06 22:35:26 Want this. Not percentage (luigi's comment)
690 // { "Slab", "Slab" },
Mandeep Singh Baines 2011/04/06 22:35:26 Want this. Not percentage (luigi's comment)
691 // { "SReclaimable", "SReclaimable" },
692 // { "SUnreclaim", "SUnreclaim" },
693 };
694 const int nfields = sizeof(fields) / sizeof(fields[0]);
695 int total_memory = 0;
696
697 /* Scan meminfo output and collect field values. Each field name has to
698 * match a meminfo entry (case insensitive) after removing non-alpha
699 * characters from the entry. */
700 int i = 0;
701 const char* p = meminfo;
702
703 for (;;) {
704 if (i == nfields) {
705 /* all fields are matched */
706 return true;
707 }
708 if (*p == '\0') {
709 /* end of input reached while scanning */
710 LOG(WARNING) << "cannot find field " << fields[i].match <<
711 " and following";
712 return false;
713 }
714 if (strncmp(fields[i].match, p, strlen(fields[i].match)) == 0) {
715 /* name matches: parse value and report */
716 int meminfo_value;
717 char metrics_name[128];
718 char* rest;
719 p += strlen(fields[i].match);
720 while (!isdigit(*p)) {
721 if (*p == '\0') {
722 LOG(WARNING) << "error parsing meminfo value";
723 return false;
724 }
725 p++;
726 }
727 meminfo_value = (int) strtol(p, &rest, 10);
728 if (p < rest) {
729 p = rest;
730 } else {
731 LOG(WARNING) << "missing meminfo value";
732 return false;
733 }
734 if (i == 0) {
735 /* special case: total memory */
736 total_memory = meminfo_value;
737 } else {
738 /* report value as percent of total memory */
739 snprintf(metrics_name, sizeof(metrics_name),
740 "Platform.Meminfo%s", fields[i].name);
741 SendLinearMetric(metrics_name, meminfo_value * 100 / total_memory,
742 100, 101);
743 }
744 /* start looking for next field */
745 i++;
746 }
747 /* move to next input line */
748 while (*p != '\n') {
749 if (*p == '\0') {
750 LOG(WARNING) << "error parsing meminfo line";
751 return false;
752 }
753 p++;
754 }
755 p++;
756 }
757 }
758
620 // static 759 // static
621 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) { 760 void MetricsDaemon::ReportDailyUse(void* handle, int tag, int count) {
622 if (count <= 0) 761 if (count <= 0)
623 return; 762 return;
624 763
625 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); 764 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle);
626 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; 765 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute;
627 daemon->SendMetric(kMetricDailyUseTimeName, minutes, 766 daemon->SendMetric(kMetricDailyUseTimeName, minutes,
628 kMetricDailyUseTimeMin, 767 kMetricDailyUseTimeMin,
629 kMetricDailyUseTimeMax, 768 kMetricDailyUseTimeMax,
630 kMetricDailyUseTimeBuckets); 769 kMetricDailyUseTimeBuckets);
631 } 770 }
632 771
633 void MetricsDaemon::SendMetric(const string& name, int sample, 772 void MetricsDaemon::SendMetric(const string& name, int sample,
634 int min, int max, int nbuckets) { 773 int min, int max, int nbuckets) {
635 DLOG(INFO) << "received metric: " << name << " " << sample << " " 774 DLOG(INFO) << "received metric: " << name << " " << sample << " "
636 << min << " " << max << " " << nbuckets; 775 << min << " " << max << " " << nbuckets;
637 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); 776 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets);
638 } 777 }
778
779 void MetricsDaemon::SendLinearMetric(const string& name, int sample,
780 int max, int nbuckets) {
781 DLOG(INFO) << "received linear metric: " << name << " " << sample << " "
782 << max << " " << nbuckets;
783 /* TODO(semenzato): add a proper linear histogram to the Chrome external
784 * metrics API. */
785 LOG_IF(FATAL, nbuckets != max + 1) << "unsupported histogram scale";
786 metrics_lib_->SendEnumToUMA(name, sample, max);
787 }
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