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 <bpf/BpfMap.h>
21 #include <gpumem/GpuMem.h>
22 #include <gtest/gtest.h>
23 #include <perfetto/trace/trace.pb.h>
24 #include <tracing/GpuMemTracer.h>
25 
26 #include "TestableGpuMem.h"
27 
28 namespace android {
29 
30 constexpr uint32_t TEST_MAP_SIZE = 10;
31 constexpr uint64_t TEST_GLOBAL_KEY = 0;
32 constexpr uint32_t TEST_GLOBAL_PID = 0;
33 constexpr uint64_t TEST_GLOBAL_VAL = 123;
34 constexpr uint32_t TEST_GLOBAL_GPU_ID = 0;
35 constexpr uint64_t TEST_PROC_KEY_1 = 1;
36 constexpr uint32_t TEST_PROC_PID_1 = 1;
37 constexpr uint64_t TEST_PROC_VAL_1 = 234;
38 constexpr uint32_t TEST_PROC_1_GPU_ID = 0;
39 constexpr uint64_t TEST_PROC_KEY_2 = 4294967298; // (1 << 32) + 2
40 constexpr uint32_t TEST_PROC_PID_2 = 2;
41 constexpr uint64_t TEST_PROC_VAL_2 = 345;
42 constexpr uint32_t TEST_PROC_2_GPU_ID = 1;
43 
44 class GpuMemTracerTest : public testing::Test {
45 public:
GpuMemTracerTest()46     GpuMemTracerTest() {
47         const ::testing::TestInfo* const test_info =
48                 ::testing::UnitTest::GetInstance()->current_test_info();
49         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
50     }
51 
~GpuMemTracerTest()52     ~GpuMemTracerTest() {
53         const ::testing::TestInfo* const test_info =
54                 ::testing::UnitTest::GetInstance()->current_test_info();
55         ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
56     }
57 
SetUp()58     void SetUp() override {
59         bpf::setrlimitForTest();
60 
61         mGpuMem = std::make_shared<GpuMem>();
62         mGpuMemTracer = std::make_unique<GpuMemTracer>();
63         mGpuMemTracer->initializeForTest(mGpuMem);
64         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
65 
66         errno = 0;
67         mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
68                                                    BPF_F_NO_PREALLOC);
69 
70         EXPECT_EQ(0, errno);
71         EXPECT_LE(0, mTestMap.getMap().get());
72         EXPECT_TRUE(mTestMap.isValid());
73     }
74 
getTracerThreadCount()75     int getTracerThreadCount() { return mGpuMemTracer->tracerThreadCount; }
76 
readGpuMemTotalPacketsBlocking(perfetto::TracingSession * tracingSession)77     std::vector<perfetto::protos::TracePacket> readGpuMemTotalPacketsBlocking(
78             perfetto::TracingSession* tracingSession) {
79         std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
80         perfetto::protos::Trace trace;
81         trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()));
82 
83         std::vector<perfetto::protos::TracePacket> packets;
84         for (const auto& packet : trace.packet()) {
85             if (!packet.has_gpu_mem_total_event()) {
86                 continue;
87             }
88             packets.emplace_back(packet);
89         }
90         return packets;
91     }
92 
93     std::shared_ptr<GpuMem> mGpuMem;
94     TestableGpuMem mTestableGpuMem;
95     std::unique_ptr<GpuMemTracer> mGpuMemTracer;
96     bpf::BpfMap<uint64_t, uint64_t> mTestMap;
97 };
98 
getSizeForPid(uint32_t pid)99 static constexpr uint64_t getSizeForPid(uint32_t pid) {
100     switch (pid) {
101         case TEST_GLOBAL_PID:
102             return TEST_GLOBAL_VAL;
103         case TEST_PROC_PID_1:
104             return TEST_PROC_VAL_1;
105         case TEST_PROC_PID_2:
106             return TEST_PROC_VAL_2;
107     }
108     return 0;
109 }
110 
getGpuIdForPid(uint32_t pid)111 static constexpr uint32_t getGpuIdForPid(uint32_t pid) {
112     switch (pid) {
113         case TEST_GLOBAL_PID:
114             return TEST_GLOBAL_GPU_ID;
115         case TEST_PROC_PID_1:
116             return TEST_PROC_1_GPU_ID;
117         case TEST_PROC_PID_2:
118             return TEST_PROC_2_GPU_ID;
119     }
120     return 0;
121 }
122 
TEST_F(GpuMemTracerTest,traceInitialCountersAfterGpuMemInitialize)123 TEST_F(GpuMemTracerTest, traceInitialCountersAfterGpuMemInitialize) {
124     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
125     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
126     ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
127     mTestableGpuMem.setGpuMemTotalMap(mTestMap);
128     mTestableGpuMem.setInitialized();
129 
130     // Only 1 tracer thread should be existing for test.
131     EXPECT_EQ(getTracerThreadCount(), 1);
132     auto tracingSession = mGpuMemTracer->getTracingSessionForTest();
133 
134     tracingSession->StartBlocking();
135     // Sleep for a short time to let the tracer thread finish its work
136     sleep(1);
137     tracingSession->StopBlocking();
138 
139     // The test tracer thread should have finished its execution by now.
140     EXPECT_EQ(getTracerThreadCount(), 0);
141 
142     auto packets = readGpuMemTotalPacketsBlocking(tracingSession.get());
143     EXPECT_EQ(packets.size(), 3);
144 
145     const auto& packet0 = packets[0];
146     ASSERT_TRUE(packet0.has_timestamp());
147     ASSERT_TRUE(packet0.has_gpu_mem_total_event());
148     const auto& gpuMemEvent0 = packet0.gpu_mem_total_event();
149     ASSERT_TRUE(gpuMemEvent0.has_pid());
150     const auto& pid0 = gpuMemEvent0.pid();
151     ASSERT_TRUE(gpuMemEvent0.has_size());
152     EXPECT_EQ(gpuMemEvent0.size(), getSizeForPid(pid0));
153     ASSERT_TRUE(gpuMemEvent0.has_gpu_id());
154     EXPECT_EQ(gpuMemEvent0.gpu_id(), getGpuIdForPid(pid0));
155 
156     const auto& packet1 = packets[1];
157     ASSERT_TRUE(packet1.has_timestamp());
158     ASSERT_TRUE(packet1.has_gpu_mem_total_event());
159     const auto& gpuMemEvent1 = packet1.gpu_mem_total_event();
160     ASSERT_TRUE(gpuMemEvent1.has_pid());
161     const auto& pid1 = gpuMemEvent1.pid();
162     ASSERT_TRUE(gpuMemEvent1.has_size());
163     EXPECT_EQ(gpuMemEvent1.size(), getSizeForPid(pid1));
164     ASSERT_TRUE(gpuMemEvent1.has_gpu_id());
165     EXPECT_EQ(gpuMemEvent1.gpu_id(), getGpuIdForPid(pid1));
166 
167     const auto& packet2 = packets[2];
168     ASSERT_TRUE(packet2.has_timestamp());
169     ASSERT_TRUE(packet2.has_gpu_mem_total_event());
170     const auto& gpuMemEvent2 = packet2.gpu_mem_total_event();
171     ASSERT_TRUE(gpuMemEvent2.has_pid());
172     const auto& pid2 = gpuMemEvent2.pid();
173     ASSERT_TRUE(gpuMemEvent2.has_size());
174     EXPECT_EQ(gpuMemEvent2.size(), getSizeForPid(pid2));
175     ASSERT_TRUE(gpuMemEvent2.has_gpu_id());
176     EXPECT_EQ(gpuMemEvent2.gpu_id(), getGpuIdForPid(pid2));
177 }
178 
TEST_F(GpuMemTracerTest,noTracingWithoutGpuMemInitialize)179 TEST_F(GpuMemTracerTest, noTracingWithoutGpuMemInitialize) {
180     // Only 1 tracer thread should be existing for test.
181     EXPECT_EQ(getTracerThreadCount(), 1);
182 
183     auto tracingSession = mGpuMemTracer->getTracingSessionForTest();
184 
185     tracingSession->StartBlocking();
186     // Sleep for a short time to let the tracer thread finish its work
187     sleep(1);
188     tracingSession->StopBlocking();
189 
190     // The test tracer thread should have finished its execution by now.
191     EXPECT_EQ(getTracerThreadCount(), 0);
192 
193     auto packets = readGpuMemTotalPacketsBlocking(tracingSession.get());
194     EXPECT_EQ(packets.size(), 0);
195 }
196 } // namespace android
197