tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

PerformanceRecorder.h (13368B)


      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 <utility>
     11 
     12 #include "mozilla/BaseProfilerMarkersPrerequisites.h"
     13 #include "mozilla/DefineEnum.h"
     14 #include "mozilla/Maybe.h"
     15 #include "mozilla/Mutex.h"
     16 #include "mozilla/ProfilerMarkerTypes.h"
     17 #include "mozilla/ProfilerMarkers.h"
     18 #include "mozilla/TimeStamp.h"
     19 #include "mozilla/TypedEnumBits.h"
     20 #include "nsStringFwd.h"
     21 #include "nsTPriorityQueue.h"
     22 
     23 namespace mozilla {
     24 namespace gfx {
     25 enum class YUVColorSpace : uint8_t;
     26 enum class ColorDepth : uint8_t;
     27 enum class ColorRange : uint8_t;
     28 }  // namespace gfx
     29 
     30 struct TrackingId {
     31  MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE(
     32      Source, uint8_t,
     33      (Unimplemented, AudioDestinationNode, Camera, Canvas, ChannelDecoder,
     34       HLSDecoder, MediaCapabilities, MediaElementDecoder, MediaElementStream,
     35       MSEDecoder, RTCRtpReceiver, Screen, Tab, Window, LAST));
     36  enum class TrackAcrossProcesses : uint8_t {
     37    Yes,
     38    No,
     39  };
     40  TrackingId();
     41  TrackingId(Source aSource, uint32_t aUniqueInProcId,
     42             TrackAcrossProcesses aTrack = TrackAcrossProcesses::No);
     43 
     44  nsCString ToString() const;
     45 
     46  Source mSource;
     47  uint32_t mUniqueInProcId;
     48  Maybe<uint32_t> mProcId;
     49 };
     50 
     51 enum class MediaInfoFlag : uint16_t {
     52  None = (0 << 0),
     53  NonKeyFrame = (1 << 0),
     54  KeyFrame = (1 << 1),
     55  SoftwareDecoding = (1 << 2),
     56  HardwareDecoding = (1 << 3),
     57  VIDEO_AV1 = (1 << 4),
     58  VIDEO_H264 = (1 << 5),
     59  VIDEO_VP8 = (1 << 6),
     60  VIDEO_VP9 = (1 << 7),
     61  VIDEO_HEVC = (1 << 9),
     62 };
     63 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MediaInfoFlag)
     64 
     65 /**
     66 * This represents the different stages that a media data will go through
     67 * within the playback journey.
     68 *
     69 *           |---|           |---|                 |------|
     70 *            Copy Demuxed    Copy Demuxed          Copy Decoded
     71 *            Data            Data                  Video
     72 *   |------------- |      |-----------------------------------|
     73 *     Request Demux         Request Decode
     74 * |-----------------------------------------------------------|
     75 *   Request Data
     76 *
     77 * RequestData : Record the time where MediaDecoderStateMachine(MDSM) starts
     78 * asking for a decoded data to MDSM receives a decoded data.
     79 *
     80 * RequestDemux : Record the time where MediaFormatReader(MFR) starts asking
     81 * a demuxed sample to MFR received a demuxed sample. This stage is a sub-
     82 * stage of RequestData.
     83 *
     84 * CopyDemuxedData : On some situations, we will need to copy the demuxed
     85 * data, which is still not decoded yet so its size is still small. This
     86 * records the time which we spend on copying data. This stage could happen
     87 * multiple times, either being a sub-stage of RequestDemux (in MSE case),
     88 * or being a sub-stage of RequestDecode (when sending data via IPC).
     89 *
     90 * RequestDecode : Record the time where MFR starts asking decoder to return
     91 * a decoded data to MFR receives a decoded data. As the decoder might be
     92 * remote, this stage might include the time spending on IPC trips. This
     93 * stage is a sub-stage of RequestData.
     94 *
     95 * CopyDecodedVideo : If we can't reuse same decoder texture to the
     96 * compositor, then we have to copy video data to to another sharable
     97 * texture. This records the time which we spend on copying data. This stage
     98 * is a sub- stage of RequestDecode.
     99 */
    100 MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING(MediaStage, uint8_t,
    101                                             (Invalid, RequestData,
    102                                              RequestDemux, CopyDemuxedData,
    103                                              RequestDecode, CopyDecodedVideo));
    104 
    105 class StageBase {
    106 public:
    107  virtual void AddMarker(MarkerOptions&& aOption) {
    108    profiler_add_marker(Name(), Category(),
    109                        std::forward<MarkerOptions&&>(aOption));
    110  }
    111 
    112 protected:
    113  virtual ProfilerString8View Name() const = 0;
    114  virtual const MarkerCategory& Category() const = 0;
    115 };
    116 
    117 class PlaybackStage : public StageBase {
    118 public:
    119  explicit PlaybackStage(MediaStage aStage, int32_t aHeight = 0,
    120                         MediaInfoFlag aFlag = MediaInfoFlag::None)
    121      : mStage(aStage), mHeight(aHeight), mFlag(aFlag) {
    122    MOZ_ASSERT(aStage != MediaStage::Invalid);
    123  }
    124 
    125  ProfilerString8View Name() const override;
    126  const MarkerCategory& Category() const override {
    127    return baseprofiler::category::MEDIA_PLAYBACK;
    128  }
    129  void AddMarker(MarkerOptions&& aOption) override;
    130 
    131  void SetStartTimeAndEndTime(uint64_t aStartTime, uint64_t aEndTime) {
    132    mStartAndEndTimeUs =
    133        Some(std::pair<uint64_t, uint64_t>{aStartTime, aEndTime});
    134  }
    135 
    136  void AddFlag(MediaInfoFlag aFlag);
    137 
    138  MediaStage mStage;
    139  int32_t mHeight;
    140  MediaInfoFlag mFlag;
    141 
    142  Maybe<std::pair<uint64_t, uint64_t>> mStartAndEndTimeUs;
    143 
    144 private:
    145  mutable Maybe<nsCString> mName;
    146 };
    147 
    148 class CaptureStage : public StageBase {
    149 public:
    150  MOZ_DEFINE_ENUM_CLASS_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE(
    151      ImageType, uint8_t, (Unknown, I420, YUY2, YV12, UYVY, NV12, NV21, MJPEG));
    152 
    153  CaptureStage(nsCString aSource, TrackingId aTrackingId, int32_t aWidth,
    154               int32_t aHeight, ImageType aImageType)
    155      : mSource(std::move(aSource)),
    156        mTrackingId(std::move(aTrackingId)),
    157        mWidth(aWidth),
    158        mHeight(aHeight),
    159        mImageType(aImageType) {}
    160 
    161  ProfilerString8View Name() const override;
    162  const MarkerCategory& Category() const override {
    163    return baseprofiler::category::MEDIA_RT;
    164  }
    165 
    166  nsCString mSource;
    167  TrackingId mTrackingId;
    168  int32_t mWidth;
    169  int32_t mHeight;
    170  ImageType mImageType;
    171 
    172 private:
    173  mutable Maybe<nsCString> mName;
    174 };
    175 
    176 class CopyVideoStage : public StageBase {
    177 public:
    178  CopyVideoStage(nsCString aSource, TrackingId aTrackingId, int32_t aWidth,
    179                 int32_t aHeight)
    180      : mSource(std::move(aSource)),
    181        mTrackingId(std::move(aTrackingId)),
    182        mWidth(aWidth),
    183        mHeight(aHeight) {}
    184 
    185  ProfilerString8View Name() const override;
    186  const MarkerCategory& Category() const override {
    187    return baseprofiler::category::MEDIA_RT;
    188  }
    189 
    190  // The name of the source that performs this stage.
    191  nsCString mSource;
    192  // A unique id identifying the source of the video frame this stage is
    193  // performed for.
    194  TrackingId mTrackingId;
    195  int32_t mWidth;
    196  int32_t mHeight;
    197 
    198 private:
    199  mutable Maybe<nsCString> mName;
    200 };
    201 
    202 class DecodeStage : public StageBase {
    203 public:
    204  MOZ_DEFINE_ENUM_WITH_BASE_AND_TOSTRING_AT_CLASS_SCOPE(
    205      ImageFormat, uint8_t,
    206      (YUV420P, YUV422P, YUV444P, NV12, YV12, NV21, P010, P016, RGBA32, RGB24,
    207       GBRP, ANDROID_SURFACE, VAAPI_SURFACE, D3D11_SURFACE));
    208 
    209  DecodeStage(nsCString aSource, TrackingId aTrackingId, MediaInfoFlag aFlag)
    210      : mSource(std::move(aSource)),
    211        mTrackingId(std::move(aTrackingId)),
    212        mFlag(aFlag) {}
    213  ProfilerString8View Name() const override;
    214  const MarkerCategory& Category() const override {
    215    return baseprofiler::category::MEDIA_PLAYBACK;
    216  }
    217 
    218  void SetResolution(int aWidth, int aHeight) {
    219    mWidth = Some(aWidth);
    220    mHeight = Some(aHeight);
    221  }
    222  void SetImageFormat(ImageFormat aFormat) { mImageFormat = Some(aFormat); }
    223  void SetYUVColorSpace(gfx::YUVColorSpace aColorSpace) {
    224    mYUVColorSpace = Some(aColorSpace);
    225  }
    226  void SetColorRange(gfx::ColorRange aColorRange) {
    227    mColorRange = Some(aColorRange);
    228  }
    229  void SetColorDepth(gfx::ColorDepth aColorDepth) {
    230    mColorDepth = Some(aColorDepth);
    231  }
    232  void SetStartTimeAndEndTime(uint64_t aStartTime, uint64_t aEndTime) {
    233    mStartAndEndTimeUs =
    234        Some(std::pair<uint64_t, uint64_t>{aStartTime, aEndTime});
    235  }
    236  void AddMarker(MarkerOptions&& aOption) override;
    237 
    238  // The name of the source that performs this stage.
    239  nsCString mSource;
    240  // A unique id identifying the source of the video frame this stage is
    241  // performed for.
    242  TrackingId mTrackingId;
    243  MediaInfoFlag mFlag;
    244  Maybe<int> mWidth;
    245  Maybe<int> mHeight;
    246  Maybe<ImageFormat> mImageFormat;
    247  Maybe<gfx::YUVColorSpace> mYUVColorSpace;
    248  Maybe<gfx::ColorRange> mColorRange;
    249  Maybe<gfx::ColorDepth> mColorDepth;
    250  mutable Maybe<nsCString> mName;
    251  Maybe<std::pair<uint64_t, uint64_t>> mStartAndEndTimeUs;
    252 };
    253 
    254 class PerformanceRecorderBase {
    255 public:
    256  static bool IsMeasurementEnabled();
    257  static TimeStamp GetCurrentTimeForMeasurement();
    258 
    259  // Return the resolution range for the given height. Eg. V:1080<h<=1440.
    260  static const char* FindMediaResolution(int32_t aHeight);
    261 
    262 protected:
    263  // We would enable the measurement on testing.
    264  static inline bool sEnableMeasurementForTesting = false;
    265 };
    266 
    267 template <typename StageType>
    268 class PerformanceRecorderImpl : public PerformanceRecorderBase {
    269 public:
    270  ~PerformanceRecorderImpl() = default;
    271 
    272  PerformanceRecorderImpl(PerformanceRecorderImpl&& aRhs) noexcept
    273      : mStages(std::move(aRhs.mStages)) {}
    274  PerformanceRecorderImpl& operator=(PerformanceRecorderImpl&&) = delete;
    275  PerformanceRecorderImpl(const PerformanceRecorderImpl&) = delete;
    276  PerformanceRecorderImpl& operator=(const PerformanceRecorderImpl&) = delete;
    277 
    278 protected:
    279  PerformanceRecorderImpl() = default;
    280 
    281  // Stores the stage with the current time as its start time, associated with
    282  // aId.
    283  template <typename... Args>
    284  void Start(int64_t aId, Args... aArgs) {
    285    if (IsMeasurementEnabled()) {
    286      MutexAutoLock lock(mMutex);
    287      mStages.Push(std::make_tuple(aId, GetCurrentTimeForMeasurement(),
    288                                   StageType(std::move(aArgs)...)));
    289    }
    290  }
    291 
    292  // Return the passed time since creation of the aId stage in microseconds if
    293  // it has not yet been recorded. Other stages with lower ids will be
    294  // discarded. Otherwise, return 0.
    295  template <typename F>
    296  float Record(int64_t aId, F&& aStageMutator) {
    297    Maybe<Entry> entry;
    298    {
    299      MutexAutoLock lock(mMutex);
    300      while (!mStages.IsEmpty() && std::get<0>(mStages.Top()) < aId) {
    301        mStages.Pop();
    302      }
    303      if (mStages.IsEmpty()) {
    304        return 0.0;
    305      }
    306      if (std::get<0>(mStages.Top()) != aId) {
    307        return 0.0;
    308      }
    309      entry = Some(mStages.Pop());
    310    }
    311    const auto& startTime = std::get<1>(*entry);
    312    auto& stage = std::get<2>(*entry);
    313    MOZ_ASSERT(std::get<0>(*entry) == aId);
    314    double elapsedTimeUs = 0.0;
    315    if (!startTime.IsNull() && IsMeasurementEnabled()) {
    316      const auto now = TimeStamp::Now();
    317      elapsedTimeUs = (now - startTime).ToMicroseconds();
    318      MOZ_ASSERT(elapsedTimeUs >= 0, "Elapsed time can't be less than 0!");
    319      aStageMutator(stage);
    320      AUTO_PROFILER_STATS(PROFILER_MARKER_UNTYPED);
    321      stage.AddMarker(MarkerOptions(MarkerTiming::Interval(startTime, now)));
    322    }
    323    return static_cast<float>(elapsedTimeUs);
    324  }
    325  float Record(int64_t aId) {
    326    return Record(aId, [](auto&) {});
    327  }
    328 
    329 protected:
    330  using Entry = std::tuple<int64_t, TimeStamp, StageType>;
    331 
    332  struct IdComparator {
    333    bool LessThan(const Entry& aTupleA, const Entry& aTupleB) {
    334      return std::get<0>(aTupleA) < std::get<0>(aTupleB);
    335    }
    336  };
    337 
    338  Mutex mMutex{"PerformanceRecorder::mMutex"};
    339  nsTPriorityQueue<Entry, IdComparator> mStages MOZ_GUARDED_BY(mMutex);
    340 };
    341 
    342 /**
    343 * This class is used to record the time spent on different stages in the media
    344 * pipeline. `Record()` needs to be called explicitly to record a profiler
    345 * marker registering the time passed since creation. A stage may be mutated in
    346 * `Record()` in case data has become available since the recorder started.
    347 *
    348 * This variant is intended to be created on the stack when a stage starts, then
    349 * recorded with `Record()` when the stage is finished.
    350 */
    351 template <typename StageType>
    352 class PerformanceRecorder : public PerformanceRecorderImpl<StageType> {
    353  using Super = PerformanceRecorderImpl<StageType>;
    354 
    355 public:
    356  template <typename... Args>
    357  explicit PerformanceRecorder(Args... aArgs) {
    358    Start(std::move(aArgs)...);
    359  };
    360 
    361 private:
    362  template <typename... Args>
    363  void Start(Args... aArgs) {
    364    Super::Start(0, std::move(aArgs)...);
    365  }
    366 
    367 public:
    368  template <typename F>
    369  float Record(F&& aStageMutator) {
    370    return Super::Record(0, std::forward<F>(aStageMutator));
    371  }
    372  float Record() { return Super::Record(0); }
    373 };
    374 
    375 /**
    376 * This class is used to record the time spent on different stages in the media
    377 * pipeline. `Start()` and `Record()` needs to be called explicitly to record a
    378 * profiler marker registering the time passed since creation. A stage may be
    379 * mutated in `Record()` in case data has become available since the recorder
    380 * started.
    381 *
    382 * This variant is intended to be kept as a member in a class and supports async
    383 * stages. The async stages may overlap each other. To distinguish different
    384 * stages from each other, an int64_t is used as identifier. This is often a
    385 * timestamp in microseconds, see TimeUnit::ToMicroseconds.
    386 */
    387 template <typename StageType>
    388 class PerformanceRecorderMulti : public PerformanceRecorderImpl<StageType> {
    389  using Super = PerformanceRecorderImpl<StageType>;
    390 
    391 public:
    392  PerformanceRecorderMulti() = default;
    393 
    394  using Super::Record;
    395  using Super::Start;
    396 };
    397 
    398 }  // namespace mozilla
    399 
    400 #endif  // mozilla_PerformanceRecorder_h