1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/traced/probes/system_info/system_info_data_source.h"
18 #include "src/traced/probes/common/cpu_freq_info_for_testing.h"
19 #include "src/traced/probes/system_info/cpu_info_features_allowlist.h"
20 #include "src/tracing/core/trace_writer_for_testing.h"
21 #include "test/gtest_and_gmock.h"
22
23 #include "protos/perfetto/trace/system_info/cpu_info.gen.h"
24
25 using ::testing::AnyOf;
26 using ::testing::ElementsAre;
27 using ::testing::Return;
28
29 namespace perfetto {
30 namespace {
31
32 static const uint32_t CPU_COUNT = 8;
33
34 const char kMockCpuInfoAndroid[] = R"(
35 Processor : AArch64 Processor rev 13 (aarch64)
36 processor : 0
37 BogoMIPS : 38.00
38 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
39 CPU implementer : 0x51
40 CPU architecture: 8
41 CPU variant : 0x7
42 CPU part : 0x803
43 CPU revision : 12
44
45 processor : 1
46 BogoMIPS : 38.00
47 Features : fp mte mte3
48 CPU implementer : 0x51
49 CPU architecture: 8
50 CPU variant : 0x7
51 CPU part : 0x803
52 CPU revision : 12
53
54 processor : 2
55 BogoMIPS : 38.00
56 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
57 CPU implementer : 0x51
58 CPU architecture: 8
59 CPU variant : 0x7
60 CPU part : 0x803
61 CPU revision : 12
62
63 processor : 3
64 BogoMIPS : 38.00
65 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
66 CPU implementer : 0x51
67 CPU architecture: 8
68 CPU variant : 0x7
69 CPU part : 0x803
70 CPU revision : 12
71
72 processor : 4
73 BogoMIPS : 38.00
74 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
75 CPU implementer : 0x51
76 CPU architecture: 8
77 CPU variant : 0x7
78 CPU part : 0x803
79 CPU revision : 12
80
81 processor : 5
82 BogoMIPS : 38.00
83 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
84 CPU implementer : 0x51
85 CPU architecture: 8
86 CPU variant : 0x7
87 CPU part : 0x803
88 CPU revision : 12
89
90 processor : 6
91 BogoMIPS : 38.00
92 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
93 CPU implementer : 0x51
94 CPU architecture: 8
95 CPU variant : 0x6
96 CPU part : 0x802
97 CPU revision : 13
98
99 processor : 7
100 BogoMIPS : 38.00
101 Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
102 CPU implementer : 0x51
103 CPU architecture: 8
104 CPU variant : 0x6
105 CPU part : 0x802
106 CPU revision : 13
107
108 Hardware : Qualcomm Technologies, Inc SDM670
109
110 )";
111
112 const char* kMockCpuCapacityInfoAndroid[8] = {
113 "200\n", "200\n", "200\n", "600\n", "600\n", "600\n", "1024\n", "1024\n"};
114
115 class TestSystemInfoDataSource : public SystemInfoDataSource {
116 public:
TestSystemInfoDataSource(std::unique_ptr<TraceWriter> writer,std::unique_ptr<CpuFreqInfo> cpu_freq_info)117 TestSystemInfoDataSource(std::unique_ptr<TraceWriter> writer,
118 std::unique_ptr<CpuFreqInfo> cpu_freq_info)
119 : SystemInfoDataSource(
120 /* session_id */ 0,
121 std::move(writer),
122 std::move(cpu_freq_info)) {}
123
124 MOCK_METHOD(std::string, ReadFile, (std::string), (override));
125 };
126
127 class SystemInfoDataSourceTest : public ::testing::Test {
128 protected:
GetSystemInfoDataSource()129 std::unique_ptr<TestSystemInfoDataSource> GetSystemInfoDataSource() {
130 auto writer =
131 std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
132 writer_raw_ = writer.get();
133 auto instance =
134 std::unique_ptr<TestSystemInfoDataSource>(new TestSystemInfoDataSource(
135 std::move(writer), cpu_freq_info_for_testing.GetInstance()));
136 return instance;
137 }
138
139 TraceWriterForTesting* writer_raw_ = nullptr;
140 CpuFreqInfoForTesting cpu_freq_info_for_testing;
141 };
142
TEST_F(SystemInfoDataSourceTest,CpuInfoAndroid)143 TEST_F(SystemInfoDataSourceTest, CpuInfoAndroid) {
144 auto data_source = GetSystemInfoDataSource();
145 EXPECT_CALL(*data_source, ReadFile("/proc/cpuinfo"))
146 .WillOnce(Return(kMockCpuInfoAndroid));
147
148 for (uint32_t cpu_index = 0; cpu_index < CPU_COUNT; cpu_index++) {
149 EXPECT_CALL(*data_source,
150 ReadFile("/sys/devices/system/cpu/cpu" +
151 std::to_string(cpu_index) + "/cpu_capacity"))
152 .WillOnce(Return(kMockCpuCapacityInfoAndroid[cpu_index]));
153 }
154
155 data_source->Start();
156
157 protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
158 ASSERT_TRUE(packet.has_cpu_info());
159 auto cpu_info = packet.cpu_info();
160 ASSERT_EQ(cpu_info.cpus_size(), 8);
161 auto cpu = cpu_info.cpus()[0];
162 ASSERT_EQ(cpu.processor(), "AArch64 Processor rev 13 (aarch64)");
163 ASSERT_THAT(cpu.frequencies(),
164 ElementsAre(300000, 576000, 748800, 998400, 1209600, 1324800,
165 1516800, 1612800, 1708800));
166 ASSERT_TRUE(cpu.has_arm_identifier());
167 auto id = cpu.arm_identifier();
168 ASSERT_EQ(id.implementer(), 0x51U);
169 ASSERT_EQ(id.architecture(), 8U);
170 ASSERT_EQ(id.variant(), 0x7U);
171 ASSERT_EQ(id.part(), 0x803U);
172 ASSERT_EQ(id.revision(), 12U);
173
174 ASSERT_EQ(cpu.capacity(), static_cast<uint32_t>(200));
175 cpu = cpu_info.cpus()[1];
176 ASSERT_EQ(cpu.processor(), "AArch64 Processor rev 13 (aarch64)");
177 ASSERT_THAT(cpu.frequencies(),
178 ElementsAre(300000, 652800, 825600, 979200, 1132800, 1363200,
179 1536000, 1747200, 1843200, 1996800, 2803200));
180 ASSERT_TRUE(cpu.has_arm_identifier());
181 id = cpu.arm_identifier();
182 ASSERT_EQ(id.implementer(), 0x51U);
183 ASSERT_EQ(id.architecture(), 8U);
184 ASSERT_EQ(id.variant(), 0x7U);
185 ASSERT_EQ(id.part(), 0x803U);
186 ASSERT_EQ(id.revision(), 12U);
187 ASSERT_TRUE(cpu.features() & (1u << 0));
188 ASSERT_STREQ(kCpuInfoFeatures[0], "mte");
189 ASSERT_TRUE(cpu.features() & (1u << 1));
190 ASSERT_STREQ(kCpuInfoFeatures[1], "mte3");
191
192 cpu = cpu_info.cpus()[7];
193 ASSERT_EQ(cpu.capacity(), static_cast<uint32_t>(1024));
194 ASSERT_TRUE(cpu.has_arm_identifier());
195 id = cpu.arm_identifier();
196 ASSERT_EQ(id.implementer(), 0x51U);
197 ASSERT_EQ(id.architecture(), 8U);
198 ASSERT_EQ(id.variant(), 0x6U);
199 ASSERT_EQ(id.part(), 0x802U);
200 ASSERT_EQ(id.revision(), 13U);
201 ASSERT_EQ(cpu.features(), 0U);
202 }
203
204 } // namespace
205 } // namespace perfetto
206