From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- dom/media/utils/PerformanceRecorder.h | 407 ++++++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 dom/media/utils/PerformanceRecorder.h (limited to 'dom/media/utils/PerformanceRecorder.h') diff --git a/dom/media/utils/PerformanceRecorder.h b/dom/media/utils/PerformanceRecorder.h new file mode 100644 index 0000000000..582d56e5e3 --- /dev/null +++ b/dom/media/utils/PerformanceRecorder.h @@ -0,0 +1,407 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_PerformanceRecorder_h +#define mozilla_PerformanceRecorder_h + +#include + +#include "mozilla/Attributes.h" +#include "mozilla/BaseProfilerMarkersPrerequisites.h" +#include "mozilla/Maybe.h" +#include "mozilla/Mutex.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/TypedEnumBits.h" +#include "nsStringFwd.h" +#include "nsTPriorityQueue.h" +#include "mozilla/ProfilerMarkers.h" + +namespace mozilla { +namespace gfx { +enum class YUVColorSpace : uint8_t; +enum class ColorDepth : uint8_t; +enum class ColorRange : uint8_t; +} // namespace gfx + +struct TrackingId { + enum class Source : uint8_t { + Unimplemented, + AudioDestinationNode, + Camera, + Canvas, + ChannelDecoder, + HLSDecoder, + MediaCapabilities, + MediaElementDecoder, + MediaElementStream, + MSEDecoder, + RTCRtpReceiver, + Screen, + Tab, + Window, + LAST + }; + enum class TrackAcrossProcesses : uint8_t { + Yes, + No, + }; + TrackingId(); + TrackingId(Source aSource, uint32_t aUniqueInProcId, + TrackAcrossProcesses aTrack = TrackAcrossProcesses::No); + + nsCString ToString() const; + + Source mSource; + uint32_t mUniqueInProcId; + Maybe mProcId; +}; + +enum class MediaInfoFlag : uint16_t { + None = (0 << 0), + NonKeyFrame = (1 << 0), + KeyFrame = (1 << 1), + SoftwareDecoding = (1 << 2), + HardwareDecoding = (1 << 3), + VIDEO_AV1 = (1 << 4), + VIDEO_H264 = (1 << 5), + VIDEO_VP8 = (1 << 6), + VIDEO_VP9 = (1 << 7), + VIDEO_THEORA = (1 << 8), +}; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(MediaInfoFlag) + +/** + * This represents the different stages that a media data will go through + * within the playback journey. + * + * |---| |---| |------| + * Copy Demuxed Copy Demuxed Copy Decoded + * Data Data Video + * |------------- | |-----------------------------------| + * Request Demux Request Decode + * |-----------------------------------------------------------| + * Request Data + * + * RequestData : Record the time where MediaDecoderStateMachine(MDSM) starts + * asking for a decoded data to MDSM receives a decoded data. + * + * RequestDemux : Record the time where MediaFormatReader(MFR) starts asking + * a demuxed sample to MFR received a demuxed sample. This stage is a sub- + * stage of RequestData. + * + * CopyDemuxedData : On some situations, we will need to copy the demuxed + * data, which is still not decoded yet so its size is still small. This + * records the time which we spend on copying data. This stage could happen + * multiple times, either being a sub-stage of RequestDemux (in MSE case), + * or being a sub-stage of RequestDecode (when sending data via IPC). + * + * RequestDecode : Record the time where MFR starts asking decoder to return + * a decoded data to MFR receives a decoded data. As the decoder might be + * remote, this stage might include the time spending on IPC trips. This + * stage is a sub-stage of RequestData. + * + * CopyDecodedVideo : If we can't reuse same decoder texture to the + * compositor, then we have to copy video data to to another sharable + * texture. This records the time which we spend on copying data. This stage + * is a sub- stage of RequestDecode. + */ +enum class MediaStage : uint8_t { + Invalid, + RequestData, + RequestDemux, + CopyDemuxedData, + RequestDecode, + CopyDecodedVideo, +}; + +class PlaybackStage { + public: + explicit PlaybackStage(MediaStage aStage, int32_t aHeight = 0, + MediaInfoFlag aFlag = MediaInfoFlag::None) + : mStage(aStage), mHeight(aHeight), mFlag(aFlag) { + MOZ_ASSERT(aStage != MediaStage::Invalid); + } + + ProfilerString8View Name() const; + const MarkerCategory& Category() const { + return baseprofiler::category::MEDIA_PLAYBACK; + } + + MediaStage mStage; + int32_t mHeight; + MediaInfoFlag mFlag; + + private: + mutable Maybe mName; +}; + +class CaptureStage { + public: + enum class ImageType : uint8_t { + Unknown, + I420, + YUY2, + YV12, + UYVY, + NV12, + NV21, + MJPEG, + }; + + CaptureStage(nsCString aSource, TrackingId aTrackingId, int32_t aWidth, + int32_t aHeight, ImageType aImageType) + : mSource(std::move(aSource)), + mTrackingId(std::move(aTrackingId)), + mWidth(aWidth), + mHeight(aHeight), + mImageType(aImageType) {} + + ProfilerString8View Name() const; + const MarkerCategory& Category() const { + return baseprofiler::category::MEDIA_RT; + } + + nsCString mSource; + TrackingId mTrackingId; + int32_t mWidth; + int32_t mHeight; + ImageType mImageType; + + private: + mutable Maybe mName; +}; + +class CopyVideoStage { + public: + CopyVideoStage(nsCString aSource, TrackingId aTrackingId, int32_t aWidth, + int32_t aHeight) + : mSource(std::move(aSource)), + mTrackingId(std::move(aTrackingId)), + mWidth(aWidth), + mHeight(aHeight) {} + + ProfilerString8View Name() const; + const MarkerCategory& Category() const { + return baseprofiler::category::MEDIA_RT; + } + + // The name of the source that performs this stage. + nsCString mSource; + // A unique id identifying the source of the video frame this stage is + // performed for. + TrackingId mTrackingId; + int32_t mWidth; + int32_t mHeight; + + private: + mutable Maybe mName; +}; + +class DecodeStage { + public: + enum ImageFormat : uint8_t { + YUV420P, + YUV422P, + YUV444P, + NV12, + YV12, + NV21, + P010, + P016, + RGBA32, + RGB24, + GBRP, + ANDROID_SURFACE, + }; + + DecodeStage(nsCString aSource, TrackingId aTrackingId, MediaInfoFlag aFlag) + : mSource(std::move(aSource)), + mTrackingId(std::move(aTrackingId)), + mFlag(aFlag) {} + ProfilerString8View Name() const; + const MarkerCategory& Category() const { + return baseprofiler::category::MEDIA_PLAYBACK; + } + + void SetResolution(int aWidth, int aHeight) { + mWidth = Some(aWidth); + mHeight = Some(aHeight); + } + void SetImageFormat(ImageFormat aFormat) { mImageFormat = Some(aFormat); } + void SetYUVColorSpace(gfx::YUVColorSpace aColorSpace) { + mYUVColorSpace = Some(aColorSpace); + } + void SetColorRange(gfx::ColorRange aColorRange) { + mColorRange = Some(aColorRange); + } + void SetColorDepth(gfx::ColorDepth aColorDepth) { + mColorDepth = Some(aColorDepth); + } + + // The name of the source that performs this stage. + nsCString mSource; + // A unique id identifying the source of the video frame this stage is + // performed for. + TrackingId mTrackingId; + MediaInfoFlag mFlag; + Maybe mWidth; + Maybe mHeight; + Maybe mImageFormat; + Maybe mYUVColorSpace; + Maybe mColorRange; + Maybe mColorDepth; + mutable Maybe mName; +}; + +class PerformanceRecorderBase { + public: + static bool IsMeasurementEnabled(); + static TimeStamp GetCurrentTimeForMeasurement(); + + // Return the resolution range for the given height. Eg. V:1080 +class PerformanceRecorderImpl : public PerformanceRecorderBase { + public: + ~PerformanceRecorderImpl() = default; + + PerformanceRecorderImpl(PerformanceRecorderImpl&& aRhs) noexcept + : mStages(std::move(aRhs.mStages)) {} + PerformanceRecorderImpl& operator=(PerformanceRecorderImpl&&) = delete; + PerformanceRecorderImpl(const PerformanceRecorderImpl&) = delete; + PerformanceRecorderImpl& operator=(const PerformanceRecorderImpl&) = delete; + + protected: + PerformanceRecorderImpl() = default; + + // Stores the stage with the current time as its start time, associated with + // aId. + template + void Start(int64_t aId, Args... aArgs) { + if (IsMeasurementEnabled()) { + MutexAutoLock lock(mMutex); + mStages.Push(std::make_tuple(aId, GetCurrentTimeForMeasurement(), + StageType(std::move(aArgs)...))); + } + } + + // Return the passed time since creation of the aId stage in microseconds if + // it has not yet been recorded. Other stages with lower ids will be + // discarded. Otherwise, return 0. + template + float Record(int64_t aId, F&& aStageMutator) { + Maybe entry; + { + MutexAutoLock lock(mMutex); + while (!mStages.IsEmpty() && std::get<0>(mStages.Top()) < aId) { + mStages.Pop(); + } + if (mStages.IsEmpty()) { + return 0.0; + } + if (std::get<0>(mStages.Top()) != aId) { + return 0.0; + } + entry = Some(mStages.Pop()); + } + const auto& startTime = std::get<1>(*entry); + auto& stage = std::get<2>(*entry); + MOZ_ASSERT(std::get<0>(*entry) == aId); + double elapsedTimeUs = 0.0; + if (!startTime.IsNull() && IsMeasurementEnabled()) { + const auto now = TimeStamp::Now(); + elapsedTimeUs = (now - startTime).ToMicroseconds(); + MOZ_ASSERT(elapsedTimeUs >= 0, "Elapsed time can't be less than 0!"); + aStageMutator(stage); + AUTO_PROFILER_STATS(PROFILER_MARKER_UNTYPED); + ::profiler_add_marker( + stage.Name(), stage.Category(), + MarkerOptions(MarkerTiming::Interval(startTime, now))); + } + return static_cast(elapsedTimeUs); + } + float Record(int64_t aId) { + return Record(aId, [](auto&) {}); + } + + protected: + using Entry = std::tuple; + + struct IdComparator { + bool LessThan(const Entry& aTupleA, const Entry& aTupleB) { + return std::get<0>(aTupleA) < std::get<0>(aTupleB); + } + }; + + Mutex mMutex{"PerformanceRecorder::mMutex"}; + nsTPriorityQueue mStages MOZ_GUARDED_BY(mMutex); +}; + +/** + * This class is used to record the time spent on different stages in the media + * pipeline. `Record()` needs to be called explicitly to record a profiler + * marker registering the time passed since creation. A stage may be mutated in + * `Record()` in case data has become available since the recorder started. + * + * This variant is intended to be created on the stack when a stage starts, then + * recorded with `Record()` when the stage is finished. + */ +template +class PerformanceRecorder : public PerformanceRecorderImpl { + using Super = PerformanceRecorderImpl; + + public: + template + explicit PerformanceRecorder(Args... aArgs) { + Start(std::move(aArgs)...); + }; + + private: + template + void Start(Args... aArgs) { + Super::Start(0, std::move(aArgs)...); + } + + public: + template + float Record(F&& aStageMutator) { + return Super::Record(0, std::forward(aStageMutator)); + } + float Record() { return Super::Record(0); } +}; + +/** + * This class is used to record the time spent on different stages in the media + * pipeline. `Start()` and `Record()` needs to be called explicitly to record a + * profiler marker registering the time passed since creation. A stage may be + * mutated in `Record()` in case data has become available since the recorder + * started. + * + * This variant is intended to be kept as a member in a class and supports async + * stages. The async stages may overlap each other. To distinguish different + * stages from each other, an int64_t is used as identifier. This is often a + * timestamp in microseconds, see TimeUnit::ToMicroseconds. + */ +template +class PerformanceRecorderMulti : public PerformanceRecorderImpl { + using Super = PerformanceRecorderImpl; + + public: + PerformanceRecorderMulti() = default; + + using Super::Record; + using Super::Start; +}; + +} // namespace mozilla + +#endif // mozilla_PerformanceRecorder_h -- cgit v1.2.3