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:
parent
03bbd64aa9
commit
90b02cd46d
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue