Bug 1022235: Make the webrtc LoadManager/LoadMonitor a singleton r=bsmedberg,pkerr

This commit is contained in:
Randell Jesup 2014-06-13 15:50:51 -04:00
parent fbe30a91e1
commit 95ddaacac2
11 changed files with 182 additions and 96 deletions

View File

@ -15,6 +15,7 @@
#include "nsThreadUtils.h"
#include "nsReadableUtils.h"
#include "nsNetUtil.h"
#include "nsIObserverService.h"
// NSPR_LOG_MODULES=LoadManager:5
PRLogModuleInfo *gLoadManagerLog = nullptr;
@ -30,10 +31,15 @@ PRLogModuleInfo *gLoadManagerLog = nullptr;
namespace mozilla {
LoadManager::LoadManager(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold)
/* static */ StaticRefPtr<LoadManagerSingleton> LoadManagerSingleton::sSingleton;
NS_IMPL_ISUPPORTS(LoadManagerSingleton, nsIObserver)
LoadManagerSingleton::LoadManagerSingleton(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold)
: mLoadSum(0.0f),
mLoadSumMeasurements(0),
mOveruseActive(false),
@ -41,7 +47,8 @@ LoadManager::LoadManager(int aLoadMeasurementInterval,
mAveragingMeasurements(aAveragingMeasurements),
mHighLoadThreshold(aHighLoadThreshold),
mLowLoadThreshold(aLowLoadThreshold),
mCurrentState(webrtc::kLoadNormal)
mCurrentState(webrtc::kLoadNormal),
mLock("LoadManager")
{
#if defined(PR_LOGGING)
if (!gLoadManagerLog)
@ -56,15 +63,44 @@ LoadManager::LoadManager(int aLoadMeasurementInterval,
mLoadMonitor->SetLoadChangeCallback(this);
}
LoadManager::~LoadManager()
LoadManagerSingleton::~LoadManagerSingleton()
{
LOG(("LoadManager: shutting down LoadMonitor"));
mLoadMonitor->Shutdown();
MOZ_ASSERT(!mLoadMonitor, "why wasn't the LoadMonitor shut down in xpcom-shutdown?");
if (mLoadMonitor) {
mLoadMonitor->Shutdown();
}
}
nsresult
LoadManagerSingleton::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (!strcmp(aTopic, "xpcom-shutdown")) {
obs->RemoveObserver(this, "xpcom-shutdown");
{
MutexAutoLock lock(mLock);
mObservers.Clear();
}
if (mLoadMonitor) {
mLoadMonitor->Shutdown();
mLoadMonitor = nullptr;
}
LOG(("Releasing LoadManager singleton and thread"));
// Note: won't be released immediately as the Observer has a ref to us
sSingleton = nullptr;
}
return NS_OK;
}
void
LoadManager::LoadChanged(float aSystemLoad, float aProcesLoad)
LoadManagerSingleton::LoadChanged(float aSystemLoad, float aProcesLoad)
{
MutexAutoLock lock(mLock);
// Update total load, and total amount of measured seconds.
mLoadSum += aSystemLoad;
mLoadSumMeasurements++;
@ -94,9 +130,10 @@ LoadManager::LoadChanged(float aSystemLoad, float aProcesLoad)
}
void
LoadManager::OveruseDetected()
LoadManagerSingleton::OveruseDetected()
{
LOG(("LoadManager - Overuse Detected"));
MutexAutoLock lock(mLock);
mOveruseActive = true;
if (mCurrentState != webrtc::kLoadStressed) {
mCurrentState = webrtc::kLoadStressed;
@ -105,15 +142,17 @@ LoadManager::OveruseDetected()
}
void
LoadManager::NormalUsage()
LoadManagerSingleton::NormalUsage()
{
LOG(("LoadManager - Overuse finished"));
MutexAutoLock lock(mLock);
mOveruseActive = false;
}
void
LoadManager::LoadHasChanged()
LoadManagerSingleton::LoadHasChanged()
{
mLock.AssertCurrentThreadOwns();
LOG(("LoadManager - Signaling LoadHasChanged to %d listeners", mObservers.Length()));
for (size_t i = 0; i < mObservers.Length(); i++) {
mObservers.ElementAt(i)->onLoadStateChanged(mCurrentState);
@ -121,18 +160,36 @@ LoadManager::LoadHasChanged()
}
void
LoadManager::AddObserver(webrtc::CPULoadStateObserver * aObserver)
LoadManagerSingleton::AddObserver(webrtc::CPULoadStateObserver * aObserver)
{
LOG(("LoadManager - Adding Observer"));
MutexAutoLock lock(mLock);
mObservers.AppendElement(aObserver);
if (mObservers.Length() == 1) {
if (!mLoadMonitor) {
mLoadMonitor = new LoadMonitor(mLoadMeasurementInterval);
mLoadMonitor->Init(mLoadMonitor);
mLoadMonitor->SetLoadChangeCallback(this);
}
}
}
void
LoadManager::RemoveObserver(webrtc::CPULoadStateObserver * aObserver)
LoadManagerSingleton::RemoveObserver(webrtc::CPULoadStateObserver * aObserver)
{
LOG(("LoadManager - Removing Observer"));
MutexAutoLock lock(mLock);
if (!mObservers.RemoveElement(aObserver)) {
LOG(("LOadManager - Element to remove not found"));
LOG(("LoadManager - Element to remove not found"));
}
if (mObservers.Length() == 0) {
if (mLoadMonitor) {
// Dance to avoid deadlock on mLock!
nsRefPtr<LoadMonitor> loadMonitor = mLoadMonitor.forget();
MutexAutoUnlock unlock(mLock);
loadMonitor->Shutdown();
}
}
}

View File

@ -7,25 +7,30 @@
#define _LOADMANAGER_H_
#include "LoadMonitor.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Services.h"
#include "nsTArray.h"
#include "nsIObserver.h"
#include "webrtc/common_types.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "mozilla/TimeStamp.h"
#include "nsTArray.h"
extern PRLogModuleInfo *gLoadManagerLog;
namespace mozilla {
class LoadManager : public LoadNotificationCallback,
public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver
class LoadManagerSingleton : public LoadNotificationCallback,
public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver,
public nsIObserver
{
public:
LoadManager(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold);
~LoadManager();
static LoadManagerSingleton* Get();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
// LoadNotificationCallback interface
virtual void LoadChanged(float aSystemLoad, float aProcessLoad) MOZ_OVERRIDE;
@ -39,22 +44,62 @@ public:
virtual void RemoveObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE;
private:
LoadManagerSingleton(int aLoadMeasurementInterval,
int aAveragingMeasurements,
float aHighLoadThreshold,
float aLowLoadThreshold);
~LoadManagerSingleton();
void LoadHasChanged();
nsRefPtr<LoadMonitor> mLoadMonitor;
float mLoadSum;
int mLoadSumMeasurements;
// This protexts access to the mObservers list, the current state, pretty much all
// the other members (below)
Mutex mLock;
nsTArray<webrtc::CPULoadStateObserver*> mObservers;
webrtc::CPULoadState mCurrentState;
// Set when overuse was signaled to us, and hasn't been un-signaled yet.
bool mOveruseActive;
float mLoadSum;
int mLoadSumMeasurements;
// Load measurement settings
int mLoadMeasurementInterval;
int mAveragingMeasurements;
float mHighLoadThreshold;
float mLowLoadThreshold;
webrtc::CPULoadState mCurrentState;
static StaticRefPtr<LoadManagerSingleton> sSingleton;
};
nsTArray<webrtc::CPULoadStateObserver*> mObservers;
class LoadManager MOZ_FINAL : public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver
{
public:
LoadManager(LoadManagerSingleton* aManager)
: mManager(aManager)
{}
~LoadManager() {}
void AddObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE
{
mManager->AddObserver(aObserver);
}
void RemoveObserver(webrtc::CPULoadStateObserver * aObserver) MOZ_OVERRIDE
{
mManager->RemoveObserver(aObserver);
}
void OveruseDetected() MOZ_OVERRIDE
{
mManager->OveruseDetected();
}
void NormalUsage() MOZ_OVERRIDE
{
mManager->NormalUsage();
}
private:
LoadManagerSingleton* mManager;
};
} //namespace

View File

@ -6,33 +6,44 @@
#include "LoadManager.h"
#include "LoadManagerFactory.h"
#include "MainThreadUtils.h"
#include "nsIObserverService.h"
#include "mozilla/Preferences.h"
namespace mozilla {
LoadManager* LoadManagerBuild(void)
// Assume stored in an nsAutoPtr<>
LoadManager *
LoadManagerBuild(void)
{
MOZ_ASSERT(NS_IsMainThread());
int loadMeasurementInterval =
mozilla::Preferences::GetInt("media.navigator.load_adapt.measure_interval", 1000);
int averagingSeconds =
mozilla::Preferences::GetInt("media.navigator.load_adapt.avg_seconds", 3);
float highLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.high_load", 0.90);
float lowLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.low_load", 0.40);
return new LoadManager(loadMeasurementInterval,
averagingSeconds,
highLoadThreshold,
lowLoadThreshold);
return new LoadManager(LoadManagerSingleton::Get());
}
void LoadManagerDestroy(mozilla::LoadManager* aLoadManager)
{
delete aLoadManager;
/* static */ LoadManagerSingleton*
LoadManagerSingleton::Get() {
if (!sSingleton) {
MOZ_ASSERT(NS_IsMainThread());
int loadMeasurementInterval =
mozilla::Preferences::GetInt("media.navigator.load_adapt.measure_interval", 1000);
int averagingSeconds =
mozilla::Preferences::GetInt("media.navigator.load_adapt.avg_seconds", 3);
float highLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.high_load", 0.90);
float lowLoadThreshold =
mozilla::Preferences::GetFloat("media.navigator.load_adapt.low_load", 0.40);
sSingleton = new LoadManagerSingleton(loadMeasurementInterval,
averagingSeconds,
highLoadThreshold,
lowLoadThreshold);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
}
}
return sSingleton;
}
}; // namespace

View File

@ -416,8 +416,7 @@ WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
codecConfig->mFreq,
codecConfig->mPacSize,
codecConfig->mChannels,
codecConfig->mRate,
codecConfig->mLoadManager);
codecConfig->mRate);
mEngineTransmitting = true;
return kMediaConduitNoError;
@ -910,8 +909,7 @@ WebrtcAudioConduit::CopyCodecToDB(const AudioCodecConfig* codecInfo)
codecInfo->mFreq,
codecInfo->mPacSize,
codecInfo->mChannels,
codecInfo->mRate,
codecInfo->mLoadManager);
codecInfo->mRate);
mRecvCodecList.push_back(cdcConfig);
return true;
}

View File

@ -11,8 +11,6 @@
namespace mozilla {
class LoadManager;
/**
* Minimalistic Audio Codec Config Params
*/
@ -28,22 +26,19 @@ struct AudioCodecConfig
int mPacSize;
int mChannels;
int mRate;
LoadManager* mLoadManager;
/* Default constructor is not provided since as a consumer, we
* can't decide the default configuration for the codec
*/
explicit AudioCodecConfig(int type, std::string name,
int freq,int pacSize,
int channels, int rate,
LoadManager* load_manager = nullptr)
int channels, int rate)
: mType(type),
mName(name),
mFreq(freq),
mPacSize(pacSize),
mChannels(channels),
mRate(rate),
mLoadManager(load_manager)
mRate(rate)
{
}
@ -65,7 +60,6 @@ struct VideoCodecConfig
uint32_t mRtcpFbTypes;
unsigned int mMaxFrameSize;
unsigned int mMaxFrameRate;
LoadManager* mLoadManager;
uint8_t mProfile;
uint8_t mConstraints;
uint8_t mLevel;
@ -75,7 +69,6 @@ struct VideoCodecConfig
VideoCodecConfig(int type,
std::string name,
int rtcpFbTypes,
LoadManager* load_manager = nullptr,
uint8_t profile = 0x42,
uint8_t constraints = 0xC0,
uint8_t level = 30,
@ -85,7 +78,6 @@ struct VideoCodecConfig
mRtcpFbTypes(rtcpFbTypes),
mMaxFrameSize(0),
mMaxFrameRate(0),
mLoadManager(load_manager),
mProfile(profile),
mConstraints(constraints),
mLevel(level),
@ -95,14 +87,12 @@ struct VideoCodecConfig
std::string name,
int rtcpFbTypes,
unsigned int max_fs,
unsigned int max_fr,
LoadManager* load_manager = nullptr) :
unsigned int max_fr) :
mType(type),
mName(name),
mRtcpFbTypes(rtcpFbTypes),
mMaxFrameSize(max_fs),
mMaxFrameRate(max_fr),
mLoadManager(load_manager) {}
mMaxFrameRate(max_fr) {}
bool RtcpFbIsSet(sdp_rtcp_fb_nack_type_e type) const
{

View File

@ -275,6 +275,11 @@ MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
if (temp >= 0) {
mMaxBitrate = temp;
}
bool use_loadmanager = false;
NS_WARN_IF(NS_FAILED(branch->GetBoolPref("media.navigator.load_adapt", &use_loadmanager)));
if (use_loadmanager) {
mLoadManager = LoadManagerBuild();
}
}
}
#endif
@ -552,9 +557,9 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
mEngineTransmitting = false;
}
if (codecConfig->mLoadManager) {
mPtrViEBase->RegisterCpuOveruseObserver(mChannel, codecConfig->mLoadManager);
mPtrViEBase->SetLoadManager(codecConfig->mLoadManager);
if (mLoadManager) {
mPtrViEBase->RegisterCpuOveruseObserver(mChannel, mLoadManager);
mPtrViEBase->SetLoadManager(mLoadManager);
}
if (mExternalSendCodec &&

View File

@ -11,6 +11,7 @@
#include "MediaConduitInterface.h"
#include "MediaEngineWrapper.h"
#include "CodecStatistics.h"
#include "LoadManagerFactory.h"
// conflicts with #include of scoped_ptr.h
#undef FF
@ -358,6 +359,8 @@ private:
// statistics object for video codec;
nsAutoPtr<VideoCodecStatistics> mVideoCodecStat;
nsAutoPtr<LoadManager> mLoadManager;
};
} // end namespace

View File

@ -1692,8 +1692,7 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
payloads[i].audio.frequency,
payloads[i].audio.packet_size,
payloads[i].audio.channels,
payloads[i].audio.bitrate,
pc.impl()->load_manager());
payloads[i].audio.bitrate);
configs.push_back(config_raw);
}
@ -1750,8 +1749,7 @@ static int vcmRxStartICE_m(cc_mcapid_t mcap_id,
config_raw = new mozilla::VideoCodecConfig(
payloads[i].remote_rtp_pt,
ccsdpCodecName(payloads[i].codec_type),
payloads[i].video.rtcp_fb_types,
pc.impl()->load_manager());
payloads[i].video.rtcp_fb_types);
if (vcmEnsureExternalCodec(conduit, config_raw, false)) {
continue;
}
@ -2350,8 +2348,7 @@ static int vcmTxCreateAudioConduit(int level,
payload->audio.frequency,
payload->audio.packet_size,
payload->audio.channels,
payload->audio.bitrate,
pc.impl()->load_manager());
payload->audio.bitrate);
// Take possession of this pointer
mozilla::ScopedDeletePtr<mozilla::AudioCodecConfig> config(config_raw);
@ -2398,8 +2395,7 @@ static int vcmTxCreateVideoConduit(int level,
ccsdpCodecName(payload->codec_type),
payload->video.rtcp_fb_types,
payload->video.max_fs,
payload->video.max_fr,
pc.impl()->load_manager());
payload->video.max_fr);
// Take possession of this pointer
mozilla::ScopedDeletePtr<mozilla::VideoCodecConfig> config(config_raw);

View File

@ -489,7 +489,6 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
, mWindow(nullptr)
, mIdentity(nullptr)
, mSTSThread(nullptr)
, mLoadManager(nullptr)
, mMedia(nullptr)
, mNumAudioStreams(0)
, mNumVideoStreams(0)
@ -538,10 +537,6 @@ PeerConnectionImpl::~PeerConnectionImpl()
shutdown(calledFromObject);
}
}
if (mLoadManager) {
mozilla::LoadManagerDestroy(mLoadManager);
mLoadManager = nullptr;
}
#endif
// Since this and Initialize() occur on MainThread, they can't both be
@ -877,12 +872,6 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
return res;
}
#ifdef MOZILLA_INTERNAL_API
if (mozilla::Preferences::GetBool("media.navigator.load_adapt", false)) {
mLoadManager = mozilla::LoadManagerBuild();
}
#endif
return NS_OK;
}

View File

@ -27,7 +27,6 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PeerConnectionImplEnumsBinding.h"
#include "StreamBuffer.h"
#include "LoadManagerFactory.h"
#ifdef MOZILLA_INTERNAL_API
#include "mozilla/TimeStamp.h"
@ -254,10 +253,6 @@ public:
return mMedia;
}
mozilla::LoadManager* load_manager() {
return mLoadManager;
}
// Handle system to allow weak references to be passed through C code
virtual const std::string& GetHandle();
@ -694,9 +689,6 @@ private:
// The target to run stuff on
nsCOMPtr<nsIEventTarget> mSTSThread;
// CPU Load adaptation stuff
mozilla::LoadManager* mLoadManager;
#ifdef MOZILLA_INTERNAL_API
// DataConnection that's used to get all the DataChannels
nsRefPtr<mozilla::DataChannelConnection> mDataConnection;

View File

@ -812,7 +812,7 @@ class TransportConduitTest : public ::testing::Test
ASSERT_NE(mVideoSession, (void*)nullptr);
// Configure send codecs on the conduit.
mozilla::VideoCodecConfig cinst1(120, "VP8", 0, max_fs, 0);
mozilla::VideoCodecConfig cinst1(120, "VP8", 0, max_fs);
err = mVideoSession->ConfigureSendMediaCodec(&cinst1);
ASSERT_EQ(mozilla::kMediaConduitNoError, err);