• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 #pragma once
18 
19 #include <bpf/BpfMap.h>
20 #include <stats_pull_atom_callback.h>
21 #include <utils/Mutex.h>
22 #include <utils/String16.h>
23 #include <utils/Vector.h>
24 
25 #include <condition_variable>
26 #include <cstdint>
27 #include <functional>
28 #include <thread>
29 
30 #include "gpuwork/gpu_work.h"
31 
32 namespace android {
33 namespace gpuwork {
34 
35 class GpuWork {
36 public:
37     using Uid = uint32_t;
38 
39     GpuWork() = default;
40     ~GpuWork();
41 
42     void initialize();
43 
44     // Dumps the GPU work information.
45     void dump(const Vector<String16>& args, std::string* result);
46 
47 private:
48     // Attaches tracepoint |tracepoint_group|/|tracepoint_name| to BPF program at path
49     // |program_path|. The tracepoint is also enabled.
50     static bool attachTracepoint(const char* program_path, const char* tracepoint_group,
51                                  const char* tracepoint_name);
52 
53     // Native atom puller callback registered in statsd.
54     static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atomTag,
55                                                                  AStatsEventList* data,
56                                                                  void* cookie);
57 
58     AStatsManager_PullAtomCallbackReturn pullWorkAtoms(AStatsEventList* data);
59 
60     // Periodically calls |clearMapIfNeeded| to clear the |mGpuWorkMap| map, if
61     // needed.
62     //
63     // Thread safety analysis is skipped because we need to use
64     // |std::unique_lock|, which is not currently supported by thread safety
65     // analysis.
66     void periodicallyClearMap() NO_THREAD_SAFETY_ANALYSIS;
67 
68     // Checks whether the |mGpuWorkMap| map is nearly full and, if so, clears
69     // it.
70     void clearMapIfNeeded() REQUIRES(mMutex);
71 
72     // Clears the |mGpuWorkMap| map.
73     void clearMap() REQUIRES(mMutex);
74 
75     // Waits for required permissions to become set. This seems to be needed
76     // because platform service permissions might not be set when a service
77     // first starts. See b/214085769.
78     void waitForPermissions();
79 
80     // Indicates whether our eBPF components have been initialized.
81     std::atomic<bool> mInitialized = false;
82 
83     // A thread that periodically checks whether |mGpuWorkMap| is nearly full
84     // and, if so, clears it.
85     std::thread mMapClearerThread;
86 
87     // Mutex for |mGpuWorkMap| and a few other fields.
88     std::mutex mMutex;
89 
90     // BPF map for per-UID GPU work.
91     bpf::BpfMap<GpuIdUid, UidTrackingInfo> mGpuWorkMap GUARDED_BY(mMutex);
92 
93     // BPF map containing a single element for global data.
94     bpf::BpfMap<uint32_t, GlobalData> mGpuWorkGlobalDataMap GUARDED_BY(mMutex);
95 
96     // When true, we are being destructed, so |mMapClearerThread| should stop.
97     bool mIsTerminating GUARDED_BY(mMutex);
98 
99     // A condition variable for |mIsTerminating|.
100     std::condition_variable mIsTerminatingConditionVariable GUARDED_BY(mMutex);
101 
102     // 30 second timeout for trying to attach a BPF program to a tracepoint.
103     static constexpr int kGpuWaitTimeoutSeconds = 30;
104 
105     // The wait duration for the map clearer thread; the thread checks the map
106     // every ~1 hour.
107     static constexpr uint32_t kMapClearerWaitDurationSeconds = 60 * 60;
108 
109     // Whether our |pullAtomCallback| function is registered.
110     bool mStatsdRegistered GUARDED_BY(mMutex) = false;
111 
112     // The number of randomly chosen (i.e. sampled) UIDs to log stats for.
113     static constexpr size_t kNumSampledUids = 10;
114 
115     // A "large" number of GPUs. If we observe more GPUs than this limit then
116     // we reduce the amount of stats we log.
117     static constexpr size_t kNumGpusSoftLimit = 4;
118 
119     // A "very large" number of GPUs. If we observe more GPUs than this limit
120     // then we don't log any stats.
121     static constexpr size_t kNumGpusHardLimit = 32;
122 
123     // The minimum GPU time needed to actually log stats for a UID.
124     static constexpr uint64_t kMinGpuTimeNanoseconds = 30U * 1000000000U; // 30 seconds.
125 
126     // The previous time point at which |mGpuWorkMap| was cleared.
127     std::chrono::steady_clock::time_point mPreviousMapClearTimePoint GUARDED_BY(mMutex);
128 
129     // Permission to register a statsd puller.
130     static constexpr char16_t kPermissionRegisterStatsPullAtom[] =
131             u"android.permission.REGISTER_STATS_PULL_ATOM";
132 
133     // Time limit for waiting for permissions.
134     static constexpr int kPermissionsWaitTimeoutSeconds = 30;
135 };
136 
137 } // namespace gpuwork
138 } // namespace android
139