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