• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2025 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 <ui/FatVector.h>
20 #include <ui/FenceTime.h>
21 #include <ui/RingBuffer.h>
22 
23 namespace android {
24 
25 // Debugging class for that tries to add userspace logging for fence depencencies.
26 // The model that a DependencyMonitor tries to follow is, for each access of some resource:
27 // 1. There is a single ingress fence, that guards whether a resource is now safe to read from
28 // another system.
29 // 2. There are multiple access fences, that are fired when a resource is read.
30 // 3. There is a single egress fence, that is fired when a resource is released and sent to another
31 // system.
32 //
33 // Note that there can be repeated ingress and egress of a resource, but the assumption is that
34 // there is exactly one egress for every ingress, unless the resource is destroyed rather than
35 // released.
36 //
37 // The DependencyMonitor will log if there is an anomaly in the fences tracked for some resource.
38 // This includes:
39 // * If (2) happens before (1)
40 // * If (2) happens after (3)
41 //
42 // Note that this class has no knowledge of the "other system". I.e., if the other system ignores
43 // the fence reported in (3), but still takes a long time to write to the resource and produce (1),
44 // then nothing will be logged. That other system must have its own DependencyMonitor. Conversely,
45 // this class has imperfect knowledge of the system it is monitoring. For example, this class does
46 // not know the precise start times of reading from a resource, the exact time that a read might
47 // occur from a hardware unit is not known to userspace.
48 //
49 // In other words, this class logs specific classes of fence violations, but is not sensitive to
50 // *all* violations. One property of this is that unless the system tracked by a DependencyMonitor
51 // is feeding in literally incorrect fences, then there is no chance of a false positive.
52 //
53 // This class is thread safe.
54 class DependencyMonitor {
55 public:
56     // Sets a debug token identifying the resource this monitor is tracking.
setToken(std::string token)57     void setToken(std::string token) { mToken = std::move(token); }
58 
59     // Adds a fence that is fired when the resource ready to be ingested by the system using the
60     // DependencyMonitor.
61     void addIngress(FenceTimePtr fence, std::string annotation);
62     // Adds a fence that is fired when the resource is accessed.
63     void addAccessCompletion(FenceTimePtr fence, std::string annotation);
64     // Adds a fence that is fired when the resource is released to another system.
65     void addEgress(FenceTimePtr fence, std::string annotation);
66 
67 private:
68     struct AnnotatedFenceTime {
69         FenceTimePtr fence;
70         std::string annotation;
71     };
72 
73     struct DependencyBlock {
74         int64_t id = -1;
75         AnnotatedFenceTime ingress = {FenceTime::NO_FENCE, ""};
76         FatVector<AnnotatedFenceTime> accessCompletions;
77         AnnotatedFenceTime egress = {FenceTime::NO_FENCE, ""};
78         bool validated = false;
79         const char* token = nullptr;
80 
resetDependencyBlock81         void reset(const char* newToken) {
82             static std::atomic<int64_t> counter = 0;
83             id = counter++;
84             ingress = {FenceTime::NO_FENCE, ""};
85             accessCompletions.clear();
86             egress = {FenceTime::NO_FENCE, ""};
87             validated = false;
88             token = newToken;
89         }
90 
91         // Returns true if all fences in this block have valid signal times.
92         bool updateSignalTimes(bool excludeIngress);
93 
94         void checkUnsafeAccess() const;
95     };
96 
97     void resolveLocked() REQUIRES(mMutex);
98 
99     std::string mToken;
100     std::mutex mMutex;
101     ui::RingBuffer<DependencyBlock, 10> mDependencies GUARDED_BY(mMutex);
102 };
103 
104 } // namespace android