Bug 1482109 - Add a generic MemoryPressureObserver. r=sotaro
authorNicolas Silva <nsilva@mozilla.com>
Fri, 10 Aug 2018 17:15:02 +0200
changeset 431011 287b6b052c20c5a0d38f9e6a99ac6c386ac88e93
parent 431010 402e309359419e325967c42a51beeb97eb0971b9
child 431012 6c09f894ccf18ccd3b472cc2810fa9811429a224
push id34419
push userbtara@mozilla.com
push dateSat, 11 Aug 2018 03:43:33 +0000
treeherdermozilla-central@7ed5ed3d4814 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1482109
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1482109 - Add a generic MemoryPressureObserver. r=sotaro
gfx/layers/MemoryPressureObserver.cpp
gfx/layers/MemoryPressureObserver.h
gfx/layers/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/layers/MemoryPressureObserver.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "MemoryPressureObserver.h"
+
+namespace mozilla {
+namespace layers {
+
+MemoryPressureObserver::MemoryPressureObserver(MemoryPressureListener* aListener)
+: mListener(aListener)
+{}
+
+MemoryPressureObserver::~MemoryPressureObserver()
+{
+  // If this assertion is hit we probably forgot to unregister the observer.
+  MOZ_ASSERT(!mListener);
+}
+
+already_AddRefed<MemoryPressureObserver>
+MemoryPressureObserver::Create(MemoryPressureListener* aListener)
+{
+  nsCOMPtr<nsIObserverService> service = services::GetObserverService();
+
+  if (!service) {
+    return nullptr;
+  }
+
+  RefPtr<MemoryPressureObserver> observer = new MemoryPressureObserver(aListener);
+
+  bool useWeakRef = false;
+  service->AddObserver(observer, "memory-pressure", useWeakRef);
+
+  return observer.forget();
+}
+
+void
+MemoryPressureObserver::Unregister()
+{
+  if (!mListener) {
+    return;
+  }
+
+  nsCOMPtr<nsIObserverService> service = services::GetObserverService();
+  if (service) {
+    service->RemoveObserver(this, "memory-pressure");
+  }
+
+  mListener = nullptr;
+}
+
+NS_IMETHODIMP
+MemoryPressureObserver::Observe(nsISupports* aSubject,
+                                const char* aTopic,
+                                const char16_t* aData)
+{
+  if (mListener && strcmp(aTopic, "memory-pressure")) {
+    MemoryPressureReason reason = MemoryPressureReason::LOW_MEMORY;
+    auto reason_string = nsDependentString(aData);
+    if (StringBeginsWith(reason_string, NS_LITERAL_STRING("low-memory-ongoing"))) {
+        reason = MemoryPressureReason::LOW_MEMORY_ONGOING;
+    } else if (StringBeginsWith(reason_string, NS_LITERAL_STRING("heap-minimize"))) {
+        reason = MemoryPressureReason::HEAP_MINIMIZE;
+    }
+    mListener->OnMemoryPressure(reason);
+  }
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(MemoryPressureObserver, nsIObserver)
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/MemoryPressureObserver.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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/. */
+
+#ifndef MOZILLA_LAYERS_MEMORYPRESSUREOBSERVER_H
+#define MOZILLA_LAYERS_MEMORYPRESSUREOBSERVER_H
+
+#include "nsIObserver.h"
+
+namespace mozilla {
+namespace layers {
+
+// A simple memory pressure observer implementation born out of the realization
+// that almost all of our memory pressure observers do exactly the same thing.
+//
+// The intended way to use it is to have the class that nees to react on memory
+// pressure inherit the MemoryPressureListener interface and own a strong
+// reference to a MemoryPressureListener object.
+// Call Unregister on the listener in the destructor of your class or whenever
+// you do not which to receive the notification anymore, otherwise the listener
+// will be held alive by the observer service (leak) and keep a dangling pointer
+// to your class.
+
+/// See nsIMemory.idl
+enum class MemoryPressureReason {
+    LOW_MEMORY,
+    LOW_MEMORY_ONGOING,
+    HEAP_MINIMIZE,
+};
+
+class MemoryPressureListener {
+public:
+  virtual void OnMemoryPressure(MemoryPressureReason aWhy) = 0;
+};
+
+class MemoryPressureObserver final : public nsIObserver {
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  // Returns null if anything goes wrong.
+  static already_AddRefed<MemoryPressureObserver>
+  Create(MemoryPressureListener* aListener);
+
+  void Unregister();
+
+private:
+  explicit MemoryPressureObserver(MemoryPressureListener* aListener);
+  virtual ~MemoryPressureObserver();
+  MemoryPressureListener* mListener;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -203,16 +203,17 @@ EXPORTS.mozilla.layers += [
     'ipc/UiCompositorControllerMessageTypes.h',
     'ipc/UiCompositorControllerParent.h',
     'ipc/VideoBridgeChild.h',
     'ipc/VideoBridgeParent.h',
     'LayerAttributes.h',
     'LayerMetricsWrapper.h',
     'LayersHelpers.h',
     'LayersTypes.h',
+    'MemoryPressureObserver.h',
     'mlgpu/LayerManagerMLGPU.h',
     'mlgpu/LayerMLGPU.h',
     'mlgpu/MemoryReportingMLGPU.h',
     'mlgpu/MLGDevice.h',
     'mlgpu/MLGDeviceTypes.h',
     'mlgpu/ShaderDefinitionsMLGPU.h',
     'mlgpu/UtilityMLGPU.h',
     'opengl/CompositingRenderTargetOGL.h',
@@ -435,16 +436,17 @@ UNIFIED_SOURCES += [
     'ipc/VideoBridgeParent.cpp',
     'Layers.cpp',
     'LayerScope.cpp',
     'LayersHelpers.cpp',
     'LayersLogging.cpp',
     'LayerSorter.cpp',
     'LayersTypes.cpp',
     'LayerTreeInvalidation.cpp',
+    'MemoryPressureObserver.cpp',
     'mlgpu/BufferCache.cpp',
     'mlgpu/CanvasLayerMLGPU.cpp',
     'mlgpu/ContainerLayerMLGPU.cpp',
     'mlgpu/FrameBuilder.cpp',
     'mlgpu/ImageLayerMLGPU.cpp',
     'mlgpu/LayerManagerMLGPU.cpp',
     'mlgpu/LayerMLGPU.cpp',
     'mlgpu/MaskOperation.cpp',