Bug 1362212 - Move canPlayType telemetry to an idle service observer off main thread. r=gerald

Currently we call HTMLMediaElement.canPlayType() in a JS function called
shortly after startup in order to collect telemetry as to how many of our users
don't have functioning decoders.

Unfortunately, HTMLMediaElement.canPlayType() checks whether we can play a
codec by instantiating a decoder, and this requires us to load the system
decoding libraries from disk. This requires disk I/O, which can cause jank. We
have some BHR reports showing that canPlayType can hang for > 8 seconds to back
this up.

So move the collection of this telemetry to an idle service observer, so that
we only collect this when the user is idle, and do it on a non-main thread so
it is less likely to cause jank.


MozReview-Commit-ID: HJQawmRxz

--HG--
extra : rebase_source : f5a8596fd9de770abd20e1a3e8ac0bcbb5b48599
This commit is contained in:
Chris Pearce 2017-05-05 13:55:14 +12:00
Родитель ccf94e7ff7
Коммит aa3f97c3ef
3 изменённых файлов: 106 добавлений и 1 удалений

Просмотреть файл

@ -33,10 +33,15 @@
#include "mozilla/Telemetry.h"
#include "Layers.h"
#include "mozilla/layers/ShadowLayers.h"
#include "nsIIdleService.h"
#include "MP4Decoder.h"
#ifdef MOZ_ANDROID_OMX
#include "AndroidBridge.h"
#endif
#ifdef XP_WIN
#include "Objbase.h"
#endif
using namespace mozilla::dom;
using namespace mozilla::layers;
@ -125,10 +130,108 @@ LazyLogModule gMediaTimerLog("MediaTimer");
constexpr TimeUnit MediaDecoder::DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED;
class MediaIdleListener : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
private:
virtual ~MediaIdleListener() {}
};
NS_IMPL_ISUPPORTS(MediaIdleListener, nsIObserver)
const unsigned long sMediaTelemetryIdleSeconds = 30u;
NS_IMETHODIMP
MediaIdleListener::Observe(nsISupports*,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(XRE_IsParentProcess());
if (!NS_LITERAL_CSTRING(OBSERVER_TOPIC_IDLE).EqualsASCII(aTopic)) {
return NS_OK;
}
// Collect telemetry about whether the user's machine can decode AAC
// and H.264. We do this off main thread, as determining whether we
// can create a decoder requires us to load decoding libraries, which
// requires disk I/O, and we don't want to be blocking the main thread
// on the chrome process for I/O.
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
RefPtr<MediaIdleListener> self = this;
rv = idleService->RemoveIdleObserver(self, sMediaTelemetryIdleSeconds);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
RefPtr<nsIThread> thread;
rv = NS_NewNamedThread("MediaTelemetry", getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
thread->Dispatch(
NS_NewRunnableFunction([thread]() {
#if XP_WIN
// Windows Media Foundation requires MSCOM to be inited.
HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
MOZ_ASSERT(hr == S_OK);
#endif
bool aac = MP4Decoder::IsSupportedType(
MediaContainerType(MEDIAMIMETYPE("audio/mp4")), nullptr);
bool h264 = MP4Decoder::IsSupportedType(
MediaContainerType(MEDIAMIMETYPE("video/mp4")), nullptr);
AbstractThread::MainThread()->Dispatch(
NS_NewRunnableFunction([thread, aac, h264]() {
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("MediaTelemetry aac=%d h264=%d", aac, h264));
Telemetry::Accumulate(
Telemetry::HistogramID::VIDEO_CAN_CREATE_AAC_DECODER, aac);
Telemetry::Accumulate(
Telemetry::HistogramID::VIDEO_CAN_CREATE_H264_DECODER, h264);
thread->AsyncShutdown();
}));
}),
NS_DISPATCH_NORMAL);
return NS_OK;
}
void
MediaDecoder::InitStatics()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, ("%s", __func__));
if (!XRE_IsParentProcess()) {
return;
}
// Add an idle listener so that we can record some telemetry when the
// user is idle.
nsresult rv;
nsCOMPtr<nsIIdleService> idleService =
do_GetService("@mozilla.org/widget/idleservice;1", &rv);
if (NS_WARN_IF(NS_FAILED((rv)))) {
return;
}
RefPtr<MediaIdleListener> listener = new MediaIdleListener();
rv = idleService->AddIdleObserver(listener, sMediaTelemetryIdleSeconds);
if (NS_WARN_IF(NS_FAILED((rv)))) {
return;
}
}
NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)

Просмотреть файл

@ -181,6 +181,8 @@ private:
DECL_MEDIA_PREF("media.rust.mp4parser", EnableRustMP4Parser, bool, false);
#endif
DECL_MEDIA_PREF("media.mp4.enabled", MP4Enabled, bool, false);
// Error/warning handling, Decoder Doctor
DECL_MEDIA_PREF("media.playback.warnings-as-errors", MediaWarningsAsErrors, bool, false);
DECL_MEDIA_PREF("media.playback.warnings-as-errors.stagefright-vs-rust",

Просмотреть файл

@ -181,7 +181,7 @@ MP4Decoder::IsAAC(const nsACString& aMimeType)
bool
MP4Decoder::IsEnabled()
{
return Preferences::GetBool("media.mp4.enabled", true);
return MediaPrefs::MP4Enabled();
}
// sTestH264ExtraData represents the content of the avcC atom found in