Browse Source

Merge pull request #9214 from electron/app-memoryinfo

API to get memory of all processes of the app
Kevin Sawicki 8 years ago
parent
commit
59511354fd

+ 55 - 2
atom/browser/api/atom_api_app.cc

@@ -34,12 +34,12 @@
 #include "chrome/browser/icon_manager.h"
 #include "chrome/common/chrome_paths.h"
 #include "content/public/browser/browser_accessibility_state.h"
+#include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/client_certificate_delegate.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/common/content_switches.h"
 #include "media/audio/audio_manager.h"
-#include "native_mate/dictionary.h"
 #include "native_mate/object_template_builder.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -337,6 +337,17 @@ namespace api {
 
 namespace {
 
+class AppIdProcessIterator : public base::ProcessIterator {
+ public:
+  AppIdProcessIterator() : base::ProcessIterator(nullptr) {}
+
+ protected:
+  bool IncludeEntry() override {
+    return (entry().parent_pid() == base::GetCurrentProcId() ||
+            entry().pid() == base::GetCurrentProcId());
+  }
+};
+
 IconLoader::IconSize GetIconSizeByString(const std::string& size) {
   if (size == "small") {
     return IconLoader::IconSize::SMALL;
@@ -912,6 +923,47 @@ void App::GetFileIcon(const base::FilePath& path,
   }
 }
 
+std::vector<mate::Dictionary> App::GetAppMemoryInfo(v8::Isolate* isolate) {
+  AppIdProcessIterator process_iterator;
+  auto process_entry = process_iterator.NextProcessEntry();
+  std::vector<mate::Dictionary> result;
+
+  while (process_entry != nullptr) {
+    int64_t pid = process_entry->pid();
+    auto process = base::Process::OpenWithExtraPrivileges(pid);
+
+#if defined(OS_MACOSX)
+    std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+        process.Handle(), content::BrowserChildProcessHost::GetPortProvider()));
+#else
+    std::unique_ptr<base::ProcessMetrics> metrics(
+      base::ProcessMetrics::CreateProcessMetrics(process.Handle()));
+#endif
+
+    mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate);
+    mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate);
+
+    memory_dict.Set("workingSetSize",
+            static_cast<double>(metrics->GetWorkingSetSize() >> 10));
+    memory_dict.Set("peakWorkingSetSize",
+            static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10));
+
+    size_t private_bytes, shared_bytes;
+    if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) {
+      memory_dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
+      memory_dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
+    }
+
+    pid_dict.Set("memory", memory_dict);
+    pid_dict.Set("pid", pid);
+    result.push_back(pid_dict);
+    process_entry = process_iterator.NextProcessEntry();
+  }
+
+  return result;
+}
+
 // static
 mate::Handle<App> App::Create(v8::Isolate* isolate) {
   return mate::CreateHandle(isolate, new App(isolate));
@@ -983,7 +1035,8 @@ void App::BuildPrototype(
                  &App::IsAccessibilitySupportEnabled)
       .SetMethod("disableHardwareAcceleration",
                  &App::DisableHardwareAcceleration)
-      .SetMethod("getFileIcon", &App::GetFileIcon);
+      .SetMethod("getFileIcon", &App::GetFileIcon)
+      .SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo);
 }
 
 }  // namespace api

+ 4 - 0
atom/browser/api/atom_api_app.h

@@ -13,10 +13,12 @@
 #include "atom/browser/browser.h"
 #include "atom/browser/browser_observer.h"
 #include "atom/common/native_mate_converters/callback.h"
+#include "base/process/process_iterator.h"
 #include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/icon_manager.h"
 #include "chrome/browser/process_singleton.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
+#include "native_mate/dictionary.h"
 #include "native_mate/handle.h"
 #include "net/base/completion_callback.h"
 
@@ -141,6 +143,8 @@ class App : public AtomBrowserClient::Delegate,
   void GetFileIcon(const base::FilePath& path,
                    mate::Arguments* args);
 
+  std::vector<mate::Dictionary> GetAppMemoryInfo(v8::Isolate* isolate);
+
 #if defined(OS_WIN)
   // Get the current Jump List settings.
   v8::Local<v8::Value> GetJumpListSettings();

+ 4 - 0
docs/api/app.md

@@ -760,6 +760,10 @@ Disables hardware acceleration for current app.
 
 This method can only be called before app is ready.
 
+### `app.getAppMemoryInfo()`
+
+Returns [ProcessMemoryInfo[]](structures/process-memory-info.md):  Array of `ProcessMemoryInfo` objects that correspond to memory usage statistics of all the processes associated with the app.
+
 ### `app.setBadgeCount(count)` _Linux_ _macOS_
 
 * `count` Integer

+ 12 - 0
docs/api/structures/memory-info.md

@@ -0,0 +1,12 @@
+# MemoryInfo Object
+
+* `workingSetSize` Integer - Process id of the process.
+* `workingSetSize` Integer - The amount of memory currently pinned to actual physical RAM.
+* `peakWorkingSetSize` Integer - The maximum amount of memory that has ever been pinned
+  to actual physical RAM.
+* `privateBytes` Integer - The amount of memory not shared by other processes, such as
+  JS heap or HTML content.
+* `sharedBytes` Integer - The amount of memory shared between processes, typically
+  memory consumed by the Electron code itself
+
+Note that all statistics are reported in Kilobytes.

+ 4 - 0
docs/api/structures/process-memory-info.md

@@ -0,0 +1,4 @@
+# ProcessMemoryInfo Object
+
+* `pid` Integer - Process id of the process.
+* `memory` [MemoryInfo](memory-info.md) - Memory information of the process.

+ 13 - 0
spec/api-app-spec.js

@@ -533,4 +533,17 @@ describe('app module', function () {
       })
     })
   })
+
+  describe('getAppMemoryInfo() API', function () {
+    it('returns the process memory of all running electron processes', function () {
+      const appMemoryInfo = app.getAppMemoryInfo()
+      assert.ok(appMemoryInfo.length > 0, 'App memory info object is not > 0')
+      for (const {memory, pid} of appMemoryInfo) {
+        assert.ok(memory.workingSetSize > 0, 'working set size is not > 0')
+        assert.ok(memory.privateBytes > 0, 'private bytes is not > 0')
+        assert.ok(memory.sharedBytes > 0, 'shared bytes is not > 0')
+        assert.ok(pid > 0, 'pid is not > 0')
+      }
+    })
+  })
 })