1*38e8c45fSAndroid Build Coastguard Worker /* 2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2021 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 #pragma once 18*38e8c45fSAndroid Build Coastguard Worker 19*38e8c45fSAndroid Build Coastguard Worker #include <android-base/thread_annotations.h> 20*38e8c45fSAndroid Build Coastguard Worker #include <layerproto/TransactionProto.h> 21*38e8c45fSAndroid Build Coastguard Worker #include <utils/Errors.h> 22*38e8c45fSAndroid Build Coastguard Worker #include <utils/Singleton.h> 23*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h> 24*38e8c45fSAndroid Build Coastguard Worker 25*38e8c45fSAndroid Build Coastguard Worker #include <mutex> 26*38e8c45fSAndroid Build Coastguard Worker #include <optional> 27*38e8c45fSAndroid Build Coastguard Worker #include <set> 28*38e8c45fSAndroid Build Coastguard Worker #include <thread> 29*38e8c45fSAndroid Build Coastguard Worker 30*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/DisplayInfo.h" 31*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/LayerCreationArgs.h" 32*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/Update.h" 33*38e8c45fSAndroid Build Coastguard Worker #include "LocklessStack.h" 34*38e8c45fSAndroid Build Coastguard Worker #include "TransactionProtoParser.h" 35*38e8c45fSAndroid Build Coastguard Worker #include "TransactionRingBuffer.h" 36*38e8c45fSAndroid Build Coastguard Worker 37*38e8c45fSAndroid Build Coastguard Worker using namespace android::surfaceflinger; 38*38e8c45fSAndroid Build Coastguard Worker 39*38e8c45fSAndroid Build Coastguard Worker namespace android { 40*38e8c45fSAndroid Build Coastguard Worker 41*38e8c45fSAndroid Build Coastguard Worker class SurfaceFlinger; 42*38e8c45fSAndroid Build Coastguard Worker class TransactionTracingTest; 43*38e8c45fSAndroid Build Coastguard Worker 44*38e8c45fSAndroid Build Coastguard Worker /* 45*38e8c45fSAndroid Build Coastguard Worker * Records all committed transactions into a ring buffer. 46*38e8c45fSAndroid Build Coastguard Worker * 47*38e8c45fSAndroid Build Coastguard Worker * Transactions come in via the binder thread. They are serialized to proto 48*38e8c45fSAndroid Build Coastguard Worker * and stored in a map using the transaction id as key. Main thread will 49*38e8c45fSAndroid Build Coastguard Worker * pass the list of transaction ids that are committed every vsync and notify 50*38e8c45fSAndroid Build Coastguard Worker * the tracing thread. The tracing thread will then wake up and add the 51*38e8c45fSAndroid Build Coastguard Worker * committed transactions to the ring buffer. 52*38e8c45fSAndroid Build Coastguard Worker * 53*38e8c45fSAndroid Build Coastguard Worker * The traced data can then be collected via: 54*38e8c45fSAndroid Build Coastguard Worker * - Perfetto (preferred). 55*38e8c45fSAndroid Build Coastguard Worker * - File system, after triggering the disk write through SF backdoor. This is legacy and is going 56*38e8c45fSAndroid Build Coastguard Worker * to be phased out. 57*38e8c45fSAndroid Build Coastguard Worker * 58*38e8c45fSAndroid Build Coastguard Worker * The Perfetto custom data source TransactionDataSource is registered with perfetto and is used 59*38e8c45fSAndroid Build Coastguard Worker * to listen to perfetto events (setup, start, stop, flush) and to write trace packets to perfetto. 60*38e8c45fSAndroid Build Coastguard Worker * 61*38e8c45fSAndroid Build Coastguard Worker * The user can configure/start/stop tracing via /system/bin/perfetto. 62*38e8c45fSAndroid Build Coastguard Worker * 63*38e8c45fSAndroid Build Coastguard Worker * Tracing can operate in the following modes. 64*38e8c45fSAndroid Build Coastguard Worker * 65*38e8c45fSAndroid Build Coastguard Worker * ACTIVE mode: 66*38e8c45fSAndroid Build Coastguard Worker * The transactions ring buffer (starting state + following committed transactions) is written 67*38e8c45fSAndroid Build Coastguard Worker * (only once) to perfetto when the 'start' event is received. 68*38e8c45fSAndroid Build Coastguard Worker * Transactions are then written to perfetto each time they are committed. 69*38e8c45fSAndroid Build Coastguard Worker * On the receiver side, the data source is to be configured to periodically 70*38e8c45fSAndroid Build Coastguard Worker * flush data to disk providing virtually infinite storage. 71*38e8c45fSAndroid Build Coastguard Worker * 72*38e8c45fSAndroid Build Coastguard Worker * CONTINUOUS mode: 73*38e8c45fSAndroid Build Coastguard Worker * Listens to the perfetto 'flush' event (e.g. when a bugreport is taken). 74*38e8c45fSAndroid Build Coastguard Worker * When a 'flush' event is received, the ring buffer of transactions (starting state + following 75*38e8c45fSAndroid Build Coastguard Worker * committed transactions) is written to perfetto. On the receiver side, the data source is to be 76*38e8c45fSAndroid Build Coastguard Worker * configured with a dedicated buffer large enough to store all the flushed data. 77*38e8c45fSAndroid Build Coastguard Worker * 78*38e8c45fSAndroid Build Coastguard Worker * 79*38e8c45fSAndroid Build Coastguard Worker * E.g. start active mode tracing: 80*38e8c45fSAndroid Build Coastguard Worker * 81*38e8c45fSAndroid Build Coastguard Worker adb shell perfetto \ 82*38e8c45fSAndroid Build Coastguard Worker -c - --txt \ 83*38e8c45fSAndroid Build Coastguard Worker -o /data/misc/perfetto-traces/trace \ 84*38e8c45fSAndroid Build Coastguard Worker <<EOF 85*38e8c45fSAndroid Build Coastguard Worker unique_session_name: "surfaceflinger_transactions_active" 86*38e8c45fSAndroid Build Coastguard Worker buffers: { 87*38e8c45fSAndroid Build Coastguard Worker size_kb: 1024 88*38e8c45fSAndroid Build Coastguard Worker fill_policy: RING_BUFFER 89*38e8c45fSAndroid Build Coastguard Worker } 90*38e8c45fSAndroid Build Coastguard Worker data_sources: { 91*38e8c45fSAndroid Build Coastguard Worker config { 92*38e8c45fSAndroid Build Coastguard Worker name: "android.surfaceflinger.transactions" 93*38e8c45fSAndroid Build Coastguard Worker surfaceflinger_transactions_config: { 94*38e8c45fSAndroid Build Coastguard Worker mode: MODE_ACTIVE 95*38e8c45fSAndroid Build Coastguard Worker } 96*38e8c45fSAndroid Build Coastguard Worker } 97*38e8c45fSAndroid Build Coastguard Worker } 98*38e8c45fSAndroid Build Coastguard Worker write_into_file: true 99*38e8c45fSAndroid Build Coastguard Worker file_write_period_ms: 100 100*38e8c45fSAndroid Build Coastguard Worker EOF 101*38e8c45fSAndroid Build Coastguard Worker * 102*38e8c45fSAndroid Build Coastguard Worker * 103*38e8c45fSAndroid Build Coastguard Worker * E.g. start continuous mode tracing: 104*38e8c45fSAndroid Build Coastguard Worker * 105*38e8c45fSAndroid Build Coastguard Worker adb shell perfetto \ 106*38e8c45fSAndroid Build Coastguard Worker -c - --txt \ 107*38e8c45fSAndroid Build Coastguard Worker -o /data/misc/perfetto-traces/trace \ 108*38e8c45fSAndroid Build Coastguard Worker <<EOF 109*38e8c45fSAndroid Build Coastguard Worker unique_session_name: "surfaceflinger_transactions_continuous" 110*38e8c45fSAndroid Build Coastguard Worker buffers: { 111*38e8c45fSAndroid Build Coastguard Worker size_kb: 1024 112*38e8c45fSAndroid Build Coastguard Worker fill_policy: RING_BUFFER 113*38e8c45fSAndroid Build Coastguard Worker } 114*38e8c45fSAndroid Build Coastguard Worker data_sources: { 115*38e8c45fSAndroid Build Coastguard Worker config { 116*38e8c45fSAndroid Build Coastguard Worker name: "android.surfaceflinger.transactions" 117*38e8c45fSAndroid Build Coastguard Worker surfaceflinger_transactions_config: { 118*38e8c45fSAndroid Build Coastguard Worker mode: MODE_CONTINUOUS 119*38e8c45fSAndroid Build Coastguard Worker } 120*38e8c45fSAndroid Build Coastguard Worker } 121*38e8c45fSAndroid Build Coastguard Worker } 122*38e8c45fSAndroid Build Coastguard Worker EOF 123*38e8c45fSAndroid Build Coastguard Worker * 124*38e8c45fSAndroid Build Coastguard Worker */ 125*38e8c45fSAndroid Build Coastguard Worker class TransactionTracing { 126*38e8c45fSAndroid Build Coastguard Worker public: 127*38e8c45fSAndroid Build Coastguard Worker using Mode = perfetto::protos::pbzero::SurfaceFlingerTransactionsConfig::Mode; 128*38e8c45fSAndroid Build Coastguard Worker 129*38e8c45fSAndroid Build Coastguard Worker TransactionTracing(); 130*38e8c45fSAndroid Build Coastguard Worker ~TransactionTracing(); 131*38e8c45fSAndroid Build Coastguard Worker 132*38e8c45fSAndroid Build Coastguard Worker // Start event from perfetto data source 133*38e8c45fSAndroid Build Coastguard Worker void onStart(Mode mode); 134*38e8c45fSAndroid Build Coastguard Worker // Flush event from perfetto data source 135*38e8c45fSAndroid Build Coastguard Worker void onFlush(Mode mode); 136*38e8c45fSAndroid Build Coastguard Worker 137*38e8c45fSAndroid Build Coastguard Worker void addQueuedTransaction(const TransactionState&); 138*38e8c45fSAndroid Build Coastguard Worker void addCommittedTransactions(int64_t vsyncId, nsecs_t commitTime, frontend::Update& update, 139*38e8c45fSAndroid Build Coastguard Worker const frontend::DisplayInfos&, bool displayInfoChanged); 140*38e8c45fSAndroid Build Coastguard Worker status_t writeToFile(const std::string& filename = FILE_PATH); 141*38e8c45fSAndroid Build Coastguard Worker // Return buffer contents as trace file proto 142*38e8c45fSAndroid Build Coastguard Worker perfetto::protos::TransactionTraceFile writeToProto() EXCLUDES(mMainThreadLock); 143*38e8c45fSAndroid Build Coastguard Worker void setBufferSize(size_t bufferSizeInBytes); 144*38e8c45fSAndroid Build Coastguard Worker void onLayerRemoved(int layerId); 145*38e8c45fSAndroid Build Coastguard Worker void dump(std::string&) const; 146*38e8c45fSAndroid Build Coastguard Worker // Wait until all the committed transactions for the specified vsync id are added to the buffer. 147*38e8c45fSAndroid Build Coastguard Worker void flush() EXCLUDES(mMainThreadLock); 148*38e8c45fSAndroid Build Coastguard Worker 149*38e8c45fSAndroid Build Coastguard Worker static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024; 150*38e8c45fSAndroid Build Coastguard Worker static constexpr auto LEGACY_ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024; 151*38e8c45fSAndroid Build Coastguard Worker // version 1 - switching to support new frontend 152*38e8c45fSAndroid Build Coastguard Worker static constexpr auto TRACING_VERSION = 1; 153*38e8c45fSAndroid Build Coastguard Worker 154*38e8c45fSAndroid Build Coastguard Worker private: 155*38e8c45fSAndroid Build Coastguard Worker friend class TransactionTraceWriter; 156*38e8c45fSAndroid Build Coastguard Worker friend class TransactionTracingTest; 157*38e8c45fSAndroid Build Coastguard Worker friend class SurfaceFlinger; 158*38e8c45fSAndroid Build Coastguard Worker 159*38e8c45fSAndroid Build Coastguard Worker static constexpr auto DIR_NAME = "/data/misc/wmtrace/"; 160*38e8c45fSAndroid Build Coastguard Worker static constexpr auto FILE_NAME = "transactions_trace.winscope"; 161*38e8c45fSAndroid Build Coastguard Worker static constexpr auto FILE_PATH = "/data/misc/wmtrace/transactions_trace.winscope"; getFilePath(const std::string & prefix)162*38e8c45fSAndroid Build Coastguard Worker static std::string getFilePath(const std::string& prefix) { 163*38e8c45fSAndroid Build Coastguard Worker return DIR_NAME + prefix + FILE_NAME; 164*38e8c45fSAndroid Build Coastguard Worker } 165*38e8c45fSAndroid Build Coastguard Worker 166*38e8c45fSAndroid Build Coastguard Worker mutable std::mutex mTraceLock; 167*38e8c45fSAndroid Build Coastguard Worker TransactionRingBuffer<perfetto::protos::TransactionTraceFile, 168*38e8c45fSAndroid Build Coastguard Worker perfetto::protos::TransactionTraceEntry> 169*38e8c45fSAndroid Build Coastguard Worker mBuffer GUARDED_BY(mTraceLock); 170*38e8c45fSAndroid Build Coastguard Worker std::unordered_map<uint64_t, perfetto::protos::TransactionState> mQueuedTransactions 171*38e8c45fSAndroid Build Coastguard Worker GUARDED_BY(mTraceLock); 172*38e8c45fSAndroid Build Coastguard Worker LocklessStack<perfetto::protos::TransactionState> mTransactionQueue; 173*38e8c45fSAndroid Build Coastguard Worker nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock); 174*38e8c45fSAndroid Build Coastguard Worker std::unordered_map<int, perfetto::protos::LayerCreationArgs> mCreatedLayers 175*38e8c45fSAndroid Build Coastguard Worker GUARDED_BY(mTraceLock); 176*38e8c45fSAndroid Build Coastguard Worker std::map<uint32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock); 177*38e8c45fSAndroid Build Coastguard Worker frontend::DisplayInfos mStartingDisplayInfos GUARDED_BY(mTraceLock); 178*38e8c45fSAndroid Build Coastguard Worker 179*38e8c45fSAndroid Build Coastguard Worker std::set<uint32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock); 180*38e8c45fSAndroid Build Coastguard Worker TransactionProtoParser mProtoParser; 181*38e8c45fSAndroid Build Coastguard Worker 182*38e8c45fSAndroid Build Coastguard Worker // We do not want main thread to block so main thread will try to acquire mMainThreadLock, 183*38e8c45fSAndroid Build Coastguard Worker // otherwise will push data to temporary container. 184*38e8c45fSAndroid Build Coastguard Worker std::mutex mMainThreadLock; 185*38e8c45fSAndroid Build Coastguard Worker std::thread mThread GUARDED_BY(mMainThreadLock); 186*38e8c45fSAndroid Build Coastguard Worker bool mDone GUARDED_BY(mMainThreadLock) = false; 187*38e8c45fSAndroid Build Coastguard Worker std::condition_variable mTransactionsAvailableCv; 188*38e8c45fSAndroid Build Coastguard Worker std::condition_variable mTransactionsAddedToBufferCv; 189*38e8c45fSAndroid Build Coastguard Worker struct CommittedUpdates { 190*38e8c45fSAndroid Build Coastguard Worker std::vector<uint64_t> transactionIds; 191*38e8c45fSAndroid Build Coastguard Worker std::vector<LayerCreationArgs> createdLayers; 192*38e8c45fSAndroid Build Coastguard Worker std::vector<uint32_t> destroyedLayerHandles; 193*38e8c45fSAndroid Build Coastguard Worker bool displayInfoChanged; 194*38e8c45fSAndroid Build Coastguard Worker frontend::DisplayInfos displayInfos; 195*38e8c45fSAndroid Build Coastguard Worker int64_t vsyncId; 196*38e8c45fSAndroid Build Coastguard Worker int64_t timestamp; 197*38e8c45fSAndroid Build Coastguard Worker }; 198*38e8c45fSAndroid Build Coastguard Worker std::vector<CommittedUpdates> mUpdates GUARDED_BY(mMainThreadLock); 199*38e8c45fSAndroid Build Coastguard Worker std::vector<CommittedUpdates> mPendingUpdates; // only accessed by main thread 200*38e8c45fSAndroid Build Coastguard Worker 201*38e8c45fSAndroid Build Coastguard Worker std::vector<uint32_t /* layerId */> mDestroyedLayers GUARDED_BY(mMainThreadLock); 202*38e8c45fSAndroid Build Coastguard Worker std::vector<uint32_t /* layerId */> mPendingDestroyedLayers; // only accessed by main thread 203*38e8c45fSAndroid Build Coastguard Worker int64_t mLastUpdatedVsyncId = -1; 204*38e8c45fSAndroid Build Coastguard Worker 205*38e8c45fSAndroid Build Coastguard Worker void writeRingBufferToPerfetto(TransactionTracing::Mode mode); 206*38e8c45fSAndroid Build Coastguard Worker perfetto::protos::TransactionTraceFile createTraceFileProto() const; 207*38e8c45fSAndroid Build Coastguard Worker void loop(); 208*38e8c45fSAndroid Build Coastguard Worker void addEntry(const std::vector<CommittedUpdates>& committedTransactions, 209*38e8c45fSAndroid Build Coastguard Worker const std::vector<uint32_t>& removedLayers) EXCLUDES(mTraceLock); 210*38e8c45fSAndroid Build Coastguard Worker int32_t getLayerIdLocked(const sp<IBinder>& layerHandle) REQUIRES(mTraceLock); 211*38e8c45fSAndroid Build Coastguard Worker void tryPushToTracingThread() EXCLUDES(mMainThreadLock); 212*38e8c45fSAndroid Build Coastguard Worker std::optional<perfetto::protos::TransactionTraceEntry> createStartingStateProtoLocked() 213*38e8c45fSAndroid Build Coastguard Worker REQUIRES(mTraceLock); 214*38e8c45fSAndroid Build Coastguard Worker void updateStartingStateLocked(const perfetto::protos::TransactionTraceEntry& entry) 215*38e8c45fSAndroid Build Coastguard Worker REQUIRES(mTraceLock); 216*38e8c45fSAndroid Build Coastguard Worker }; 217*38e8c45fSAndroid Build Coastguard Worker 218*38e8c45fSAndroid Build Coastguard Worker class TransactionTraceWriter : public Singleton<TransactionTraceWriter> { 219*38e8c45fSAndroid Build Coastguard Worker friend class Singleton<TransactionTracing>; 220*38e8c45fSAndroid Build Coastguard Worker std::function<void(const std::string& prefix, bool overwrite)> mWriterFunction = 221*38e8c45fSAndroid Build Coastguard Worker [](const std::string&, bool) {}; 222*38e8c45fSAndroid Build Coastguard Worker std::atomic<bool> mEnabled{true}; 223*38e8c45fSAndroid Build Coastguard Worker doInvoke(const std::string & filename,bool overwrite)224*38e8c45fSAndroid Build Coastguard Worker void doInvoke(const std::string& filename, bool overwrite) { 225*38e8c45fSAndroid Build Coastguard Worker if (mEnabled) { 226*38e8c45fSAndroid Build Coastguard Worker mWriterFunction(filename, overwrite); 227*38e8c45fSAndroid Build Coastguard Worker } 228*38e8c45fSAndroid Build Coastguard Worker }; 229*38e8c45fSAndroid Build Coastguard Worker 230*38e8c45fSAndroid Build Coastguard Worker public: setWriterFunction(std::function<void (const std::string & filename,bool overwrite)> function)231*38e8c45fSAndroid Build Coastguard Worker void setWriterFunction( 232*38e8c45fSAndroid Build Coastguard Worker std::function<void(const std::string& filename, bool overwrite)> function) { 233*38e8c45fSAndroid Build Coastguard Worker mWriterFunction = std::move(function); 234*38e8c45fSAndroid Build Coastguard Worker } invoke(const std::string & prefix,bool overwrite)235*38e8c45fSAndroid Build Coastguard Worker void invoke(const std::string& prefix, bool overwrite) { 236*38e8c45fSAndroid Build Coastguard Worker doInvoke(TransactionTracing::getFilePath(prefix), overwrite); 237*38e8c45fSAndroid Build Coastguard Worker } 238*38e8c45fSAndroid Build Coastguard Worker /* pass in a complete file path for testing */ invokeForTest(const std::string & filename,bool overwrite)239*38e8c45fSAndroid Build Coastguard Worker void invokeForTest(const std::string& filename, bool overwrite) { 240*38e8c45fSAndroid Build Coastguard Worker doInvoke(filename, overwrite); 241*38e8c45fSAndroid Build Coastguard Worker } 242*38e8c45fSAndroid Build Coastguard Worker /* hacky way to avoid generating traces when converting transaction trace to layers trace. */ disable()243*38e8c45fSAndroid Build Coastguard Worker void disable() { mEnabled.store(false); } enable()244*38e8c45fSAndroid Build Coastguard Worker void enable() { mEnabled.store(true); } 245*38e8c45fSAndroid Build Coastguard Worker }; 246*38e8c45fSAndroid Build Coastguard Worker 247*38e8c45fSAndroid Build Coastguard Worker } // namespace android 248