1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et ft=cpp : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_PerformanceRecorder_h
8 #define mozilla_PerformanceRecorder_h
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/TimeStamp.h"
13 #include "mozilla/TypedEnumBits.h"
14 #include "nsStringFwd.h"
15 
16 namespace mozilla {
17 
18 enum class MediaInfoFlag : uint16_t {
19   None = (0 << 0),
20   NonKeyFrame = (1 << 0),
21   KeyFrame = (1 << 1),
22   SoftwareDecoding = (1 << 2),
23   HardwareDecoding = (1 << 3),
24   VIDEO_AV1 = (1 << 4),
25   VIDEO_H264 = (1 << 5),
26   VIDEO_VP8 = (1 << 6),
27   VIDEO_VP9 = (1 << 7),
28 };
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MediaInfoFlag)29 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MediaInfoFlag)
30 
31 /**
32  * This class is used to record the passed time on the different stages in the
33  * media playback pipeline. It needs to call `Start()` and `End()` explicitly
34  * in order to record the passed time between these two calls.
35  */
36 class PerformanceRecorder {
37  public:
38   /**
39    * This represents the different stages that a media data will go through
40    * within the playback journey.
41    *
42    *           |---|           |---|                 |------|
43    *            Copy Demuxed    Copy Demuxed          Copy Decoded
44    *            Data            Data                  Video
45    *   |------------- |      |-----------------------------------|
46    *     Request Demux         Request Decode
47    * |-----------------------------------------------------------|
48    *   Request Data
49    *
50    * RequestData : Record the time where MediaDecoderStateMachine(MDSM) starts
51    * asking for a decoded data to MDSM receives a decoded data.
52    *
53    * RequestDemux : Record the time where MediaFormatReader(MFR) starts asking
54    * a demuxed sample to MFR received a demuxed sample. This stage is a sub-
55    * stage of RequestData.
56    *
57    * CopyDemuxedData : On some situations, we will need to copy the demuxed
58    * data, which is still not decoded yet so its size is still small. This
59    * records the time which we spend on copying data. This stage could happen
60    * multiple times, either being a sub-stage of RequestDemux (in MSE case), or
61    * being a sub-stage of RequestDecode (when sending data via IPC).
62    *
63    * RequestDecode : Record the time where MFR starts asking decoder to return
64    * a decoded data to MFR receives a decoded data. As the decoder might be
65    * remote, this stage might include the time spending on IPC trips. This stage
66    * is a sub-stage of RequestData.
67    *
68    * CopyDecodedVideo : If we can't reuse same decoder texture to the
69    * compositor, then we have to copy video data to to another sharable texture.
70    * This records the time which we spend on copying data. This stage is a sub-
71    * stage of RequestDecode.
72    */
73   enum class Stage : uint8_t {
74     Invalid,
75     RequestData,
76     RequestDemux,
77     CopyDemuxedData,
78     RequestDecode,
79     CopyDecodedVideo,
80   };
81 
82   explicit PerformanceRecorder(Stage aStage, int32_t aHeight = 0,
83                                MediaInfoFlag aFlag = MediaInfoFlag::None)
84       : mStage(aStage), mHeight(aHeight), mFlag(aFlag) {}
85   ~PerformanceRecorder() = default;
86 
87   PerformanceRecorder(PerformanceRecorder&& aRhs) noexcept {
88     mStage = aRhs.mStage;
89     mHeight = aRhs.mHeight;
90     mStartTime = std::move(aRhs.mStartTime);
91     mFlag = aRhs.mFlag;
92     aRhs.mStage = Stage::Invalid;
93   }
94 
95   PerformanceRecorder& operator=(PerformanceRecorder&& aRhs) noexcept {
96     MOZ_ASSERT(&aRhs != this, "self-moves are prohibited");
97     mStage = aRhs.mStage;
98     mHeight = aRhs.mHeight;
99     mStartTime = std::move(aRhs.mStartTime);
100     mFlag = aRhs.mFlag;
101     aRhs.mStage = Stage::Invalid;
102     return *this;
103   }
104 
105   PerformanceRecorder(const PerformanceRecorder&) = delete;
106   PerformanceRecorder& operator=(const PerformanceRecorder&) = delete;
107 
108   void Start();
109 
110   // Return the passed time if it has started and still valid. Otherwise,
111   // return 0.
112   float End();
113 
114  protected:
115   void Reset();
116 
117   static bool IsMeasurementEnabled();
118   static TimeStamp GetCurrentTimeForMeasurement();
119 
120   // Return the resolution range for the given height. Eg. V:1080<h<=1440.
121   static const char* FindMediaResolution(int32_t aHeight);
122 
123   Stage mStage = Stage::Invalid;
124   int32_t mHeight;
125   MediaInfoFlag mFlag = MediaInfoFlag::None;
126   Maybe<TimeStamp> mStartTime;
127 
128   // We would enable the measurement on testing.
129   static inline bool sEnableMeasurementForTesting = false;
130 };
131 
132 }  // namespace mozilla
133 
134 #endif  // mozilla_PerformanceRecorder_h
135