blob: 8965b27ed65dd2dc939acc07ef2c041118f50222 [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <inttypes.h>
#include <utime.h>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <base/at_exit.h>
#include <base/files/file_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#include <chromeos/dbus/service_constants.h>
#include <gtest/gtest.h>
#include "metrics/metrics_daemon.h"
#include "metrics/metrics_library_mock.h"
#include "metrics/persistent_integer_mock.h"
#include "metrics/vmlog_writer.h"
using base::FilePath;
using base::StringPrintf;
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
using std::string;
using std::vector;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::AtLeast;
using ::testing::Return;
using ::testing::StrictMock;
namespace chromeos_metrics {
TEST(VmlogWriterTest, ParseVmStats) {
const char kVmStats[] =
"pswpin 1345\n"
"pswpout 8896\n"
"foo 100\n"
"bar 200\n"
"pgmajfault 42\n"
"pgmajfault_a 3838\n"
"pgmajfault_f 66\n"
"etcetc 300\n";
std::istringstream input_stream(kVmStats);
struct VmstatRecord stats;
EXPECT_TRUE(VmStatsParseStats(&input_stream, &stats));
EXPECT_EQ(stats.page_faults_, 42);
EXPECT_EQ(stats.anon_page_faults_, 3838);
EXPECT_EQ(stats.file_page_faults_, 66);
EXPECT_EQ(stats.swap_in_, 1345);
EXPECT_EQ(stats.swap_out_, 8896);
}
TEST(VmlogWriterTest, ParseVmStatsOptionalMissing) {
const char kVmStats[] =
"pswpin 1345\n"
"pswpout 8896\n"
"foo 100\n"
"bar 200\n"
"pgmajfault 42\n"
// pgmajfault_a and pgmajfault_f are optional.
// The default value when missing is 0.
// "pgmajfault_a 3838\n"
// "pgmajfault_f 66\n"
"etcetc 300\n";
std::istringstream input_stream(kVmStats);
struct VmstatRecord stats;
EXPECT_TRUE(VmStatsParseStats(&input_stream, &stats));
EXPECT_EQ(stats.anon_page_faults_, 0);
EXPECT_EQ(stats.file_page_faults_, 0);
}
// For mocking sysfs info.
class TestGpuInfo : public GpuInfo {
public:
TestGpuInfo(std::unique_ptr<std::istream> gpu_info_stream,
GpuInfo::GpuType gpu_type)
: GpuInfo(std::move(gpu_info_stream), gpu_type) {}
};
TEST(VmlogWriterTest, ParseAmdgpuFrequency) {
const char kAmdgpuSclkFrequency[] =
"0: 200Mhz\n"
"1: 300Mhz\n"
"2: 400Mhz *\n"
"3: 480Mhz\n"
"4: 553Mhz\n"
"5: 626Mhz\n"
"6: 685Mhz\n"
"7: 720Mhz\n";
auto input_stream =
std::make_unique<std::istringstream>(kAmdgpuSclkFrequency);
std::stringstream selected_frequency;
TestGpuInfo gpu_info(std::move(input_stream), GpuInfo::GpuType::kAmd);
EXPECT_TRUE(gpu_info.GetCurrentFrequency(selected_frequency));
EXPECT_EQ(selected_frequency.str(), " 400");
}
TEST(VmlogWriterTest, ParseAmdgpuFrequencyMissing) {
const char kAmdgpuSclkFrequency[] =
"0: 200Mhz\n"
"1: 300Mhz\n"
"2: 400Mhz\n"
"3: 480Mhz\n"
"4: 553Mhz\n"
"5: 626Mhz\n"
"6: 685Mhz\n"
"7: 720Mhz\n";
auto input_stream =
std::make_unique<std::istringstream>(kAmdgpuSclkFrequency);
std::stringstream selected_frequency;
TestGpuInfo gpu_info(std::move(input_stream), GpuInfo::GpuType::kAmd);
EXPECT_FALSE(gpu_info.GetCurrentFrequency(selected_frequency));
EXPECT_EQ(selected_frequency.str(), "");
}
TEST(VmlogWriterTest, ParseIntelgpuFrequency) {
const char kIntelI915FrequencyInfo[] = R"(
PM IER=0x00000070 IMR=0xffffff8f ISR=0x00000000 IIR=0x00000000, MASK=0x00003fde
GT_PERF_STATUS: 0x00000000
Current freq: 100 MHz
Actual freq: 100 MHz
Idle freq: 100 MHz
Min freq: 100 MHz
)";
auto input_stream =
std::make_unique<std::istringstream>(kIntelI915FrequencyInfo);
std::stringstream selected_frequency;
TestGpuInfo gpu_info(std::move(input_stream), GpuInfo::GpuType::kIntel);
EXPECT_TRUE(gpu_info.GetCurrentFrequency(selected_frequency));
EXPECT_EQ(selected_frequency.str(), " 100");
}
TEST(VmlogWriterTest, ParseIntelgpuFrequencyMissing) {
const char kIntelI915FrequencyInfo[] = R"()";
auto input_stream =
std::make_unique<std::istringstream>(kIntelI915FrequencyInfo);
std::stringstream selected_frequency;
TestGpuInfo gpu_info(std::move(input_stream), GpuInfo::GpuType::kIntel);
EXPECT_FALSE(gpu_info.GetCurrentFrequency(selected_frequency));
EXPECT_EQ(selected_frequency.str(), "");
}
TEST(VmlogWriterTest, ParseCpuTime) {
const char kProcStat[] =
"cpu 9440559 4101628 4207468 764635735 5162045 0 132368 0 0 0";
std::istringstream input_stream(kProcStat);
struct CpuTimeRecord record;
EXPECT_TRUE(ParseCpuTime(&input_stream, &record));
EXPECT_EQ(record.non_idle_time_, 17882023);
EXPECT_EQ(record.total_time_, 787679803);
}
TEST(VmlogWriterTest, VmlogRotation) {
base::FilePath temp_directory;
EXPECT_TRUE(base::CreateNewTempDirectory("", &temp_directory));
base::FilePath log_path = temp_directory.Append("log");
base::FilePath rotated_path = temp_directory.Append("rotated");
base::FilePath latest_symlink_path = temp_directory.Append("vmlog.1.LATEST");
base::FilePath previous_symlink_path =
temp_directory.Append("vmlog.1.PREVIOUS");
// VmlogFile expects to create its output files.
base::DeleteFile(log_path);
base::DeleteFile(rotated_path);
std::string header_string("header\n");
VmlogFile l(log_path, rotated_path, 500, header_string);
EXPECT_FALSE(base::PathExists(latest_symlink_path));
std::string x_400(400, 'x');
EXPECT_TRUE(l.Write(x_400));
std::string buf;
EXPECT_TRUE(base::ReadFileToString(log_path, &buf));
EXPECT_EQ(header_string.size() + x_400.size(), buf.size());
EXPECT_FALSE(base::ReadFileToString(rotated_path, &buf));
std::string y_200(200, 'y');
EXPECT_TRUE(l.Write(y_200));
EXPECT_TRUE(base::ReadFileToString(log_path, &buf));
EXPECT_EQ(header_string.size() + y_200.size(), buf.size());
EXPECT_TRUE(base::ReadFileToString(rotated_path, &buf));
EXPECT_EQ(header_string.size() + x_400.size(), buf.size());
EXPECT_TRUE(base::PathExists(latest_symlink_path));
base::FilePath symlink_target;
EXPECT_TRUE(base::ReadSymbolicLink(latest_symlink_path, &symlink_target));
EXPECT_EQ(rotated_path.value(), symlink_target.value());
// Test log rotation for vmlog.1 files when a writer is created.
// We use a zero log_interval to prevent writes from happening.
EXPECT_TRUE(base::PathExists(latest_symlink_path));
EXPECT_FALSE(base::PathExists(previous_symlink_path));
VmlogWriter writer(temp_directory, base::TimeDelta());
EXPECT_FALSE(base::PathExists(latest_symlink_path));
EXPECT_TRUE(base::PathExists(previous_symlink_path));
EXPECT_TRUE(base::ReadSymbolicLink(previous_symlink_path, &symlink_target));
EXPECT_EQ(rotated_path.value(), symlink_target.value());
}
TEST(VmlogWriterTest, WriteCallbackSuccess) {
base::FilePath tempdir;
EXPECT_TRUE(base::CreateNewTempDirectory("", &tempdir));
// Create a VmlogWriter with a zero log_interval to avoid scheduling write
// callbacks.
VmlogWriter writer(tempdir, base::TimeDelta());
writer.WriteCallback();
EXPECT_TRUE(base::PathExists(writer.vmlog_->live_path_));
EXPECT_FALSE(base::PathExists(writer.vmlog_->rotated_path_));
}
TEST(VmlogWriterTest, GetOnlineCpus) {
const char kProcCpuInfo[] =
R"(processor : 0
vendor_id : GenuineIntel
model name : Intel(R) Core(TM) i5-7Y57 CPU @ 1.20GHz
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass
processor : 2
vendor_id : GenuineIntel
model name : Intel(R) Core(TM) i5-7Y57 CPU @ 1.20GHz
bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass)";
std::istringstream input_stream(kProcCpuInfo);
auto cpus = GetOnlineCpus(input_stream);
EXPECT_TRUE(cpus.has_value());
std::vector<int> expected_cpus = {0, 2};
EXPECT_EQ(*cpus, expected_cpus);
}
} // namespace chromeos_metrics