metricsd: Collect generic stats about the system.

Collect memory usage and disk IO statistics periodically.

BUG: 22953719

Change-Id: I2e35d4800ddc684284969e6a58a6f50497086b69
This commit is contained in:
Bertrand SIMONNET 2015-08-25 14:16:02 -07:00
parent 03bbd64aa9
commit 90b02cd46d
5 changed files with 100 additions and 6 deletions

View file

@ -133,7 +133,9 @@ LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
libchromeos-http \
libchromeos-dbus \
libcutils \
libdbus
libdbus \
librootdev
LOCAL_SRC_FILES := $(metrics_daemon_sources)
LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
include $(BUILD_EXECUTABLE)

View file

@ -112,6 +112,7 @@ const char kMetricsProcStatFileName[] = "/proc/stat";
const char kVmStatFileName[] = "/proc/vmstat";
const char kMeminfoFileName[] = "/proc/meminfo";
const int kMetricsProcStatFirstLineItemsCount = 11;
const int kDiskMetricsStatItemCount = 11;
// Thermal CPU throttling.
@ -217,6 +218,7 @@ void MetricsDaemon::Init(bool testing,
bool uploader_active,
bool dbus_enabled,
MetricsLibraryInterface* metrics_lib,
const string& diskstats_path,
const string& scaling_max_freq_path,
const string& cpuinfo_max_freq_path,
const base::TimeDelta& upload_interval,
@ -275,8 +277,13 @@ void MetricsDaemon::Init(bool testing,
weekly_cycle_.reset(new PersistentInteger("weekly.cycle"));
version_cycle_.reset(new PersistentInteger("version.cycle"));
diskstats_path_ = diskstats_path;
scaling_max_freq_path_ = scaling_max_freq_path;
cpuinfo_max_freq_path_ = cpuinfo_max_freq_path;
// If testing, initialize Stats Reporter without connecting DBus
if (testing_)
StatsReporterInit();
}
int MetricsDaemon::OnInit() {
@ -285,6 +292,13 @@ int MetricsDaemon::OnInit() {
if (return_code != EX_OK)
return return_code;
StatsReporterInit();
// Start collecting meminfo stats.
ScheduleMeminfoCallback(kMetricMeminfoInterval);
memuse_final_time_ = GetActiveTime() + kMemuseIntervals[0];
ScheduleMemuseCallback(kMemuseIntervals[0]);
if (testing_)
return EX_OK;
@ -315,6 +329,11 @@ int MetricsDaemon::OnInit() {
}
}
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&MetricsDaemon::HandleUpdateStatsTimeout,
base::Unretained(this)),
base::TimeDelta::FromMilliseconds(kUpdateStatsIntervalMs));
if (uploader_active_) {
upload_service_.reset(
new UploadService(new SystemProfileCache(), metrics_lib_, server_));
@ -496,6 +515,40 @@ void MetricsDaemon::ScheduleStatsCallback(int wait) {
base::TimeDelta::FromSeconds(wait));
}
bool MetricsDaemon::DiskStatsReadStats(uint64_t* read_sectors,
uint64_t* write_sectors) {
CHECK(read_sectors);
CHECK(write_sectors);
std::string line;
if (diskstats_path_.empty()) {
return false;
}
if (!base::ReadFileToString(base::FilePath(diskstats_path_), &line)) {
PLOG(WARNING) << "Could not read disk stats from " << diskstats_path_;
return false;
}
std::vector<std::string> parts = base::SplitString(
line, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (parts.size() != kDiskMetricsStatItemCount) {
LOG(ERROR) << "Could not parse disk stat correctly. Expected "
<< kDiskMetricsStatItemCount << " elements but got "
<< parts.size();
return false;
}
if (!base::StringToUint64(parts[2], read_sectors)) {
LOG(ERROR) << "Couldn't convert read sectors " << parts[2] << " to uint64";
return false;
}
if (!base::StringToUint64(parts[6], write_sectors)) {
LOG(ERROR) << "Couldn't convert write sectors " << parts[6] << " to uint64";
return false;
}
return true;
}
bool MetricsDaemon::VmStatsParseStats(const char* stats,
struct VmstatRecord* record) {
CHECK(stats);
@ -715,10 +768,7 @@ void MetricsDaemon::MeminfoCallback(base::TimeDelta wait) {
}
// Make both calls even if the first one fails.
bool success = ProcessMeminfo(meminfo_raw);
bool reschedule =
ReportZram(base::FilePath(FILE_PATH_LITERAL("/sys/block/zram0"))) &&
success;
if (reschedule) {
if (ProcessMeminfo(meminfo_raw)) {
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&MetricsDaemon::MeminfoCallback, base::Unretained(this),
wait),

View file

@ -45,6 +45,7 @@ class MetricsDaemon : public chromeos::DBusDaemon {
bool uploader_active,
bool dbus_enabled,
MetricsLibraryInterface* metrics_lib,
const std::string& diskstats_path,
const std::string& cpuinfo_max_freq_path,
const std::string& scaling_max_freq_path,
const base::TimeDelta& upload_interval,
@ -78,6 +79,7 @@ class MetricsDaemon : public chromeos::DBusDaemon {
FRIEND_TEST(MetricsDaemonTest, GetHistogramPath);
FRIEND_TEST(MetricsDaemonTest, IsNewEpoch);
FRIEND_TEST(MetricsDaemonTest, MessageFilter);
FRIEND_TEST(MetricsDaemonTest, ParseDiskStats);
FRIEND_TEST(MetricsDaemonTest, ParseVmStats);
FRIEND_TEST(MetricsDaemonTest, ProcessKernelCrash);
FRIEND_TEST(MetricsDaemonTest, ProcessMeminfo);
@ -86,7 +88,6 @@ class MetricsDaemon : public chromeos::DBusDaemon {
FRIEND_TEST(MetricsDaemonTest, ProcessUserCrash);
FRIEND_TEST(MetricsDaemonTest, ReportCrashesDailyFrequency);
FRIEND_TEST(MetricsDaemonTest, ReadFreqToInt);
FRIEND_TEST(MetricsDaemonTest, ReportDiskStats);
FRIEND_TEST(MetricsDaemonTest, ReportKernelCrashInterval);
FRIEND_TEST(MetricsDaemonTest, ReportUncleanShutdownInterval);
FRIEND_TEST(MetricsDaemonTest, ReportUserCrashInterval);
@ -324,6 +325,7 @@ class MetricsDaemon : public chromeos::DBusDaemon {
scoped_ptr<PersistentInteger> unclean_shutdowns_daily_count_;
scoped_ptr<PersistentInteger> unclean_shutdowns_weekly_count_;
std::string diskstats_path_;
std::string scaling_max_freq_path_;
std::string cpuinfo_max_freq_path_;

View file

@ -20,6 +20,7 @@
#include <base/strings/string_util.h>
#include <chromeos/flag_helper.h>
#include <chromeos/syslog_logging.h>
#include <rootdev.h>
#include "constants.h"
#include "metrics_daemon.h"
@ -29,6 +30,28 @@ const char kScalingMaxFreqPath[] =
const char kCpuinfoMaxFreqPath[] =
"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
// Returns the path to the disk stats in the sysfs. Returns the null string if
// it cannot find the disk stats file.
static
const std::string MetricsMainDiskStatsPath() {
char dev_path_cstr[PATH_MAX];
std::string dev_prefix = "/dev/block/";
std::string dev_path;
int ret = rootdev(dev_path_cstr, sizeof(dev_path_cstr), true, true);
if (ret != 0) {
LOG(WARNING) << "error " << ret << " determining root device";
return "";
}
dev_path = dev_path_cstr;
// Check that rootdev begins with "/dev/block/".
if (!base::StartsWithASCII(dev_path, dev_prefix, false)) {
LOG(WARNING) << "unexpected root device " << dev_path;
return "";
}
return "/sys/class/block/" + dev_path.substr(dev_prefix.length()) + "/stat";
}
int main(int argc, char** argv) {
DEFINE_bool(daemon, true, "run as daemon (use -nodaemon for debugging)");
@ -75,6 +98,7 @@ int main(int argc, char** argv) {
FLAGS_uploader | FLAGS_uploader_test,
FLAGS_withdbus,
&metrics_lib,
MetricsMainDiskStatsPath(),
kScalingMaxFreqPath,
kCpuinfoMaxFreqPath,
base::TimeDelta::FromSeconds(FLAGS_upload_interval_secs),

View file

@ -82,6 +82,7 @@ class MetricsDaemonTest : public testing::Test {
false,
true,
&metrics_lib_,
disk_stats_path_.value(),
scaling_max_freq_path_.value(),
cpu_max_freq_path_.value(),
base::TimeDelta::FromMinutes(30),
@ -198,6 +199,21 @@ TEST_F(MetricsDaemonTest, SendSample) {
/* min */ 1, /* max */ 100, /* buckets */ 50);
}
TEST_F(MetricsDaemonTest, ParseDiskStats) {
uint64_t read_sectors_now, write_sectors_now;
CreateFakeDiskStatsFile(kFakeDiskStats0);
ASSERT_TRUE(daemon_.DiskStatsReadStats(&read_sectors_now,
&write_sectors_now));
EXPECT_EQ(read_sectors_now, kFakeReadSectors[0]);
EXPECT_EQ(write_sectors_now, kFakeWriteSectors[0]);
CreateFakeDiskStatsFile(kFakeDiskStats1);
ASSERT_TRUE(daemon_.DiskStatsReadStats(&read_sectors_now,
&write_sectors_now));
EXPECT_EQ(read_sectors_now, kFakeReadSectors[1]);
EXPECT_EQ(write_sectors_now, kFakeWriteSectors[1]);
}
TEST_F(MetricsDaemonTest, ProcessMeminfo) {
string meminfo =
"MemTotal: 2000000 kB\nMemFree: 500000 kB\n"