summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/TimeStats/TimeStats.h
blob: 8de5d0c3e8a6410dc8de671c1185a1e466c7131e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"

#include <android/hardware/graphics/composer/2.4/IComposerClient.h>

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"

#include <stats_event.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
#include <ui/FenceTime.h>
#include <utils/String16.h>
#include <utils/Vector.h>

#include <deque>
#include <mutex>
#include <optional>
#include <unordered_map>
#include <variant>

using namespace android::surfaceflinger;

namespace android {

class TimeStats {
public:
    virtual ~TimeStats() = default;

    // Called once boot has been finished to perform additional capabilities,
    // e.g. registration to statsd.
    virtual void onBootFinished() = 0;

    virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0;
    virtual bool isEnabled() = 0;
    virtual std::string miniDump() = 0;

    virtual void incrementTotalFrames() = 0;
    virtual void incrementMissedFrames() = 0;
    virtual void incrementClientCompositionFrames() = 0;
    virtual void incrementClientCompositionReusedFrames() = 0;
    // Increments the number of times the display refresh rate changed.
    virtual void incrementRefreshRateSwitches() = 0;
    // Increments the number of changes in composition strategy
    // The intention is to reflect the number of changes between hwc and gpu
    // composition, where "gpu composition" may also include mixed composition.
    virtual void incrementCompositionStrategyChanges() = 0;
    // Records the most up-to-date count of display event connections.
    // The stored count will be the maximum ever recoded.
    virtual void recordDisplayEventConnectionCount(int32_t count) = 0;

    // Records the start and end times for a frame.
    // The start time is the same as the beginning of a SurfaceFlinger
    // invalidate message.
    // The end time corresponds to when SurfaceFlinger finishes submitting the
    // request to HWC to present a frame.
    virtual void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) = 0;
    // Records the start time and end times for when RenderEngine begins work.
    // The start time corresponds to the beginning of RenderEngine::drawLayers.
    // The end time corresponds to when RenderEngine finishes rendering.
    virtual void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) = 0;
    // Same as above, but passes in a fence representing the end time.
    virtual void recordRenderEngineDuration(nsecs_t startTime,
                                            const std::shared_ptr<FenceTime>& readyFence) = 0;

    virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
                             nsecs_t postTime) = 0;
    virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0;
    // Reasons why latching a particular buffer may be skipped
    enum class LatchSkipReason {
        // If the acquire fence did not fire on some devices we skip latching
        // the buffer until the fence fires.
        LateAcquire,
    };
    // Increments the counter of skipped latch buffers.
    virtual void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) = 0;
    // Increments the counter of bad desired present times for this layer.
    // Bad desired present times are "implausible" and cause SurfaceFlinger to
    // latch a buffer immediately to avoid stalling.
    virtual void incrementBadDesiredPresent(int32_t layerId) = 0;
    virtual void setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) = 0;
    virtual void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) = 0;
    virtual void setAcquireFence(int32_t layerId, uint64_t frameNumber,
                                 const std::shared_ptr<FenceTime>& acquireFence) = 0;
    // SetPresent{Time, Fence} are not expected to be called in the critical
    // rendering path, as they flush prior fences if those fences have fired.
    virtual void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) = 0;
    virtual void setPresentFence(int32_t layerId, uint64_t frameNumber,
                                 const std::shared_ptr<FenceTime>& presentFence) = 0;
    // Clean up the layer record
    virtual void onDestroy(int32_t layerId) = 0;
    // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
    virtual void removeTimeRecord(int32_t layerId, uint64_t frameNumber) = 0;

    virtual void setPowerMode(
            hardware::graphics::composer::V2_4::IComposerClient::PowerMode powerMode) = 0;
    // Source of truth is RefrehRateStats.
    virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0;
    virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0;
};

namespace impl {

class TimeStats : public android::TimeStats {
    using PowerMode = android::hardware::graphics::composer::V2_4::IComposerClient::PowerMode;

    struct FrameTime {
        uint64_t frameNumber = 0;
        nsecs_t postTime = 0;
        nsecs_t latchTime = 0;
        nsecs_t acquireTime = 0;
        nsecs_t desiredTime = 0;
        nsecs_t presentTime = 0;
    };

    struct TimeRecord {
        bool ready = false;
        FrameTime frameTime;
        std::shared_ptr<FenceTime> acquireFence;
        std::shared_ptr<FenceTime> presentFence;
    };

    struct LayerRecord {
        std::string layerName;
        // This is the index in timeRecords, at which the timestamps for that
        // specific frame are still not fully received. This is not waiting for
        // fences to signal, but rather waiting to receive those fences/timestamps.
        int32_t waitData = -1;
        uint32_t droppedFrames = 0;
        uint32_t lateAcquireFrames = 0;
        uint32_t badDesiredPresentFrames = 0;
        TimeRecord prevTimeRecord;
        std::deque<TimeRecord> timeRecords;
    };

    struct PowerTime {
        PowerMode powerMode = PowerMode::OFF;
        nsecs_t prevTime = 0;
    };

    struct RenderEngineDuration {
        nsecs_t startTime;
        std::variant<nsecs_t, std::shared_ptr<FenceTime>> endTime;
    };

    struct GlobalRecord {
        nsecs_t prevPresentTime = 0;
        std::deque<std::shared_ptr<FenceTime>> presentFences;
        std::deque<RenderEngineDuration> renderEngineDurations;
    };

public:
    TimeStats();

    // Delegate to the statsd service and associated APIs.
    // Production code may use this class directly, whereas unit test may define
    // a subclass for ease of testing.
    class StatsEventDelegate {
    public:
        virtual ~StatsEventDelegate() = default;
        virtual AStatsEvent* addStatsEventToPullData(AStatsEventList* data) {
            return AStatsEventList_addStatsEvent(data);
        }
        virtual void setStatsPullAtomCallback(int32_t atom_tag,
                                              AStatsManager_PullAtomMetadata* metadata,
                                              AStatsManager_PullAtomCallback callback,
                                              void* cookie) {
            return AStatsManager_setPullAtomCallback(atom_tag, metadata, callback, cookie);
        }

        virtual void clearStatsPullAtomCallback(int32_t atom_tag) {
            return AStatsManager_clearPullAtomCallback(atom_tag);
        }

        virtual void statsEventSetAtomId(AStatsEvent* event, uint32_t atom_id) {
            return AStatsEvent_setAtomId(event, atom_id);
        }

        virtual void statsEventWriteInt32(AStatsEvent* event, int32_t field) {
            return AStatsEvent_writeInt32(event, field);
        }

        virtual void statsEventWriteInt64(AStatsEvent* event, int64_t field) {
            return AStatsEvent_writeInt64(event, field);
        }

        virtual void statsEventWriteString8(AStatsEvent* event, const char* field) {
            return AStatsEvent_writeString(event, field);
        }

        virtual void statsEventWriteByteArray(AStatsEvent* event, const uint8_t* buf,
                                              size_t numBytes) {
            return AStatsEvent_writeByteArray(event, buf, numBytes);
        }

        virtual void statsEventBuild(AStatsEvent* event) { return AStatsEvent_build(event); }
    };
    // For testing only for injecting custom dependencies.
    TimeStats(std::unique_ptr<StatsEventDelegate> statsDelegate,
              std::optional<size_t> maxPulledLayers,
              std::optional<size_t> maxPulledHistogramBuckets);

    ~TimeStats() override;

    void onBootFinished() override;
    void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
    bool isEnabled() override;
    std::string miniDump() override;

    void incrementTotalFrames() override;
    void incrementMissedFrames() override;
    void incrementClientCompositionFrames() override;
    void incrementClientCompositionReusedFrames() override;
    void incrementRefreshRateSwitches() override;
    void incrementCompositionStrategyChanges() override;
    void recordDisplayEventConnectionCount(int32_t count) override;

    void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
    void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override;
    void recordRenderEngineDuration(nsecs_t startTime,
                                    const std::shared_ptr<FenceTime>& readyFence) override;

    void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
                     nsecs_t postTime) override;
    void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override;
    void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override;
    void incrementBadDesiredPresent(int32_t layerId) override;
    void setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) override;
    void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override;
    void setAcquireFence(int32_t layerId, uint64_t frameNumber,
                         const std::shared_ptr<FenceTime>& acquireFence) override;
    void setPresentTime(int32_t layerId, uint64_t frameNumber, nsecs_t presentTime) override;
    void setPresentFence(int32_t layerId, uint64_t frameNumber,
                         const std::shared_ptr<FenceTime>& presentFence) override;
    // Clean up the layer record
    void onDestroy(int32_t layerId) override;
    // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
    void removeTimeRecord(int32_t layerId, uint64_t frameNumber) override;

    void setPowerMode(
            hardware::graphics::composer::V2_4::IComposerClient::PowerMode powerMode) override;
    // Source of truth is RefrehRateStats.
    void recordRefreshRate(uint32_t fps, nsecs_t duration) override;
    void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override;

    static const size_t MAX_NUM_TIME_RECORDS = 64;

private:
    static AStatsManager_PullAtomCallbackReturn pullAtomCallback(int32_t atom_tag,
                                                                 AStatsEventList* data,
                                                                 void* cookie);
    AStatsManager_PullAtomCallbackReturn populateGlobalAtom(AStatsEventList* data);
    AStatsManager_PullAtomCallbackReturn populateLayerAtom(AStatsEventList* data);
    bool recordReadyLocked(int32_t layerId, TimeRecord* timeRecord);
    void flushAvailableRecordsToStatsLocked(int32_t layerId);
    void flushPowerTimeLocked();
    void flushAvailableGlobalRecordsToStatsLocked();

    void enable();
    void disable();
    void clearAll();
    void clearGlobalLocked();
    void clearLayersLocked();
    void dump(bool asProto, std::optional<uint32_t> maxLayers, std::string& result);

    std::atomic<bool> mEnabled = false;
    std::mutex mMutex;
    TimeStatsHelper::TimeStatsGlobal mTimeStats;
    // Hashmap for LayerRecord with layerId as the hash key
    std::unordered_map<int32_t, LayerRecord> mTimeStatsTracker;
    PowerTime mPowerTime;
    GlobalRecord mGlobalRecord;

    static const size_t MAX_NUM_LAYER_RECORDS = 200;
    static const size_t MAX_NUM_LAYER_STATS = 200;
    std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
    size_t mMaxPulledLayers = 8;
    size_t mMaxPulledHistogramBuckets = 6;
};

} // namespace impl

} // namespace android