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