lin
2025-08-01 633231e833e21d5b8b1c00cb15aedb62b3b78e8f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// 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