1 /*
2 * Copyright 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 #undef LOG_TAG
18 #define LOG_TAG "gpuservice_unittest"
19
20 #include <android-base/stringprintf.h>
21 #include <bpf/BpfMap.h>
22 #include <gmock/gmock.h>
23 #include <gpumem/GpuMem.h>
24 #include <gtest/gtest.h>
25 #include <inttypes.h>
26 #include <utils/String16.h>
27 #include <utils/Vector.h>
28
29 #include "TestableGpuMem.h"
30
31 namespace android {
32 namespace {
33
34 using base::StringPrintf;
35 using testing::HasSubstr;
36
37 constexpr uint32_t TEST_MAP_SIZE = 10;
38 constexpr uint64_t TEST_GLOBAL_KEY = 0;
39 constexpr uint64_t TEST_GLOBAL_VAL = 123;
40 constexpr uint64_t TEST_PROC_KEY_1 = 1;
41 constexpr uint64_t TEST_PROC_VAL_1 = 234;
42 constexpr uint64_t TEST_PROC_KEY_2 = 4294967298; // (1 << 32) + 2
43 constexpr uint64_t TEST_PROC_VAL_2 = 345;
44 constexpr uint32_t TEST_KEY_MASK = 0x1 | 0x2 | 0x4;
45 constexpr uint32_t TEST_KEY_COUNT = 3;
46
47 class GpuMemTest : public testing::Test {
48 public:
GpuMemTest()49 GpuMemTest() {
50 const ::testing::TestInfo* const test_info =
51 ::testing::UnitTest::GetInstance()->current_test_info();
52 ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
53 }
54
~GpuMemTest()55 ~GpuMemTest() {
56 const ::testing::TestInfo* const test_info =
57 ::testing::UnitTest::GetInstance()->current_test_info();
58 ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
59 }
60
SetUp()61 void SetUp() override {
62 bpf::setrlimitForTest();
63
64 mGpuMem = std::make_unique<GpuMem>();
65 mTestableGpuMem = TestableGpuMem(mGpuMem.get());
66 mTestableGpuMem.setInitialized();
67 errno = 0;
68 mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
69 BPF_F_NO_PREALLOC);
70
71 EXPECT_EQ(0, errno);
72 EXPECT_LE(0, mTestMap.getMap().get());
73 EXPECT_TRUE(mTestMap.isValid());
74 }
75
dumpsys()76 std::string dumpsys() {
77 std::string result;
78 Vector<String16> args;
79 mGpuMem->dump(args, &result);
80 return result;
81 }
82
83 std::unique_ptr<GpuMem> mGpuMem;
84 TestableGpuMem mTestableGpuMem;
85 bpf::BpfMap<uint64_t, uint64_t> mTestMap;
86 };
87
TEST_F(GpuMemTest,validGpuMemTotalBpfPaths)88 TEST_F(GpuMemTest, validGpuMemTotalBpfPaths) {
89 EXPECT_EQ(mTestableGpuMem.getGpuMemTraceGroup(), "gpu_mem");
90 EXPECT_EQ(mTestableGpuMem.getGpuMemTotalTracepoint(), "gpu_mem_total");
91 EXPECT_EQ(mTestableGpuMem.getGpuMemTotalProgPath(),
92 "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total");
93 EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map");
94 }
95
TEST_F(GpuMemTest,bpfInitializationFailed)96 TEST_F(GpuMemTest, bpfInitializationFailed) {
97 EXPECT_EQ(dumpsys(), "Failed to initialize GPU memory eBPF\n");
98 }
99
TEST_F(GpuMemTest,gpuMemTotalMapEmpty)100 TEST_F(GpuMemTest, gpuMemTotalMapEmpty) {
101 mTestableGpuMem.setGpuMemTotalMap(mTestMap);
102
103 EXPECT_EQ(dumpsys(), "GPU memory total usage map is empty\n");
104 }
105
TEST_F(GpuMemTest,globalMemTotal)106 TEST_F(GpuMemTest, globalMemTotal) {
107 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
108 mTestableGpuMem.setGpuMemTotalMap(mTestMap);
109
110 EXPECT_THAT(dumpsys(), HasSubstr(StringPrintf("Global total: %" PRIu64 "\n", TEST_GLOBAL_VAL)));
111 }
112
TEST_F(GpuMemTest,missingGlobalMemTotal)113 TEST_F(GpuMemTest, missingGlobalMemTotal) {
114 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
115 mTestableGpuMem.setGpuMemTotalMap(mTestMap);
116
117 EXPECT_THAT(dumpsys(), HasSubstr("Global total: N/A"));
118 }
119
TEST_F(GpuMemTest,procMemTotal)120 TEST_F(GpuMemTest, procMemTotal) {
121 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
122 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
123 mTestableGpuMem.setGpuMemTotalMap(mTestMap);
124
125 EXPECT_THAT(dumpsys(),
126 HasSubstr(StringPrintf("Memory snapshot for GPU %u:\n",
127 (uint32_t)(TEST_PROC_KEY_1 >> 32))));
128 EXPECT_THAT(dumpsys(),
129 HasSubstr(StringPrintf("Proc %u total: %" PRIu64 "\n", (uint32_t)TEST_PROC_KEY_1,
130 TEST_PROC_VAL_1)));
131 EXPECT_THAT(dumpsys(),
132 HasSubstr(StringPrintf("Memory snapshot for GPU %u:\n",
133 (uint32_t)(TEST_PROC_KEY_2 >> 32))));
134 EXPECT_THAT(dumpsys(),
135 HasSubstr(StringPrintf("Proc %u total: %" PRIu64 "\n", (uint32_t)TEST_PROC_KEY_2,
136 TEST_PROC_VAL_2)));
137 }
138
TEST_F(GpuMemTest,traverseGpuMemTotals)139 TEST_F(GpuMemTest, traverseGpuMemTotals) {
140 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
141 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
142 ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
143 mTestableGpuMem.setGpuMemTotalMap(mTestMap);
144
145 static uint32_t sMask = 0;
146 static uint32_t sCount = 0;
147 mGpuMem->traverseGpuMemTotals([](int64_t, uint32_t gpuId, uint32_t pid, uint64_t size) {
148 const uint64_t key = ((uint64_t)gpuId << 32) | pid;
149 switch (key) {
150 case TEST_GLOBAL_KEY:
151 EXPECT_EQ(size, TEST_GLOBAL_VAL);
152 sMask |= 0x1;
153 break;
154 case TEST_PROC_KEY_1:
155 EXPECT_EQ(size, TEST_PROC_VAL_1);
156 sMask |= 0x2;
157 break;
158 case TEST_PROC_KEY_2:
159 EXPECT_EQ(size, TEST_PROC_VAL_2);
160 sMask |= 0x4;
161 break;
162 }
163 sCount++;
164 });
165
166 EXPECT_EQ(sMask, TEST_KEY_MASK);
167 EXPECT_EQ(sCount, TEST_KEY_COUNT);
168 }
169
170 } // namespace
171 } // namespace android
172