xref: /aosp_15_r20/frameworks/native/services/gpuservice/gpumem/GpuMem.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2020 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
18*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "GpuMem"
19*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
20*38e8c45fSAndroid Build Coastguard Worker 
21*38e8c45fSAndroid Build Coastguard Worker #include "gpumem/GpuMem.h"
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <libbpf.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <bpf/WaitForProgsLoaded.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <unistd.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <utils/Trace.h>
30*38e8c45fSAndroid Build Coastguard Worker 
31*38e8c45fSAndroid Build Coastguard Worker #include <unordered_map>
32*38e8c45fSAndroid Build Coastguard Worker #include <vector>
33*38e8c45fSAndroid Build Coastguard Worker 
34*38e8c45fSAndroid Build Coastguard Worker namespace android {
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker using base::StringAppendF;
37*38e8c45fSAndroid Build Coastguard Worker 
~GpuMem()38*38e8c45fSAndroid Build Coastguard Worker GpuMem::~GpuMem() {
39*38e8c45fSAndroid Build Coastguard Worker     bpf_detach_tracepoint(kGpuMemTraceGroup, kGpuMemTotalTracepoint);
40*38e8c45fSAndroid Build Coastguard Worker }
41*38e8c45fSAndroid Build Coastguard Worker 
initialize()42*38e8c45fSAndroid Build Coastguard Worker void GpuMem::initialize() {
43*38e8c45fSAndroid Build Coastguard Worker     // Make sure bpf programs are loaded
44*38e8c45fSAndroid Build Coastguard Worker     bpf::waitForProgsLoaded();
45*38e8c45fSAndroid Build Coastguard Worker 
46*38e8c45fSAndroid Build Coastguard Worker     errno = 0;
47*38e8c45fSAndroid Build Coastguard Worker     int fd = bpf::retrieveProgram(kGpuMemTotalProgPath);
48*38e8c45fSAndroid Build Coastguard Worker     if (fd < 0) {
49*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Failed to retrieve pinned program from %s [%d(%s)]", kGpuMemTotalProgPath, errno,
50*38e8c45fSAndroid Build Coastguard Worker               strerror(errno));
51*38e8c45fSAndroid Build Coastguard Worker         return;
52*38e8c45fSAndroid Build Coastguard Worker     }
53*38e8c45fSAndroid Build Coastguard Worker 
54*38e8c45fSAndroid Build Coastguard Worker     // Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
55*38e8c45fSAndroid Build Coastguard Worker     errno = 0;
56*38e8c45fSAndroid Build Coastguard Worker     int count = 0;
57*38e8c45fSAndroid Build Coastguard Worker     while (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
58*38e8c45fSAndroid Build Coastguard Worker         if (++count > kGpuWaitTimeout) {
59*38e8c45fSAndroid Build Coastguard Worker             ALOGE("Failed to attach bpf program to %s/%s tracepoint [%d(%s)]", kGpuMemTraceGroup,
60*38e8c45fSAndroid Build Coastguard Worker                   kGpuMemTotalTracepoint, errno, strerror(errno));
61*38e8c45fSAndroid Build Coastguard Worker             return;
62*38e8c45fSAndroid Build Coastguard Worker         }
63*38e8c45fSAndroid Build Coastguard Worker         // Retry until GPU driver loaded or timeout.
64*38e8c45fSAndroid Build Coastguard Worker         if (mStop.load()) return;
65*38e8c45fSAndroid Build Coastguard Worker         sleep(1);
66*38e8c45fSAndroid Build Coastguard Worker     }
67*38e8c45fSAndroid Build Coastguard Worker 
68*38e8c45fSAndroid Build Coastguard Worker     // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
69*38e8c45fSAndroid Build Coastguard Worker     errno = 0;
70*38e8c45fSAndroid Build Coastguard Worker     auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kGpuMemTotalMapPath);
71*38e8c45fSAndroid Build Coastguard Worker     if (!map.isValid()) {
72*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Failed to create bpf map from %s [%d(%s)]", kGpuMemTotalMapPath, errno,
73*38e8c45fSAndroid Build Coastguard Worker               strerror(errno));
74*38e8c45fSAndroid Build Coastguard Worker         return;
75*38e8c45fSAndroid Build Coastguard Worker     }
76*38e8c45fSAndroid Build Coastguard Worker     setGpuMemTotalMap(map);
77*38e8c45fSAndroid Build Coastguard Worker 
78*38e8c45fSAndroid Build Coastguard Worker     mInitialized.store(true);
79*38e8c45fSAndroid Build Coastguard Worker }
80*38e8c45fSAndroid Build Coastguard Worker 
setGpuMemTotalMap(bpf::BpfMapRO<uint64_t,uint64_t> & map)81*38e8c45fSAndroid Build Coastguard Worker void GpuMem::setGpuMemTotalMap(bpf::BpfMapRO<uint64_t, uint64_t>& map) {
82*38e8c45fSAndroid Build Coastguard Worker     mGpuMemTotalMap = std::move(map);
83*38e8c45fSAndroid Build Coastguard Worker }
84*38e8c45fSAndroid Build Coastguard Worker 
85*38e8c45fSAndroid Build Coastguard Worker // Dump the snapshots of global and per process memory usage on all gpus
dump(const Vector<String16> &,std::string * result)86*38e8c45fSAndroid Build Coastguard Worker void GpuMem::dump(const Vector<String16>& /* args */, std::string* result) {
87*38e8c45fSAndroid Build Coastguard Worker     ATRACE_CALL();
88*38e8c45fSAndroid Build Coastguard Worker 
89*38e8c45fSAndroid Build Coastguard Worker     if (!mInitialized.load() || !mGpuMemTotalMap.isValid()) {
90*38e8c45fSAndroid Build Coastguard Worker         result->append("Failed to initialize GPU memory eBPF\n");
91*38e8c45fSAndroid Build Coastguard Worker         return;
92*38e8c45fSAndroid Build Coastguard Worker     }
93*38e8c45fSAndroid Build Coastguard Worker 
94*38e8c45fSAndroid Build Coastguard Worker     auto res = mGpuMemTotalMap.getFirstKey();
95*38e8c45fSAndroid Build Coastguard Worker     if (!res.ok()) {
96*38e8c45fSAndroid Build Coastguard Worker         result->append("GPU memory total usage map is empty\n");
97*38e8c45fSAndroid Build Coastguard Worker         return;
98*38e8c45fSAndroid Build Coastguard Worker     }
99*38e8c45fSAndroid Build Coastguard Worker     uint64_t key = res.value();
100*38e8c45fSAndroid Build Coastguard Worker     // unordered_map<gpu_id, vector<pair<pid, size>>>
101*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<uint32_t, std::vector<std::pair<uint32_t, uint64_t>>> dumpMap;
102*38e8c45fSAndroid Build Coastguard Worker     while (true) {
103*38e8c45fSAndroid Build Coastguard Worker         uint32_t gpu_id = key >> 32;
104*38e8c45fSAndroid Build Coastguard Worker         uint32_t pid = key;
105*38e8c45fSAndroid Build Coastguard Worker 
106*38e8c45fSAndroid Build Coastguard Worker         res = mGpuMemTotalMap.readValue(key);
107*38e8c45fSAndroid Build Coastguard Worker         if (!res.ok()) break;
108*38e8c45fSAndroid Build Coastguard Worker         uint64_t size = res.value();
109*38e8c45fSAndroid Build Coastguard Worker 
110*38e8c45fSAndroid Build Coastguard Worker         dumpMap[gpu_id].emplace_back(pid, size);
111*38e8c45fSAndroid Build Coastguard Worker 
112*38e8c45fSAndroid Build Coastguard Worker         res = mGpuMemTotalMap.getNextKey(key);
113*38e8c45fSAndroid Build Coastguard Worker         if (!res.ok()) break;
114*38e8c45fSAndroid Build Coastguard Worker         key = res.value();
115*38e8c45fSAndroid Build Coastguard Worker     }
116*38e8c45fSAndroid Build Coastguard Worker 
117*38e8c45fSAndroid Build Coastguard Worker     for (auto& gpu : dumpMap) {
118*38e8c45fSAndroid Build Coastguard Worker         if (gpu.second.empty()) continue;
119*38e8c45fSAndroid Build Coastguard Worker         StringAppendF(result, "Memory snapshot for GPU %u:\n", gpu.first);
120*38e8c45fSAndroid Build Coastguard Worker 
121*38e8c45fSAndroid Build Coastguard Worker         std::sort(gpu.second.begin(), gpu.second.end(),
122*38e8c45fSAndroid Build Coastguard Worker                   [](auto& l, auto& r) { return l.first < r.first; });
123*38e8c45fSAndroid Build Coastguard Worker 
124*38e8c45fSAndroid Build Coastguard Worker         int i = 0;
125*38e8c45fSAndroid Build Coastguard Worker         if (gpu.second[0].first != 0) {
126*38e8c45fSAndroid Build Coastguard Worker             StringAppendF(result, "Global total: N/A\n");
127*38e8c45fSAndroid Build Coastguard Worker         } else {
128*38e8c45fSAndroid Build Coastguard Worker             StringAppendF(result, "Global total: %" PRIu64 "\n", gpu.second[0].second);
129*38e8c45fSAndroid Build Coastguard Worker             i++;
130*38e8c45fSAndroid Build Coastguard Worker         }
131*38e8c45fSAndroid Build Coastguard Worker         for (; i < gpu.second.size(); i++) {
132*38e8c45fSAndroid Build Coastguard Worker             StringAppendF(result, "Proc %u total: %" PRIu64 "\n", gpu.second[i].first,
133*38e8c45fSAndroid Build Coastguard Worker                           gpu.second[i].second);
134*38e8c45fSAndroid Build Coastguard Worker         }
135*38e8c45fSAndroid Build Coastguard Worker     }
136*38e8c45fSAndroid Build Coastguard Worker }
137*38e8c45fSAndroid Build Coastguard Worker 
traverseGpuMemTotals(const std::function<void (int64_t ts,uint32_t gpuId,uint32_t pid,uint64_t size)> & callback)138*38e8c45fSAndroid Build Coastguard Worker void GpuMem::traverseGpuMemTotals(const std::function<void(int64_t ts, uint32_t gpuId, uint32_t pid,
139*38e8c45fSAndroid Build Coastguard Worker                                                            uint64_t size)>& callback) {
140*38e8c45fSAndroid Build Coastguard Worker     auto res = mGpuMemTotalMap.getFirstKey();
141*38e8c45fSAndroid Build Coastguard Worker     if (!res.ok()) return;
142*38e8c45fSAndroid Build Coastguard Worker     uint64_t key = res.value();
143*38e8c45fSAndroid Build Coastguard Worker     while (true) {
144*38e8c45fSAndroid Build Coastguard Worker         uint32_t gpu_id = key >> 32;
145*38e8c45fSAndroid Build Coastguard Worker         uint32_t pid = key;
146*38e8c45fSAndroid Build Coastguard Worker 
147*38e8c45fSAndroid Build Coastguard Worker         res = mGpuMemTotalMap.readValue(key);
148*38e8c45fSAndroid Build Coastguard Worker         if (!res.ok()) break;
149*38e8c45fSAndroid Build Coastguard Worker         uint64_t size = res.value();
150*38e8c45fSAndroid Build Coastguard Worker 
151*38e8c45fSAndroid Build Coastguard Worker         callback(systemTime(), gpu_id, pid, size);
152*38e8c45fSAndroid Build Coastguard Worker         res = mGpuMemTotalMap.getNextKey(key);
153*38e8c45fSAndroid Build Coastguard Worker         if (!res.ok()) break;
154*38e8c45fSAndroid Build Coastguard Worker         key = res.value();
155*38e8c45fSAndroid Build Coastguard Worker     }
156*38e8c45fSAndroid Build Coastguard Worker }
157*38e8c45fSAndroid Build Coastguard Worker 
158*38e8c45fSAndroid Build Coastguard Worker } // namespace android
159