mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 22:28:36 +00:00
86a3aa0b54
- missing part of Bug 1165772: P1. (7311039be4) - missing gstreamer stuff (54a80d69b2) - Bug 1214208: Do not use MP3Decoder on B2G. r=alfredo (0a19e7946e) - Bug 1194014 - Remove redundant includes. r=jya (ccc3753113) - Bug 1039639 - Add support for Flac on Firefox OS. r=cajbir (7d76197e07) - Bug 875573 - Add video/x-m4v mime type. r=kentuckyfriedtakahe (6ec8af93e6) - cleanup (6fb3d5dd26) - Bug 1180621 - [FxOS] Enable VP9 codec for the Android version after KK. r=sotaro (58f7c2b657) - Bug 1187247: [MSE] P2. Enable WebM in MediaSource. r=jya (2df0ee1f7a) - Bug 1187247: [MSE] P1. Continue parsing MediaSegment if buffer starts with SimpleBlock/Block. r=kinetik (574475ed6f) - Bug 1217170: P1. Rename functions to explicitly reflect what they are doing. r=kentuckyfriedtakahe (70c81a8179) - Bug 1070216 - Split DOMMediaStream::InitStreamCommon into three. r=roc (1bda71cc88) - Bug 1215582 - Rename Blacklist to Block list in GStreamerFormatReader. r=gerald (4f08077f5e) - Bug 1170958 - Destroy track-locked MediaInputPorts when the track ends. r=roc (ff3922a2d6) - Bug 1070216 - constify DOMMediaStream::Get[Audio/Video]Tracks(). r=roc (ba09f6f191) - Bug 1070216 - Guard against adding a track owned by one MSG to a stream owned by another. r=padenot (a80deb8b30) - Bug 1070216 - Implement MediaStream constructors. r=smaug,jib,padenot (3403ef2599) - Bug 1070216 - Guard against a null MediaInputPort in DOMMediaStream::FindPlaybackDOMTrack(). r=roc (453a9ffbc1) - Bug 1212783 - Expose TrackPort in DOMMediaStream.h r=roc (fb61c79ae7) - Bug 1219711 - Ensure MediaStreamTrack.enabled propagates across peer connections. r=jesup (d9d1e54dae) - Bug 1129051 - Fix double free in Camera Control Listener. Fix webrtc memory leak. r=aosmond (3e9b3bccfd) - Bug 1152260 - Generate focused event for drivers that do not notify us when using continuous auto focus. r=mikeh (6c7bd42fdc) - Bug 1175656 - Implement generation of recording posters in Gecko. r=dhylands,bz (51b2c66dc7) - Bug 1187364 - Part 1. Add ability for camera to pause/resume recording. r=dhylands,bz (c54c735e37) - Bug 1187364 - Part 2. Ensure that recording is resumed with a key frame. r=mchiang (c1c6048982) - Bug 1187364 - Part 3. Fix missing end comment in WebIDL. r=me,bz (7faf106cc1) - Bug 1212783 - Add a MediaStreamTrack to DOMCameraControl. r=aosmond (91e11efd3a) - Bug 1124338 - Fix possible camera cached parameters invalidation from underlying driver modification. r=aosmond (dea67dc155) - Bug 1196330 - Do not restart preview if configuration is unchanged. r=dhylands (097644f5d9) - Bug 1215372 - Filter empty camera face detected events at gonk layer. r=dhylands (733efe50eb) - Bug 1179726 - Prefer lower resolutions than 4kuhd as the default video recording profile. r=dhylands (27c71273dc) - Bug 1222122 - Add picture size to verified parameters when reconfiguring the camera. r=dhylands (8c1fac6a4a) - Bug 1141267 - register CameraThread with profiler, r=aosmond (299592a024) - Bug 1008483 - removes the RW lock in CameraControlImpl and replaces it with a standard mutex. r=aosmond (45936cb90d) - Bug 1008483 - Part 2. Readd missing nsPrintfCString.h include which has broken some local builds. r=me (9dd84b0f19) - Bug 1191731 - Update poster API to allow application control over when poster is saved. r=bz, r=dhylands (73f9e7e0f4) - Bug 1155648 - Fix documentation for DOMMediaStream::OnTracksAvailable. r=jesup (702828c304) - Bug 1217170: [MSE] P2. Enable WebM/MSE on systems with no MP4/H264 support. r=kentuckyfriedtakahe (0b814b0708) - Bug 1213177: Enable WebM on machines where H264 HW decoding is disabled. r=kentuckyfriedtakahe (e64da2ea24) - add back some sps telemetry (52c2c64f5b) - missing bit of Bug 1195073: [MSE/webm] P1 (9c45e82c3d) - Bug 1150305 - sourcebuffer.buffered returns the same object if not changed. r=roc, r=bz, r=jya (6005d56c0c) - Bug 1215447 - move flag setting from SeekStarted() to Seek(). r=roc. (a646b744c1) - Bug 1119936 - Audio from FM Radio or Music app ceases to play when switching between front/back camera. r=roc (1a60aa7d69) - Bug 1186806 - Part 1: Replace nsBaseHashtable::EnumerateRead() with iterators in HTMLFormControlsCollection. r=khuey (ccb8cb180a) - Bug 1186806 - Part 2: Use NS_IMPL_CYCLE_COLLECTION_TRAVERSE instead of manual traversal in HTMLFormElement. r=khuey (57e6eabf1b) - Bug 1186806 - Part 3: Replace nsBaseHashtable::EnumerateRead() with iterators in HTMLMediaElement. r=khuey (243ef6e83b) - Bug 1186806 - Part 4: Replace nsBaseHashtable::EnumerateRead() with iterators in HTMLPropertiesCollection. r=khuey (499bdef85f) - Bug 1163958 - Reduce the allocation in MediaStreamGraph - patch 3 CLOSED TREE (a557661df1) - Bug 1219330 - Prevent the creation of TextureClient after shutdown. r=mattwoodrow (a6c047d54f) - Bug 1205559: Make TextureChild/TextureClient thread-safe. r=nical (307c089631) - missing bit of 1219330 (0e351ea419) - nsRefPtr -> RefPtr (07ba248e69) - Bug 1215023. Part 1 - make MediaDecoder::mOwner a const member. We will check mShuttingDown before calling functions of mOwner. r=kinetik. (da7f201815) - Bug 1215023. Part 2 - remove null check of mOwner. We check mShuttingDown to know whether it is valid to call functions of mOwner. r=kinetik. (8d28a04bbe) - Bug 1220558. Part 2 - remove unused members. r=jya. (d3a9ed8c68) - Bug 1223599 - Remove the throttling argument from AbstractMediaDecoder::NotifyDataArrived(). r=jya. (320323ff1d) - Bug 1194606 - Make MediaDecoderStateMachine capable of requesting different kind (decoded/raw) of media data. r=jya (1e2b6a5c44) - Bug 1197075: P3. Decode frames ahead of MDSM requesting them. r=edwin This makes the media.*-decode-ahead pref performs more according to its name. We decode audio and video in advance so a MediaDataPromise can be resolved almost instantly. Default is 2. (b3f56447c4) - Bug 1189964 - Fix bustage. r=bustage CLOSED TREE (afaa49b4b5) - Bug 1212149 - e10s support for opening notification settings. r=wchen (f0e7778fb6) - Bug 1215644 - Use child process volume service cache for available and storage status requests. r=dhylands (dfd49f2ef3) - bug 1215552 - nsHttpConnectionMgr::PostEvent shouldnt manually ref count r=hurley (5e2f1886e6) - Bug 1219392 - Capitalize mozilla::unused to avoid conflicts. r=froydnj (0c8bb7f15a) - bug 1217834 - buzzfeed packet loss r=dragana (e9a60b605f) - Bug 1168033 - Add a comment to nsHttpConnectionMgr.cpp explaining the assignment of attemptedOptimisticPipeline. r=mcmanus (2451996350) - bug 1189645 - remove spdy telem r=hurley (cda90abbdb) - Bug 1148268 - fixed misspelling attribute mActorDestoryed. r=dhyland. (3615d68765) - Bug 1216031 - Make MediaDecoder::mVideoFrameContainer const. r=kinetik. (a3feb9d6bc) - missing bits of Bug 1165515 - Part 13-2 (009e32281f) - Bug 1131473 - crash in -[NativeMenuItemTarget menuItemHit:]. r=spohl (ea2da6441c) - Bug 1216416 - Fix -Wimplicit-fallthrough warnings in widget/cocoa. r=spohl (faaa390b20) - Bug 1181977 - Firefox app menu contains only "Quit" in certain edgecases. r=spohl (0b9d912961)
1034 lines
29 KiB
C++
1034 lines
29 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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/. */
|
|
|
|
#include "nsPerformanceStats.h"
|
|
|
|
#include "nsMemory.h"
|
|
#include "nsLiteralString.h"
|
|
#include "nsCRTGlue.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsCOMArray.h"
|
|
#include "nsIMutableArray.h"
|
|
#include "nsReadableUtils.h"
|
|
|
|
#include "jsapi.h"
|
|
#include "nsJSUtils.h"
|
|
#include "xpcpublic.h"
|
|
#include "jspubtd.h"
|
|
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsGlobalWindow.h"
|
|
|
|
#include "mozilla/unused.h"
|
|
#include "mozilla/ArrayUtils.h"
|
|
#include "mozilla/Services.h"
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
#if defined(XP_WIN)
|
|
#include <processthreadsapi.h>
|
|
#include <windows.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif // defined(XP_WIN)
|
|
|
|
#if defined(XP_MACOSX)
|
|
#include <mach/mach_init.h>
|
|
#include <mach/mach_interface.h>
|
|
#include <mach/mach_port.h>
|
|
#include <mach/mach_types.h>
|
|
#include <mach/message.h>
|
|
#include <mach/thread_info.h>
|
|
#elif defined(XP_UNIX)
|
|
#include <sys/time.h>
|
|
#include <sys/resource.h>
|
|
#endif // defined(XP_UNIX)
|
|
/* ------------------------------------------------------
|
|
*
|
|
* Utility functions.
|
|
*
|
|
*/
|
|
|
|
namespace {
|
|
|
|
/**
|
|
* Get the private window for the current compartment.
|
|
*
|
|
* @return null if the code is not executed in a window or in
|
|
* case of error, a nsPIDOMWindow otherwise.
|
|
*/
|
|
already_AddRefed<nsPIDOMWindow>
|
|
GetPrivateWindow(JSContext* cx) {
|
|
nsCOMPtr<nsPIDOMWindow> win = xpc::CurrentWindowOrNull(cx);
|
|
if (!win) {
|
|
return nullptr;
|
|
}
|
|
|
|
win = win->GetOuterWindow();
|
|
if (!win) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsPIDOMWindow> top = win->GetTop();
|
|
if (!top) {
|
|
return nullptr;
|
|
}
|
|
|
|
return top.forget();
|
|
}
|
|
|
|
bool
|
|
URLForGlobal(JSContext* cx, JS::Handle<JSObject*> global, nsAString& url) {
|
|
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::ObjectPrincipal(global);
|
|
if (!principal) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsresult rv = principal->GetURI(getter_AddRefs(uri));
|
|
if (NS_FAILED(rv) || !uri) {
|
|
return false;
|
|
}
|
|
|
|
nsAutoCString spec;
|
|
rv = uri->GetSpec(spec);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
url.Assign(NS_ConvertUTF8toUTF16(spec));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Extract a somewhat human-readable name from the current context.
|
|
*/
|
|
void
|
|
CompartmentName(JSContext* cx, JS::Handle<JSObject*> global, nsAString& name) {
|
|
// Attempt to use the URL as name.
|
|
if (URLForGlobal(cx, global, name)) {
|
|
return;
|
|
}
|
|
|
|
// Otherwise, fallback to XPConnect's less readable but more
|
|
// complete naming scheme.
|
|
nsAutoCString cname;
|
|
xpc::GetCurrentCompartmentName(cx, cname);
|
|
name.Assign(NS_ConvertUTF8toUTF16(cname));
|
|
}
|
|
|
|
/**
|
|
* Generate a unique-to-the-application identifier for a group.
|
|
*/
|
|
void
|
|
GenerateUniqueGroupId(const JSRuntime* rt, uint64_t uid, uint64_t processId, nsAString& groupId) {
|
|
uint64_t runtimeId = reinterpret_cast<uintptr_t>(rt);
|
|
|
|
groupId.AssignLiteral("process: ");
|
|
groupId.AppendInt(processId);
|
|
groupId.AppendLiteral(", thread: ");
|
|
groupId.AppendInt(runtimeId);
|
|
groupId.AppendLiteral(", group: ");
|
|
groupId.AppendInt(uid);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
/* ------------------------------------------------------
|
|
*
|
|
* struct PerformanceData
|
|
*
|
|
*/
|
|
|
|
PerformanceData::PerformanceData()
|
|
: mTotalUserTime(0)
|
|
, mTotalSystemTime(0)
|
|
, mTotalCPOWTime(0)
|
|
, mTicks(0)
|
|
{
|
|
mozilla::PodArrayZero(mDurations);
|
|
}
|
|
|
|
/* ------------------------------------------------------
|
|
*
|
|
* class nsPerformanceGroupDetails
|
|
*
|
|
*/
|
|
|
|
const nsAString&
|
|
nsPerformanceGroupDetails::Name() const {
|
|
return mName;
|
|
}
|
|
|
|
const nsAString&
|
|
nsPerformanceGroupDetails::GroupId() const {
|
|
return mGroupId;
|
|
}
|
|
|
|
const nsAString&
|
|
nsPerformanceGroupDetails::AddonId() const {
|
|
return mAddonId;
|
|
}
|
|
|
|
uint64_t
|
|
nsPerformanceGroupDetails::WindowId() const {
|
|
return mWindowId;
|
|
}
|
|
|
|
uint64_t
|
|
nsPerformanceGroupDetails::ProcessId() const {
|
|
return mProcessId;
|
|
}
|
|
|
|
bool
|
|
nsPerformanceGroupDetails::IsSystem() const {
|
|
return mIsSystem;
|
|
}
|
|
|
|
bool
|
|
nsPerformanceGroupDetails::IsAddon() const {
|
|
return mAddonId.Length() != 0;
|
|
}
|
|
|
|
bool
|
|
nsPerformanceGroupDetails::IsWindow() const {
|
|
return mWindowId != 0;
|
|
}
|
|
|
|
/* ------------------------------------------------------
|
|
*
|
|
* struct nsPerformanceStats
|
|
*
|
|
*/
|
|
|
|
class nsPerformanceStats: public nsIPerformanceStats,
|
|
public nsPerformanceGroupDetails
|
|
{
|
|
public:
|
|
nsPerformanceStats(const nsAString& aName,
|
|
const nsAString& aGroupId,
|
|
const nsAString& aAddonId,
|
|
const uint64_t aWindowId,
|
|
const uint64_t aProcessId,
|
|
const bool aIsSystem,
|
|
const PerformanceData& aPerformanceData)
|
|
: nsPerformanceGroupDetails(aName, aGroupId, aAddonId, aWindowId, aProcessId, aIsSystem)
|
|
, mPerformanceData(aPerformanceData)
|
|
{
|
|
}
|
|
nsPerformanceStats(const nsPerformanceGroupDetails& item,
|
|
const PerformanceData& aPerformanceData)
|
|
: nsPerformanceGroupDetails(item)
|
|
, mPerformanceData(aPerformanceData)
|
|
{
|
|
}
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_IMETHOD GetName(nsAString& aName) override {
|
|
aName.Assign(nsPerformanceGroupDetails::Name());
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetGroupId(nsAString& aGroupId) override {
|
|
aGroupId.Assign(nsPerformanceGroupDetails::GroupId());
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetAddonId(nsAString& aAddonId) override {
|
|
aAddonId.Assign(nsPerformanceGroupDetails::AddonId());
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetWindowId(uint64_t *aWindowId) override {
|
|
*aWindowId = nsPerformanceGroupDetails::WindowId();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHOD GetIsSystem(bool *_retval) override {
|
|
*_retval = nsPerformanceGroupDetails::IsSystem();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHOD GetTotalUserTime(uint64_t *aTotalUserTime) override {
|
|
*aTotalUserTime = mPerformanceData.mTotalUserTime;
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetTotalSystemTime(uint64_t *aTotalSystemTime) override {
|
|
*aTotalSystemTime = mPerformanceData.mTotalSystemTime;
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetTotalCPOWTime(uint64_t *aCpowTime) override {
|
|
*aCpowTime = mPerformanceData.mTotalCPOWTime;
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetTicks(uint64_t *aTicks) override {
|
|
*aTicks = mPerformanceData.mTicks;
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHOD GetDurations(uint32_t *aCount, uint64_t **aNumberOfOccurrences) override {
|
|
const size_t length = mozilla::ArrayLength(mPerformanceData.mDurations);
|
|
if (aCount) {
|
|
*aCount = length;
|
|
}
|
|
*aNumberOfOccurrences = new uint64_t[length];
|
|
for (size_t i = 0; i < length; ++i) {
|
|
(*aNumberOfOccurrences)[i] = mPerformanceData.mDurations[i];
|
|
}
|
|
return NS_OK;
|
|
};
|
|
|
|
NS_IMETHODIMP GetProcessId(uint64_t* processId) override {
|
|
*processId = nsPerformanceGroupDetails::ProcessId();
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
PerformanceData mPerformanceData;
|
|
|
|
virtual ~nsPerformanceStats() {}
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(nsPerformanceStats, nsIPerformanceStats)
|
|
|
|
|
|
/* ------------------------------------------------------
|
|
*
|
|
* struct nsPerformanceSnapshot
|
|
*
|
|
*/
|
|
|
|
class nsPerformanceSnapshot : public nsIPerformanceSnapshot
|
|
{
|
|
public:
|
|
NS_DECL_ISUPPORTS
|
|
NS_DECL_NSIPERFORMANCESNAPSHOT
|
|
|
|
nsPerformanceSnapshot() {}
|
|
|
|
/**
|
|
* Append statistics to the list of components data.
|
|
*/
|
|
void AppendComponentsStats(nsIPerformanceStats* stats);
|
|
|
|
/**
|
|
* Set the statistics attached to process data.
|
|
*/
|
|
void SetProcessStats(nsIPerformanceStats* group);
|
|
|
|
private:
|
|
virtual ~nsPerformanceSnapshot() {}
|
|
|
|
private:
|
|
/**
|
|
* The data for all components.
|
|
*/
|
|
nsCOMArray<nsIPerformanceStats> mComponentsData;
|
|
|
|
/**
|
|
* The data for the process.
|
|
*/
|
|
nsCOMPtr<nsIPerformanceStats> mProcessData;
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(nsPerformanceSnapshot, nsIPerformanceSnapshot)
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsPerformanceSnapshot::GetComponentsData(nsIArray * *aComponents)
|
|
{
|
|
const size_t length = mComponentsData.Length();
|
|
nsCOMPtr<nsIMutableArray> components = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
|
for (size_t i = 0; i < length; ++i) {
|
|
nsCOMPtr<nsIPerformanceStats> stats = mComponentsData[i];
|
|
mozilla::DebugOnly<nsresult> rv = components->AppendElement(stats, false);
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
}
|
|
components.forget(aComponents);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPerformanceSnapshot::GetProcessData(nsIPerformanceStats * *aProcess)
|
|
{
|
|
NS_IF_ADDREF(*aProcess = mProcessData);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsPerformanceSnapshot::AppendComponentsStats(nsIPerformanceStats* stats)
|
|
{
|
|
mComponentsData.AppendElement(stats);
|
|
}
|
|
|
|
void
|
|
nsPerformanceSnapshot::SetProcessStats(nsIPerformanceStats* stats)
|
|
{
|
|
mProcessData = stats;
|
|
}
|
|
|
|
/* ------------------------------------------------------
|
|
*
|
|
* class nsPerformanceStatsService
|
|
*
|
|
*/
|
|
|
|
NS_IMPL_ISUPPORTS(nsPerformanceStatsService, nsIPerformanceStatsService, nsIObserver)
|
|
|
|
nsPerformanceStatsService::nsPerformanceStatsService()
|
|
: mIsAvailable(false)
|
|
#if defined(XP_WIN)
|
|
, mProcessId(GetCurrentProcessId())
|
|
#else
|
|
, mProcessId(getpid())
|
|
#endif
|
|
, mRuntime(xpc::GetJSRuntime())
|
|
, mUIdCounter(0)
|
|
, mTopGroup(nsPerformanceGroup::Make(mRuntime,
|
|
this,
|
|
NS_LITERAL_STRING("<process>"), // name
|
|
NS_LITERAL_STRING(""), // addonid
|
|
0, // windowId
|
|
mProcessId,
|
|
true, // isSystem
|
|
nsPerformanceGroup::GroupScope::RUNTIME // scope
|
|
))
|
|
, mProcessStayed(0)
|
|
, mProcessMoved(0)
|
|
, mProcessUpdateCounter(0)
|
|
, mIsMonitoringPerCompartment(false)
|
|
|
|
{ }
|
|
|
|
nsPerformanceStatsService::~nsPerformanceStatsService()
|
|
{ }
|
|
|
|
/**
|
|
* Clean up the service.
|
|
*
|
|
* Called during shutdown. Idempotent.
|
|
*/
|
|
void
|
|
nsPerformanceStatsService::Dispose()
|
|
{
|
|
// Make sure that we do not accidentally destroy `this` while we are
|
|
// cleaning up back references.
|
|
RefPtr<nsPerformanceStatsService> kungFuDeathGrip(this);
|
|
mIsAvailable = false;
|
|
|
|
// Disconnect from nsIObserverService.
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
if (obs) {
|
|
obs->RemoveObserver(this, "profile-before-change");
|
|
obs->RemoveObserver(this, "quit-application");
|
|
obs->RemoveObserver(this, "quit-application-granted");
|
|
obs->RemoveObserver(this, "content-child-shutdown");
|
|
obs->RemoveObserver(this, "xpcom-will-shutdown");
|
|
}
|
|
|
|
// Clear up and disconnect from JSAPI.
|
|
js::DisposePerformanceMonitoring(mRuntime);
|
|
|
|
mozilla::Unused << js::SetStopwatchIsMonitoringCPOW(mRuntime, false);
|
|
mozilla::Unused << js::SetStopwatchIsMonitoringJank(mRuntime, false);
|
|
|
|
mozilla::Unused << js::SetStopwatchStartCallback(mRuntime, nullptr, nullptr);
|
|
mozilla::Unused << js::SetStopwatchCommitCallback(mRuntime, nullptr, nullptr);
|
|
mozilla::Unused << js::SetGetPerformanceGroupsCallback(mRuntime, nullptr, nullptr);
|
|
|
|
// At this stage, the JS VM may still be holding references to
|
|
// instances of PerformanceGroup on the stack. To let the service be
|
|
// collected, we need to break the references from these groups to
|
|
// `this`.
|
|
mTopGroup->Dispose();
|
|
mTopGroup = nullptr;
|
|
|
|
// Copy references to the groups to a vector to ensure that we do
|
|
// not modify the hashtable while iterating it.
|
|
GroupVector groups;
|
|
for (auto iter = mGroups.Iter(); !iter.Done(); iter.Next()) {
|
|
groups.append(iter.Get()->GetKey());
|
|
}
|
|
for (auto iter = groups.begin(); iter < groups.end(); iter++) {
|
|
RefPtr<nsPerformanceGroup> group = *iter;
|
|
group->Dispose();
|
|
}
|
|
|
|
// Any remaining references to PerformanceGroup will be released as
|
|
// the VM unrolls the stack. If there are any nested event loops,
|
|
// this may take time.
|
|
}
|
|
|
|
nsresult
|
|
nsPerformanceStatsService::Init()
|
|
{
|
|
nsresult rv = InitInternal();
|
|
if (NS_FAILED(rv)) {
|
|
// Attempt to clean up.
|
|
Dispose();
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsPerformanceStatsService::InitInternal()
|
|
{
|
|
// Make sure that we release everything during shutdown.
|
|
// We are a bit defensive here, as we know that some strange behavior can break the
|
|
// regular shutdown order.
|
|
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
|
if (obs) {
|
|
obs->AddObserver(this, "profile-before-change", false);
|
|
obs->AddObserver(this, "quit-application-granted", false);
|
|
obs->AddObserver(this, "quit-application", false);
|
|
obs->AddObserver(this, "content-child-shutdown", false);
|
|
obs->AddObserver(this, "xpcom-will-shutdown", false);
|
|
}
|
|
|
|
// Connect to JSAPI.
|
|
if (!js::SetStopwatchStartCallback(mRuntime, StopwatchStartCallback, this)) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
if (!js::SetStopwatchCommitCallback(mRuntime, StopwatchCommitCallback, this)) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
if (!js::SetGetPerformanceGroupsCallback(mRuntime, GetPerformanceGroupsCallback, this)) {
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
mTopGroup->setIsActive(true);
|
|
mIsAvailable = true;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// Observe shutdown events.
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::Observe(nsISupports *aSubject, const char *aTopic,
|
|
const char16_t *aData)
|
|
{
|
|
MOZ_ASSERT(strcmp(aTopic, "profile-before-change") == 0
|
|
|| strcmp(aTopic, "quit-application") == 0
|
|
|| strcmp(aTopic, "quit-application-granted") == 0
|
|
|| strcmp(aTopic, "content-child-shutdown") == 0
|
|
|| strcmp(aTopic, "xpcom-will-shutdown") == 0);
|
|
|
|
Dispose();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::GetIsMonitoringCPOW(JSContext* cx, bool *aIsStopwatchActive)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
JSRuntime *runtime = JS_GetRuntime(cx);
|
|
*aIsStopwatchActive = js::GetStopwatchIsMonitoringCPOW(runtime);
|
|
return NS_OK;
|
|
}
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::SetIsMonitoringCPOW(JSContext* cx, bool aIsStopwatchActive)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
JSRuntime *runtime = JS_GetRuntime(cx);
|
|
if (!js::SetStopwatchIsMonitoringCPOW(runtime, aIsStopwatchActive)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::GetIsMonitoringJank(JSContext* cx, bool *aIsStopwatchActive)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
JSRuntime *runtime = JS_GetRuntime(cx);
|
|
*aIsStopwatchActive = js::GetStopwatchIsMonitoringJank(runtime);
|
|
return NS_OK;
|
|
}
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::SetIsMonitoringJank(JSContext* cx, bool aIsStopwatchActive)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
JSRuntime *runtime = JS_GetRuntime(cx);
|
|
if (!js::SetStopwatchIsMonitoringJank(runtime, aIsStopwatchActive)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::GetIsMonitoringPerCompartment(JSContext*, bool *aIsMonitoringPerCompartment)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
*aIsMonitoringPerCompartment = mIsMonitoringPerCompartment;
|
|
return NS_OK;
|
|
}
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::SetIsMonitoringPerCompartment(JSContext*, bool aIsMonitoringPerCompartment)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
if (aIsMonitoringPerCompartment == mIsMonitoringPerCompartment) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Relatively slow update: walk the entire lost of performance groups,
|
|
// update the active flag of those that have changed.
|
|
//
|
|
// Alternative strategies could be envisioned to make the update
|
|
// much faster, at the expense of the speed of calling `isActive()`,
|
|
// (e.g. deferring `isActive()` to the nsPerformanceStatsService),
|
|
// but we expect that `isActive()` can be called thousands of times
|
|
// per second, while `SetIsMonitoringPerCompartment` is not called
|
|
// at all during most Firefox runs.
|
|
|
|
for (auto iter = mGroups.Iter(); !iter.Done(); iter.Next()) {
|
|
RefPtr<nsPerformanceGroup> group = iter.Get()->GetKey();
|
|
if (group->Scope() == nsPerformanceGroup::GroupScope::COMPARTMENT) {
|
|
group->setIsActive(aIsMonitoringPerCompartment);
|
|
}
|
|
}
|
|
mIsMonitoringPerCompartment = aIsMonitoringPerCompartment;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsPerformanceStatsService::UpdateTelemetry()
|
|
{
|
|
// Promote everything to floating-point explicitly before dividing.
|
|
const double processStayed = mProcessStayed;
|
|
const double processMoved = mProcessMoved;
|
|
|
|
if (processStayed <= 0 || processMoved <= 0 || processStayed + processMoved <= 0) {
|
|
// Overflow/underflow/nothing to report
|
|
return NS_OK;
|
|
}
|
|
|
|
const double proportion = (100 * processStayed) / (processStayed + processMoved);
|
|
if (proportion < 0 || proportion > 100) {
|
|
// Overflow/underflow
|
|
return NS_OK;
|
|
}
|
|
|
|
mozilla::Telemetry::Accumulate(mozilla::Telemetry::PERF_MONITORING_TEST_CPU_RESCHEDULING_PROPORTION_MOVED, (uint32_t)proportion);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/* static */ nsIPerformanceStats*
|
|
nsPerformanceStatsService::GetStatsForGroup(const js::PerformanceGroup* group)
|
|
{
|
|
return GetStatsForGroup(nsPerformanceGroup::Get(group));
|
|
}
|
|
|
|
/* static */ nsIPerformanceStats*
|
|
nsPerformanceStatsService::GetStatsForGroup(const nsPerformanceGroup* group)
|
|
{
|
|
return new nsPerformanceStats(*group, group->data);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsPerformanceStatsService::GetSnapshot(JSContext* cx, nsIPerformanceSnapshot * *aSnapshot)
|
|
{
|
|
if (!mIsAvailable) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
RefPtr<nsPerformanceSnapshot> snapshot = new nsPerformanceSnapshot();
|
|
snapshot->SetProcessStats(GetStatsForGroup(mTopGroup));
|
|
|
|
for (auto iter = mGroups.Iter(); !iter.Done(); iter.Next()) {
|
|
auto* entry = iter.Get();
|
|
nsPerformanceGroup* group = entry->GetKey();
|
|
if (group->isActive()) {
|
|
snapshot->AppendComponentsStats(GetStatsForGroup(group));
|
|
}
|
|
}
|
|
|
|
js::GetPerfMonitoringTestCpuRescheduling(JS_GetRuntime(cx), &mProcessStayed, &mProcessMoved);
|
|
|
|
if (++mProcessUpdateCounter % 10 == 0) {
|
|
mozilla::Unused << UpdateTelemetry();
|
|
}
|
|
|
|
snapshot.forget(aSnapshot);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
uint64_t
|
|
nsPerformanceStatsService::GetNextId() {
|
|
return ++mUIdCounter;
|
|
}
|
|
|
|
/* static*/ bool
|
|
nsPerformanceStatsService::GetPerformanceGroupsCallback(JSContext* cx, JSGroupVector& out, void* closure) {
|
|
RefPtr<nsPerformanceStatsService> self = reinterpret_cast<nsPerformanceStatsService*>(closure);
|
|
return self->GetPerformanceGroups(cx, out);
|
|
}
|
|
|
|
bool
|
|
nsPerformanceStatsService::GetPerformanceGroups(JSContext* cx, JSGroupVector& out) {
|
|
JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
|
if (!global) {
|
|
// While it is possible for a compartment to have no global
|
|
// (e.g. atoms), this compartment is not very interesting for us.
|
|
return true;
|
|
}
|
|
|
|
// All compartments belong to the top group.
|
|
out.append(mTopGroup);
|
|
|
|
nsAutoString name;
|
|
CompartmentName(cx, global, name);
|
|
bool isSystem = nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(global));
|
|
|
|
// Find out if the compartment is executed by an add-on. If so, its
|
|
// duration should count towards the total duration of the add-on.
|
|
JSAddonId* jsaddonId = AddonIdOfObject(global);
|
|
nsString addonId;
|
|
if (jsaddonId) {
|
|
AssignJSFlatString(addonId, (JSFlatString*)jsaddonId);
|
|
auto entry = mAddonIdToGroup.PutEntry(addonId);
|
|
if (!entry->mGroup) {
|
|
nsString addonName = name;
|
|
addonName.AppendLiteral(" (as addon ");
|
|
addonName.Append(addonId);
|
|
addonName.AppendLiteral(")");
|
|
entry->mGroup =
|
|
nsPerformanceGroup::Make(mRuntime, this,
|
|
addonName, addonId, 0,
|
|
mProcessId, isSystem,
|
|
nsPerformanceGroup::GroupScope::ADDON);
|
|
}
|
|
out.append(entry->mGroup);
|
|
}
|
|
|
|
// Find out if the compartment is executed by a window. If so, its
|
|
// duration should count towards the total duration of the window.
|
|
nsCOMPtr<nsPIDOMWindow> ptop = GetPrivateWindow(cx);
|
|
uint64_t windowId = 0;
|
|
if (ptop) {
|
|
windowId = ptop->WindowID();
|
|
auto entry = mWindowIdToGroup.PutEntry(windowId);
|
|
if (!entry->mGroup) {
|
|
nsString windowName = name;
|
|
windowName.AppendLiteral(" (as window ");
|
|
windowName.AppendInt(windowId);
|
|
windowName.AppendLiteral(")");
|
|
entry->mGroup =
|
|
nsPerformanceGroup::Make(mRuntime, this,
|
|
windowName, EmptyString(), windowId,
|
|
mProcessId, isSystem,
|
|
nsPerformanceGroup::GroupScope::WINDOW);
|
|
}
|
|
out.append(entry->mGroup);
|
|
}
|
|
|
|
// All compartments have their own group.
|
|
auto group =
|
|
nsPerformanceGroup::Make(mRuntime, this,
|
|
name, addonId, windowId,
|
|
mProcessId, isSystem,
|
|
nsPerformanceGroup::GroupScope::COMPARTMENT);
|
|
out.append(group);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*static*/ bool
|
|
nsPerformanceStatsService::StopwatchStartCallback(uint64_t iteration, void* closure) {
|
|
RefPtr<nsPerformanceStatsService> self = reinterpret_cast<nsPerformanceStatsService*>(closure);
|
|
return self->StopwatchStart(iteration);
|
|
}
|
|
|
|
bool
|
|
nsPerformanceStatsService::StopwatchStart(uint64_t iteration) {
|
|
mIteration = iteration;
|
|
|
|
nsresult rv = GetResources(&mUserTimeStart, &mSystemTimeStart);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*static*/ bool
|
|
nsPerformanceStatsService::StopwatchCommitCallback(uint64_t iteration, JSGroupVector& recentGroups, void* closure) {
|
|
RefPtr<nsPerformanceStatsService> self = reinterpret_cast<nsPerformanceStatsService*>(closure);
|
|
return self->StopwatchCommit(iteration, recentGroups);
|
|
}
|
|
|
|
bool
|
|
nsPerformanceStatsService::StopwatchCommit(uint64_t iteration, JSGroupVector& recentGroups)
|
|
{
|
|
MOZ_ASSERT(iteration == mIteration);
|
|
MOZ_ASSERT(recentGroups.length() > 0);
|
|
|
|
uint64_t userTimeStop, systemTimeStop;
|
|
nsresult rv = GetResources(&userTimeStop, &systemTimeStop);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
// `GetResources` is not guaranteed to be monotonic, so round up
|
|
// any negative result to 0 milliseconds.
|
|
uint64_t userTimeDelta = 0;
|
|
if (userTimeStop > mUserTimeStart)
|
|
userTimeDelta = userTimeStop - mUserTimeStart;
|
|
|
|
uint64_t systemTimeDelta = 0;
|
|
if (systemTimeStop > mSystemTimeStart)
|
|
systemTimeDelta = systemTimeStop - mSystemTimeStart;
|
|
|
|
MOZ_ASSERT(mTopGroup->isUsedInThisIteration());
|
|
const uint64_t totalRecentCycles = mTopGroup->recentCycles(iteration);
|
|
|
|
// We should only reach this stage if `group` has had some activity.
|
|
MOZ_ASSERT(mTopGroup->recentTicks(iteration) > 0);
|
|
for (auto iter = recentGroups.begin(); iter != recentGroups.end(); ++iter) {
|
|
RefPtr<nsPerformanceGroup> group = nsPerformanceGroup::Get(*iter);
|
|
CommitGroup(iteration, userTimeDelta, systemTimeDelta, totalRecentCycles, group);
|
|
}
|
|
|
|
// Make sure that `group` was treated along with the other items of `recentGroups`.
|
|
MOZ_ASSERT(!mTopGroup->isUsedInThisIteration());
|
|
MOZ_ASSERT(mTopGroup->recentTicks(iteration) == 0);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
nsPerformanceStatsService::CommitGroup(uint64_t iteration,
|
|
uint64_t totalUserTimeDelta, uint64_t totalSystemTimeDelta,
|
|
uint64_t totalCyclesDelta, nsPerformanceGroup* group) {
|
|
|
|
MOZ_ASSERT(group->isUsedInThisIteration());
|
|
|
|
const uint64_t ticksDelta = group->recentTicks(iteration);
|
|
const uint64_t cpowTimeDelta = group->recentCPOW(iteration);
|
|
const uint64_t cyclesDelta = group->recentCycles(iteration);
|
|
group->resetRecentData();
|
|
|
|
// We have now performed all cleanup and may `return` at any time without fear of leaks.
|
|
|
|
if (group->iteration() != iteration) {
|
|
// Stale data, don't commit.
|
|
return;
|
|
}
|
|
|
|
// When we add a group as changed, we immediately set its
|
|
// `recentTicks` from 0 to 1. If we have `ticksDelta == 0` at
|
|
// this stage, we have already called `resetRecentData` but we
|
|
// haven't removed it from the list.
|
|
MOZ_ASSERT(ticksDelta != 0);
|
|
MOZ_ASSERT(cyclesDelta <= totalCyclesDelta);
|
|
if (cyclesDelta == 0 || totalCyclesDelta == 0) {
|
|
// Nothing useful, don't commit.
|
|
return;
|
|
}
|
|
|
|
double proportion = (double)cyclesDelta / (double)totalCyclesDelta;
|
|
MOZ_ASSERT(proportion <= 1);
|
|
|
|
const uint64_t userTimeDelta = proportion * totalUserTimeDelta;
|
|
const uint64_t systemTimeDelta = proportion * totalSystemTimeDelta;
|
|
|
|
group->data.mTotalUserTime += userTimeDelta;
|
|
group->data.mTotalSystemTime += systemTimeDelta;
|
|
group->data.mTotalCPOWTime += cpowTimeDelta;
|
|
group->data.mTicks += ticksDelta;
|
|
|
|
const uint64_t totalTimeDelta = userTimeDelta + systemTimeDelta + cpowTimeDelta;
|
|
uint64_t duration = 1000; // 1ms in µs
|
|
for (size_t i = 0;
|
|
i < mozilla::ArrayLength(group->data.mDurations) && duration < totalTimeDelta;
|
|
++i, duration *= 2) {
|
|
group->data.mDurations[i]++;
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsPerformanceStatsService::GetResources(uint64_t* userTime,
|
|
uint64_t* systemTime) const {
|
|
MOZ_ASSERT(userTime);
|
|
MOZ_ASSERT(systemTime);
|
|
|
|
#if defined(XP_MACOSX)
|
|
// On MacOS X, to get we per-thread data, we need to
|
|
// reach into the kernel.
|
|
|
|
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
|
|
thread_basic_info_data_t info;
|
|
mach_port_t port = mach_thread_self();
|
|
kern_return_t err =
|
|
thread_info(/* [in] targeted thread*/ port,
|
|
/* [in] nature of information*/ THREAD_BASIC_INFO,
|
|
/* [out] thread information */ (thread_info_t)&info,
|
|
/* [inout] number of items */ &count);
|
|
|
|
// We do not need ability to communicate with the thread, so
|
|
// let's release the port.
|
|
mach_port_deallocate(mach_task_self(), port);
|
|
|
|
if (err != KERN_SUCCESS)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
*userTime = info.user_time.microseconds + info.user_time.seconds * 1000000;
|
|
*systemTime = info.system_time.microseconds + info.system_time.seconds * 1000000;
|
|
|
|
#elif defined(XP_UNIX)
|
|
struct rusage rusage;
|
|
#if defined(RUSAGE_THREAD)
|
|
// Under Linux, we can obtain per-thread statistics
|
|
int err = getrusage(RUSAGE_THREAD, &rusage);
|
|
#else
|
|
// Under other Unices, we need to do with more noisy
|
|
// per-process statistics.
|
|
int err = getrusage(RUSAGE_SELF, &rusage);
|
|
#endif // defined(RUSAGE_THREAD)
|
|
|
|
if (err)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
*userTime = rusage.ru_utime.tv_usec + rusage.ru_utime.tv_sec * 1000000;
|
|
*systemTime = rusage.ru_stime.tv_usec + rusage.ru_stime.tv_sec * 1000000;
|
|
|
|
#elif defined(XP_WIN)
|
|
// Under Windows, we can obtain per-thread statistics. Experience
|
|
// seems to suggest that they are not very accurate under Windows
|
|
// XP, though.
|
|
FILETIME creationFileTime; // Ignored
|
|
FILETIME exitFileTime; // Ignored
|
|
FILETIME kernelFileTime;
|
|
FILETIME userFileTime;
|
|
BOOL success = GetThreadTimes(GetCurrentThread(),
|
|
&creationFileTime, &exitFileTime,
|
|
&kernelFileTime, &userFileTime);
|
|
|
|
if (!success)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
ULARGE_INTEGER kernelTimeInt;
|
|
kernelTimeInt.LowPart = kernelFileTime.dwLowDateTime;
|
|
kernelTimeInt.HighPart = kernelFileTime.dwHighDateTime;
|
|
// Convert 100 ns to 1 us.
|
|
*systemTime = kernelTimeInt.QuadPart / 10;
|
|
|
|
ULARGE_INTEGER userTimeInt;
|
|
userTimeInt.LowPart = userFileTime.dwLowDateTime;
|
|
userTimeInt.HighPart = userFileTime.dwHighDateTime;
|
|
// Convert 100 ns to 1 us.
|
|
*userTime = userTimeInt.QuadPart / 10;
|
|
|
|
#endif // defined(XP_MACOSX) || defined(XP_UNIX) || defined(XP_WIN)
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------
|
|
*
|
|
* Class nsPerformanceGroup
|
|
*
|
|
*/
|
|
|
|
/*static*/ nsPerformanceGroup*
|
|
nsPerformanceGroup::Make(JSRuntime* rt,
|
|
nsPerformanceStatsService* service,
|
|
const nsAString& name,
|
|
const nsAString& addonId,
|
|
uint64_t windowId,
|
|
uint64_t processId,
|
|
bool isSystem,
|
|
GroupScope scope)
|
|
{
|
|
nsString groupId;
|
|
::GenerateUniqueGroupId(rt, service->GetNextId(), processId, groupId);
|
|
return new nsPerformanceGroup(service, name, groupId, addonId, windowId, processId, isSystem, scope);
|
|
}
|
|
|
|
nsPerformanceGroup::nsPerformanceGroup(nsPerformanceStatsService* service,
|
|
const nsAString& name,
|
|
const nsAString& groupId,
|
|
const nsAString& addonId,
|
|
uint64_t windowId,
|
|
uint64_t processId,
|
|
bool isSystem,
|
|
GroupScope scope)
|
|
: nsPerformanceGroupDetails(name, groupId, addonId, windowId, processId, isSystem)
|
|
, mService(service)
|
|
, mScope(scope)
|
|
{
|
|
mozilla::Unused << mService->mGroups.PutEntry(this);
|
|
|
|
#if defined(DEBUG)
|
|
if (scope == GroupScope::ADDON) {
|
|
MOZ_ASSERT(IsAddon());
|
|
MOZ_ASSERT(!IsWindow());
|
|
} else if (scope == GroupScope::WINDOW) {
|
|
MOZ_ASSERT(IsWindow());
|
|
MOZ_ASSERT(!IsAddon());
|
|
} else if (scope == GroupScope::RUNTIME) {
|
|
MOZ_ASSERT(!IsWindow());
|
|
MOZ_ASSERT(!IsAddon());
|
|
}
|
|
#endif // defined(DEBUG)
|
|
setIsActive(mScope != GroupScope::COMPARTMENT || mService->mIsMonitoringPerCompartment);
|
|
}
|
|
|
|
void
|
|
nsPerformanceGroup::Dispose() {
|
|
if (!mService) {
|
|
// We have already called `Dispose()`.
|
|
return;
|
|
}
|
|
|
|
// Remove any reference to the service
|
|
RefPtr<nsPerformanceStatsService> service;
|
|
service.swap(mService);
|
|
|
|
service->mGroups.RemoveEntry(this);
|
|
|
|
if (mScope == GroupScope::ADDON) {
|
|
MOZ_ASSERT(IsAddon());
|
|
service->mAddonIdToGroup.RemoveEntry(AddonId());
|
|
} else if (mScope == GroupScope::WINDOW) {
|
|
MOZ_ASSERT(IsWindow());
|
|
service->mWindowIdToGroup.RemoveEntry(WindowId());
|
|
}
|
|
}
|
|
|
|
nsPerformanceGroup::~nsPerformanceGroup() {
|
|
Dispose();
|
|
}
|
|
|
|
nsPerformanceGroup::GroupScope
|
|
nsPerformanceGroup::Scope() const {
|
|
return mScope;
|
|
}
|