LoadManager.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "LoadManager.h"
  6. #include "LoadMonitor.h"
  7. #include "nsString.h"
  8. #include "mozilla/Logging.h"
  9. #include "prtime.h"
  10. #include "prinrval.h"
  11. #include "prsystem.h"
  12. #include "nsString.h"
  13. #include "nsThreadUtils.h"
  14. #include "nsReadableUtils.h"
  15. #include "nsIObserverService.h"
  16. #include "mozilla/ArrayUtils.h"
  17. // MOZ_LOG=LoadManager:5
  18. mozilla::LazyLogModule gLoadManagerLog("LoadManager");
  19. #undef LOG
  20. #undef LOG_ENABLED
  21. #define LOG(args) MOZ_LOG(gLoadManagerLog, mozilla::LogLevel::Debug, args)
  22. #define LOG_ENABLED() MOZ_LOG_TEST(gLoadManagerLog, mozilla::LogLevel::Verbose)
  23. namespace mozilla {
  24. /* static */ StaticRefPtr<LoadManagerSingleton> LoadManagerSingleton::sSingleton;
  25. NS_IMPL_ISUPPORTS(LoadManagerSingleton, nsIObserver)
  26. LoadManagerSingleton::LoadManagerSingleton(bool aEncoderOnly,
  27. int aLoadMeasurementInterval,
  28. int aAveragingMeasurements,
  29. float aHighLoadThreshold,
  30. float aLowLoadThreshold)
  31. : mLock("LoadManager"),
  32. mCurrentState(webrtc::kLoadNormal),
  33. mOveruseActive(false),
  34. mLoadSum(0.0f),
  35. mLoadSumMeasurements(0),
  36. mLoadMeasurementInterval(aLoadMeasurementInterval),
  37. mAveragingMeasurements(aAveragingMeasurements),
  38. mHighLoadThreshold(aHighLoadThreshold),
  39. mLowLoadThreshold(aLowLoadThreshold)
  40. {
  41. LOG(("LoadManager - Initializing (%dms x %d, %f, %f)",
  42. mLoadMeasurementInterval, mAveragingMeasurements,
  43. mHighLoadThreshold, mLowLoadThreshold));
  44. MOZ_ASSERT(mHighLoadThreshold > mLowLoadThreshold);
  45. if (!aEncoderOnly) {
  46. mLoadMonitor = new LoadMonitor(mLoadMeasurementInterval);
  47. mLoadMonitor->Init(mLoadMonitor);
  48. mLoadMonitor->SetLoadChangeCallback(this);
  49. }
  50. mLastStateChange = TimeStamp::Now();
  51. for (auto &in_state : mTimeInState) {
  52. in_state = 0;
  53. }
  54. }
  55. LoadManagerSingleton::~LoadManagerSingleton()
  56. {
  57. LOG(("LoadManager: shutting down LoadMonitor"));
  58. MOZ_ASSERT(!mLoadMonitor, "why wasn't the LoadMonitor shut down in xpcom-shutdown?");
  59. if (mLoadMonitor) {
  60. mLoadMonitor->Shutdown();
  61. }
  62. }
  63. nsresult
  64. LoadManagerSingleton::Observe(nsISupports* aSubject, const char* aTopic,
  65. const char16_t* aData)
  66. {
  67. NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
  68. nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  69. if (!strcmp(aTopic, "xpcom-shutdown")) {
  70. obs->RemoveObserver(this, "xpcom-shutdown");
  71. {
  72. MutexAutoLock lock(mLock);
  73. mObservers.Clear();
  74. }
  75. if (mLoadMonitor) {
  76. mLoadMonitor->Shutdown();
  77. mLoadMonitor = nullptr;
  78. }
  79. LOG(("Releasing LoadManager singleton and thread"));
  80. // Note: won't be released immediately as the Observer has a ref to us
  81. sSingleton = nullptr;
  82. }
  83. return NS_OK;
  84. }
  85. void
  86. LoadManagerSingleton::LoadChanged(float aSystemLoad, float aProcesLoad)
  87. {
  88. MutexAutoLock lock(mLock);
  89. // Update total load, and total amount of measured seconds.
  90. mLoadSum += aSystemLoad;
  91. mLoadSumMeasurements++;
  92. if (mLoadSumMeasurements >= mAveragingMeasurements) {
  93. double averagedLoad = mLoadSum / (float)mLoadSumMeasurements;
  94. webrtc::CPULoadState newState = mCurrentState;
  95. if (mOveruseActive || averagedLoad > mHighLoadThreshold) {
  96. LOG(("LoadManager - LoadStressed"));
  97. newState = webrtc::kLoadStressed;
  98. } else if (averagedLoad < mLowLoadThreshold) {
  99. LOG(("LoadManager - LoadRelaxed"));
  100. newState = webrtc::kLoadRelaxed;
  101. } else {
  102. LOG(("LoadManager - LoadNormal"));
  103. newState = webrtc::kLoadNormal;
  104. }
  105. if (newState != mCurrentState) {
  106. LoadHasChanged(newState);
  107. }
  108. mLoadSum = 0;
  109. mLoadSumMeasurements = 0;
  110. }
  111. }
  112. void
  113. LoadManagerSingleton::OveruseDetected()
  114. {
  115. LOG(("LoadManager - Overuse Detected"));
  116. MutexAutoLock lock(mLock);
  117. mOveruseActive = true;
  118. if (mCurrentState != webrtc::kLoadStressed) {
  119. LoadHasChanged(webrtc::kLoadStressed);
  120. }
  121. }
  122. void
  123. LoadManagerSingleton::NormalUsage()
  124. {
  125. LOG(("LoadManager - Overuse finished"));
  126. MutexAutoLock lock(mLock);
  127. mOveruseActive = false;
  128. }
  129. void
  130. LoadManagerSingleton::LoadHasChanged(webrtc::CPULoadState aNewState)
  131. {
  132. mLock.AssertCurrentThreadOwns();
  133. LOG(("LoadManager - Signaling LoadHasChanged from %d to %d to %d listeners",
  134. mCurrentState, aNewState, mObservers.Length()));
  135. // Record how long we spent in this state for later Telemetry or display
  136. TimeStamp now = TimeStamp::Now();
  137. mTimeInState[mCurrentState] += (now - mLastStateChange).ToMilliseconds();
  138. mLastStateChange = now;
  139. mCurrentState = aNewState;
  140. for (size_t i = 0; i < mObservers.Length(); i++) {
  141. mObservers.ElementAt(i)->onLoadStateChanged(mCurrentState);
  142. }
  143. }
  144. void
  145. LoadManagerSingleton::AddObserver(webrtc::CPULoadStateObserver * aObserver)
  146. {
  147. LOG(("LoadManager - Adding Observer"));
  148. MutexAutoLock lock(mLock);
  149. mObservers.AppendElement(aObserver);
  150. }
  151. void
  152. LoadManagerSingleton::RemoveObserver(webrtc::CPULoadStateObserver * aObserver)
  153. {
  154. LOG(("LoadManager - Removing Observer"));
  155. MutexAutoLock lock(mLock);
  156. if (!mObservers.RemoveElement(aObserver)) {
  157. LOG(("LoadManager - Element to remove not found"));
  158. }
  159. if (mObservers.Length() == 0) {
  160. // Record how long we spent in the final state for later Telemetry or display
  161. TimeStamp now = TimeStamp::Now();
  162. mTimeInState[mCurrentState] += (now - mLastStateChange).ToMilliseconds();
  163. float total = 0;
  164. for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mTimeInState); i++) {
  165. total += mTimeInState[i];
  166. }
  167. for (auto &in_state : mTimeInState) {
  168. in_state = 0;
  169. }
  170. if (mLoadMonitor) {
  171. // Dance to avoid deadlock on mLock!
  172. RefPtr<LoadMonitor> loadMonitor = mLoadMonitor.forget();
  173. MutexAutoUnlock unlock(mLock);
  174. loadMonitor->Shutdown();
  175. }
  176. }
  177. }
  178. }