diff --git a/content/media/webrtc/LoadManagerFactory.cpp b/content/media/webrtc/LoadManagerFactory.cpp index e7d21cf10f0a..c49ecc226a2a 100644 --- a/content/media/webrtc/LoadManagerFactory.cpp +++ b/content/media/webrtc/LoadManagerFactory.cpp @@ -15,7 +15,6 @@ LoadManager* LoadManagerBuild(void) { MOZ_ASSERT(NS_IsMainThread()); -#if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX) int loadMeasurementInterval = mozilla::Preferences::GetInt("media.navigator.load_adapt.measure_interval", 1000); int averagingSeconds = @@ -29,10 +28,6 @@ LoadManager* LoadManagerBuild(void) averagingSeconds, highLoadThreshold, lowLoadThreshold); -#else - // LoadManager not implemented on this platform. - return nullptr; -#endif } void LoadManagerDestroy(mozilla::LoadManager* aLoadManager) diff --git a/content/media/webrtc/LoadMonitor.cpp b/content/media/webrtc/LoadMonitor.cpp index 696f7580f369..4fe128b0d0ab 100644 --- a/content/media/webrtc/LoadMonitor.cpp +++ b/content/media/webrtc/LoadMonitor.cpp @@ -29,13 +29,19 @@ #include #endif -#if defined(XP_MACOSX) +#ifdef XP_MACOSX #include #include #include #include #endif +#ifdef XP_WIN +#include +#include +#pragma comment(lib, "pdh.lib") +#endif + // NSPR_LOG_MODULES=LoadManager:5 #undef LOG #undef LOG_ENABLED @@ -148,6 +154,109 @@ void LoadMonitor::Shutdown() } } +#ifdef XP_WIN +static LPCTSTR TotalCounterPath = _T("\\Processor(_Total)\\% Processor Time"); + +class WinProcMon +{ +public: + WinProcMon(): + mQuery(0), mCounter(0) {}; + ~WinProcMon(); + nsresult Init(); + nsresult QuerySystemLoad(float* load_percent); + static const uint64_t TicksPerSec = 10000000; //100nsec tick (10MHz) +private: + PDH_HQUERY mQuery; + PDH_HCOUNTER mCounter; +}; + +WinProcMon::~WinProcMon() +{ + if (mQuery != 0) { + PdhCloseQuery(mQuery); + mQuery = 0; + } +} + +nsresult +WinProcMon::Init() +{ + PDH_HQUERY query; + PDH_HCOUNTER counter; + + // Get a query handle to the Performance Data Helper + PDH_STATUS status = PdhOpenQuery( + NULL, // No log file name: use real-time source + 0, // zero out user data token: unsued + &query); + + if (status != ERROR_SUCCESS) { + LOG(("PdhOpenQuery error = %X", status)); + return NS_ERROR_FAILURE; + } + + // Add a pre-defined high performance counter to the query. + // This one is for the total CPU usage. + status = PdhAddCounter(query, TotalCounterPath, 0, &counter); + + if (status != ERROR_SUCCESS) { + PdhCloseQuery(query); + LOG(("PdhAddCounter (_Total) error = %X", status)); + return NS_ERROR_FAILURE; + } + + // Need to make an initial query call to set up data capture. + status = PdhCollectQueryData(query); + + if (status != ERROR_SUCCESS) { + PdhCloseQuery(query); + LOG(("PdhCollectQueryData (init) error = %X", status)); + return NS_ERROR_FAILURE; + } + + mQuery = query; + mCounter = counter; + return NS_OK; +} + +nsresult WinProcMon::QuerySystemLoad(float* load_percent) +{ + *load_percent = 0; + + if (mQuery == 0) { + return NS_ERROR_FAILURE; + } + + // Update all counters associated with this query object. + PDH_STATUS status = PdhCollectQueryData(mQuery); + + if (status != ERROR_SUCCESS) { + LOG(("PdhCollectQueryData error = %X", status)); + return NS_ERROR_FAILURE; + } + + PDH_FMT_COUNTERVALUE counter; + // maximum is 100% regardless of CPU core count. + status = PdhGetFormattedCounterValue( + mCounter, + PDH_FMT_DOUBLE, + (LPDWORD)NULL, + &counter); + + if (ERROR_SUCCESS != status || + // There are multiple success return values. + !IsSuccessSeverity(counter.CStatus)) { + LOG(("PdhGetFormattedCounterValue error")); + return NS_ERROR_FAILURE; + } + + // The result is a percent value, reduce to match expected scale. + *load_percent = (float)(counter.doubleValue / 100.0f); + return NS_OK; +} +#endif + class LoadStats { public: @@ -167,7 +276,8 @@ class LoadInfo : public mozilla::RefCounted { public: MOZ_DECLARE_REFCOUNTED_TYPENAME(LoadInfo) - LoadInfo(int aLoadUpdateInterval); + LoadInfo(): mLoadUpdateInterval(0) {}; + nsresult Init(int aLoadUpdateInterval); double GetSystemLoad() { return mSystemLoad.GetLoad(); }; double GetProcessLoad() { return mProcessLoad.GetLoad(); }; nsresult UpdateSystemLoad(); @@ -178,17 +288,29 @@ private: uint64_t current_total_times, uint64_t current_cpu_times, LoadStats* loadStat); +#ifdef XP_WIN + WinProcMon mSysMon; + HANDLE mProcHandle; + int mNumProcessors; +#endif LoadStats mSystemLoad; LoadStats mProcessLoad; uint64_t mTicksPerInterval; int mLoadUpdateInterval; }; -LoadInfo::LoadInfo(int aLoadUpdateInterval) - : mLoadUpdateInterval(aLoadUpdateInterval) +nsresult LoadInfo::Init(int aLoadUpdateInterval) { -#if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX) + mLoadUpdateInterval = aLoadUpdateInterval; +#ifdef XP_WIN + mTicksPerInterval = (WinProcMon::TicksPerSec /*Hz*/ + * mLoadUpdateInterval /*msec*/) / 1000 ; + mNumProcessors = PR_GetNumberOfProcessors(); + mProcHandle = GetCurrentProcess(); + return mSysMon.Init(); +#else mTicksPerInterval = (sysconf(_SC_CLK_TCK) * mLoadUpdateInterval) / 1000; + return NS_OK; #endif } @@ -196,10 +318,9 @@ void LoadInfo::UpdateCpuLoad(uint64_t ticks_per_interval, uint64_t current_total_times, uint64_t current_cpu_times, LoadStats *loadStat) { - // Check if we get an inconsistent number of ticks. if (((current_total_times - loadStat->mPrevTotalTimes) - > (ticks_per_interval * 10)) + > (ticks_per_interval * 10)) || current_total_times < loadStat->mPrevTotalTimes || current_cpu_times < loadStat->mPrevCpuTimes) { // Bug at least on the Nexus 4 and Galaxy S4 @@ -217,7 +338,11 @@ void LoadInfo::UpdateCpuLoad(uint64_t ticks_per_interval, const uint64_t cpu_diff = current_cpu_times - loadStat->mPrevCpuTimes; const uint64_t total_diff = current_total_times - loadStat->mPrevTotalTimes; if (total_diff > 0) { +#ifdef XP_WIN + float result = (float)cpu_diff / (float)total_diff/ (float)mNumProcessors; +#else float result = (float)cpu_diff / (float)total_diff; +#endif loadStat->mPrevLoad = result; } loadStat->mPrevTotalTimes = current_total_times; @@ -282,6 +407,15 @@ nsresult LoadInfo::UpdateSystemLoad() cpu_times, &mSystemLoad); return NS_OK; +#elif defined(XP_WIN) + float load; + nsresult rv = mSysMon.QuerySystemLoad(&load); + + if (rv == NS_OK) { + mSystemLoad.mPrevLoad = load; + } + + return rv; #else // Not implemented return NS_OK; @@ -308,7 +442,29 @@ nsresult LoadInfo::UpdateProcessLoad() { total_times, cpu_times, &mProcessLoad); -#endif // defined(LINUX) || defined(ANDROID) || defined(XP_MACOSX) +#elif defined(XP_WIN) + FILETIME clk_time, sys_time, user_time; + uint64_t total_times, cpu_times; + + GetSystemTimeAsFileTime(&clk_time); + total_times = (((uint64_t)clk_time.dwHighDateTime) << 32) + + (uint64_t)clk_time.dwLowDateTime; + BOOL ok = GetProcessTimes(mProcHandle, &clk_time, &clk_time, &sys_time, &user_time); + + if (ok == 0) { + return NS_ERROR_FAILURE; + } + + cpu_times = (((uint64_t)sys_time.dwHighDateTime + + (uint64_t)user_time.dwHighDateTime) << 32) + + (uint64_t)sys_time.dwLowDateTime + + (uint64_t)user_time.dwLowDateTime; + + UpdateCpuLoad(mTicksPerInterval, + total_times, + cpu_times, + &mProcessLoad); +#endif return NS_OK; } @@ -316,12 +472,12 @@ class LoadInfoCollectRunner : public nsRunnable { public: LoadInfoCollectRunner(nsRefPtr loadMonitor, - int aLoadUpdateInterval) - : mLoadUpdateInterval(aLoadUpdateInterval), + RefPtr loadInfo) + : mLoadUpdateInterval(loadMonitor->mLoadUpdateInterval), mLoadNoiseCounter(0) { mLoadMonitor = loadMonitor; - mLoadInfo = new LoadInfo(mLoadUpdateInterval); + mLoadInfo = loadInfo; } NS_IMETHOD Run() @@ -332,6 +488,7 @@ public: mLoadInfo->UpdateProcessLoad(); float sysLoad = mLoadInfo->GetSystemLoad(); float procLoad = mLoadInfo->GetProcessLoad(); + if ((++mLoadNoiseCounter % (LOG_MANY_ENABLED() ? 1 : 10)) == 0) { LOG(("System Load: %f Process Load: %f", sysLoad, procLoad)); mLoadNoiseCounter = 0; @@ -390,16 +547,22 @@ LoadMonitor::Init(nsRefPtr &self) { LOG(("Initializing LoadMonitor")); -#if defined(ANDROID) || defined(LINUX) || defined(XP_MACOSX) + RefPtr load_info = new LoadInfo(); + nsresult rv = load_info->Init(mLoadUpdateInterval); + + if (NS_FAILED(rv)) { + LOG(("LoadInfo::Init error")); + return rv; + } + nsRefPtr addObsRunner = new LoadMonitorAddObserver(self); NS_DispatchToMainThread(addObsRunner, NS_DISPATCH_NORMAL); NS_NewNamedThread("Sys Load Info", getter_AddRefs(mLoadInfoThread)); nsRefPtr runner = - new LoadInfoCollectRunner(self, mLoadUpdateInterval); + new LoadInfoCollectRunner(self, load_info); mLoadInfoThread->Dispatch(runner, NS_DISPATCH_NORMAL); -#endif return NS_OK; } diff --git a/content/media/webrtc/moz.build b/content/media/webrtc/moz.build index fe8d7c1b83c6..f1d82ed99f4b 100644 --- a/content/media/webrtc/moz.build +++ b/content/media/webrtc/moz.build @@ -19,16 +19,13 @@ if CONFIG['MOZ_WEBRTC']: 'LoadMonitor.h', 'MediaEngineWebRTC.h'] UNIFIED_SOURCES += [ + 'LoadManager.cpp', 'LoadManagerFactory.cpp', + 'LoadMonitor.cpp', 'MediaEngineTabVideoSource.cpp', 'MediaEngineWebRTCAudio.cpp', 'MediaEngineWebRTCVideo.cpp', ] - if CONFIG['OS_ARCH'] == 'Android' or CONFIG['OS_ARCH'] == 'Linux' or CONFIG['OS_ARCH'] == 'Darwin': - UNIFIED_SOURCES += [ - 'LoadManager.cpp', - 'LoadMonitor.cpp', - ] # MediaEngineWebRTC.cpp needs to be built separately. SOURCES += [ 'MediaEngineWebRTC.cpp',