// Copyright 2015 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 <string>
#include "base/logging.h"
#include "compat/string.h"
#include "compat/test.h"
#include "file_utils.h"
#include "perf_stat_parser.h"
#include "scoped_temp_path.h"
namespace quipper {
namespace {
const char kInvalidInput[] =
"PerfDataProto\n"
"Attr: Even Count BuildID\n"
"1.234 1234.5 time seconds\n";
const char kSmallInput[] =
"/uncore/reads/: 711983 1002113142 1002111143\n"
"/uncore/writes/: 140867 1002113864 1002113864\n"
" \n"; // Test parsing an empty line
// From a Peppy running:
// 'perf stat -v -a -e cycles -e L1-dcache-loads -e bus-cycles -e r02c4 --'
// ' sleep 2'
const char kFullInput[] =
"cycles: 19062079 4002390292 4002381587\n"
"L1-dcache-loads: 2081375 4002517554 4002511235\n"
"bus-cycles: 2259169 4002527446 4002523976\n"
"r02c4: 201584 4002518485 4002518485\n"
"\n"
" Performance counter stats for 'system wide':\n"
"\n"
" 19062079 cycles [100.00%]\n"
" 2081375 L1-dcache-loads [100.00%]\n"
" 2259169 bus-cycles [100.00%]\n"
" 201584 r02c4 \n"
"\n"
" 2.001402976 seconds time elapsed\n"
"\n";
} // namespace
TEST(PerfStatParserTest, InvalidStringReturnsFalse) {
PerfStatProto proto;
ASSERT_FALSE(ParsePerfStatOutputToProto(kInvalidInput, &proto));
}
TEST(PerfStatParserTest, ValidInputParsesCorrectly) {
// Test string input
PerfStatProto proto;
ASSERT_TRUE(ParsePerfStatOutputToProto(kSmallInput, &proto));
ASSERT_EQ(proto.line_size(), 2);
const auto& line1 = proto.line(0);
EXPECT_EQ("/uncore/reads/", line1.event_name());
EXPECT_EQ(711983, line1.count());
EXPECT_FALSE(line1.has_time_ms());
const auto& line2 = proto.line(1);
EXPECT_EQ("/uncore/writes/", line2.event_name());
EXPECT_EQ(140867, line2.count());
EXPECT_FALSE(line2.has_time_ms());
// Test file input
ScopedTempFile input;
ASSERT_FALSE(input.path().empty());
ASSERT_TRUE(BufferToFile(input.path(), string(kSmallInput)));
PerfStatProto proto2;
ASSERT_TRUE(ParsePerfStatFileToProto(input.path(), &proto2));
ASSERT_EQ(proto2.line_size(), 2);
const auto& line3 = proto2.line(0);
EXPECT_EQ("/uncore/reads/", line3.event_name());
EXPECT_EQ(711983, line3.count());
EXPECT_FALSE(line3.has_time_ms());
const auto& line4 = proto2.line(1);
EXPECT_EQ("/uncore/writes/", line4.event_name());
EXPECT_EQ(140867, line4.count());
EXPECT_FALSE(line4.has_time_ms());
}
TEST(PerfStatParserTest, ValidFullStringParsesCorrectly) {
PerfStatProto proto;
ASSERT_TRUE(ParsePerfStatOutputToProto(kFullInput, &proto));
ASSERT_EQ(proto.line_size(), 4);
const auto& line1 = proto.line(0);
EXPECT_EQ("cycles", line1.event_name());
EXPECT_EQ(19062079, line1.count());
EXPECT_EQ(2001, line1.time_ms());
const auto& line2 = proto.line(1);
EXPECT_EQ("L1-dcache-loads", line2.event_name());
EXPECT_EQ(2081375, line2.count());
EXPECT_EQ(2001, line2.time_ms());
const auto& line3 = proto.line(2);
EXPECT_EQ("bus-cycles", line3.event_name());
EXPECT_EQ(2259169, line3.count());
EXPECT_EQ(2001, line3.time_ms());
const auto& line4 = proto.line(3);
EXPECT_EQ("r02c4", line4.event_name());
EXPECT_EQ(201584, line4.count());
EXPECT_EQ(2001, line4.time_ms());
}
TEST(PerfStatParserTest, NonexistentFileReturnsFalse) {
PerfStatProto proto;
ASSERT_FALSE(ParsePerfStatFileToProto("/dev/null/nope/nope.txt", &proto));
}
TEST(PerfStatParserTest, ParseTime) {
uint64_t out;
EXPECT_TRUE(SecondsStringToMillisecondsUint64("123.456", &out));
EXPECT_EQ(123456, out);
EXPECT_TRUE(SecondsStringToMillisecondsUint64("2.0014", &out));
EXPECT_EQ(2001, out);
EXPECT_TRUE(SecondsStringToMillisecondsUint64("0.0027", &out));
EXPECT_EQ(3, out);
EXPECT_FALSE(SecondsStringToMillisecondsUint64("-10.0027", &out));
EXPECT_FALSE(SecondsStringToMillisecondsUint64("string", &out));
EXPECT_FALSE(SecondsStringToMillisecondsUint64("string.string", &out));
EXPECT_FALSE(SecondsStringToMillisecondsUint64("23.string", &out));
EXPECT_FALSE(SecondsStringToMillisecondsUint64("string.23456", &out));
EXPECT_FALSE(SecondsStringToMillisecondsUint64("123.234.456", &out));
}
} // namespace quipper