| Adithya Srinivasan | f031e97 | 2020-12-12 03:31:50 +0000 | [diff] [blame] | 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: | 
|  | 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 |  | 
|  | 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 |  | 
|  | 58 | void SetUp() override { | 
| Adithya Srinivasan | f031e97 | 2020-12-12 03:31:50 +0000 | [diff] [blame] | 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 |  | 
|  | 75 | int getTracerThreadCount() { return mGpuMemTracer->tracerThreadCount; } | 
|  | 76 |  | 
| Adithya Srinivasan | aa51651 | 2020-12-21 23:36:42 +0000 | [diff] [blame] | 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 |  | 
| Adithya Srinivasan | f031e97 | 2020-12-12 03:31:50 +0000 | [diff] [blame] | 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 |  | 
|  | 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 |  | 
|  | 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 |  | 
|  | 123 | TEST_F(GpuMemTracerTest, traceInitialCountersAfterGpuMemInitialize) { | 
| Adithya Srinivasan | f031e97 | 2020-12-12 03:31:50 +0000 | [diff] [blame] | 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 |  | 
| Adithya Srinivasan | aa51651 | 2020-12-21 23:36:42 +0000 | [diff] [blame] | 142 | auto packets = readGpuMemTotalPacketsBlocking(tracingSession.get()); | 
| Adithya Srinivasan | f031e97 | 2020-12-12 03:31:50 +0000 | [diff] [blame] | 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 |  | 
|  | 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 |  | 
| Adithya Srinivasan | aa51651 | 2020-12-21 23:36:42 +0000 | [diff] [blame] | 193 | auto packets = readGpuMemTotalPacketsBlocking(tracingSession.get()); | 
| Adithya Srinivasan | f031e97 | 2020-12-12 03:31:50 +0000 | [diff] [blame] | 194 | EXPECT_EQ(packets.size(), 0); | 
|  | 195 | } | 
|  | 196 | } // namespace android |