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