From 939747945e114688355b9fa4bca410076c6628c6 Mon Sep 17 00:00:00 2001 From: Hari Juturu Date: Mon, 15 May 2017 17:41:45 -0700 Subject: [PATCH 01/13] Adding CPU & Memory metrics for App --- atom/browser/api/atom_api_app.cc | 112 +++++++++++++++++---- atom/browser/api/atom_api_app.h | 40 +++++++- atom/browser/atom_browser_client.cc | 10 ++ atom/browser/atom_browser_client.h | 1 + docs/api/app.md | 8 +- docs/api/structures/process-memory-info.md | 4 - docs/api/structures/process-metric.md | 6 ++ spec/api-app-spec.js | 11 +- vendor/brightray | 1 + 9 files changed, 159 insertions(+), 34 deletions(-) delete mode 100644 docs/api/structures/process-memory-info.md create mode 100644 docs/api/structures/process-metric.md create mode 160000 vendor/brightray diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index cf5cb4386cb5..30fd54f1ecf1 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -29,12 +29,14 @@ #include "base/files/file_util.h" #include "base/path_service.h" #include "base/strings/string_util.h" +#include "base/sys_info.h" #include "brightray/browser/brightray_paths.h" #include "chrome/browser/browser_process.h" #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/child_process_data.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" @@ -505,6 +507,19 @@ App::App(v8::Isolate* isolate) { static_cast(AtomBrowserClient::Get())->set_delegate(this); Browser::Get()->AddObserver(this); content::GpuDataManager::GetInstance()->AddObserver(this); + content::BrowserChildProcessObserver::Add(this); + int pid = 0; + #if defined(OS_WIN) + pid = GetCurrentProcessId(); + #elif defined(OS_POSIX) + pid = getpid(); + #endif + std::unique_ptr process_metric( + new atom::ProcessMetric( + "Browser", + pid, + base::ProcessMetrics::CreateCurrentProcessMetrics())); + app_metrics_[pid] = std::move(process_metric); Init(isolate); } @@ -513,6 +528,7 @@ App::~App() { nullptr); Browser::Get()->RemoveObserver(this); content::GpuDataManager::GetInstance()->RemoveObserver(this); + content::BrowserChildProcessObserver::Remove(this); } void App::OnBeforeQuit(bool* prevent_default) { @@ -666,6 +682,58 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) { status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); } +void App::BrowserChildProcessLaunchedAndConnected( + const content::ChildProcessData& data) { + this->ChildProcessLaunched( + data.process_type, + base::GetProcId(data.handle)); +} + +void App::BrowserChildProcessHostDisconnected( + const content::ChildProcessData& data) { + this->ChildProcessDisconnected( + base::GetProcId(data.handle)); +} + +void App::RenderProcessReady( + content::RenderProcessHost* host) { + this->ChildProcessLaunched( + content::PROCESS_TYPE_RENDERER, + base::GetProcId(host->GetHandle())); +} + +void App::RenderProcessDisconnected( + content::RenderProcessHost* host) { + this->ChildProcessDisconnected( + base::GetProcId(host->GetHandle())); +} + +void App::ChildProcessLaunched( + int process_type, + base::ProcessId pid) { + auto process = base::Process::OpenWithExtraPrivileges(pid); + +#if defined(OS_MACOSX) + std::unique_ptr metrics( + base::ProcessMetrics::CreateProcessMetrics( + process.Handle(), content::BrowserChildProcessHost::GetPortProvider())); +#else + std::unique_ptr metrics( + base::ProcessMetrics::CreateProcessMetrics(process.Handle())); +#endif + std::unique_ptr process_metric( + new atom::ProcessMetric( + content::GetProcessTypeNameInEnglish(process_type), + pid, + std::move(metrics))); + app_metrics_[pid] = std::move(process_metric); +} + +void App::ChildProcessDisconnected( + base::ProcessId pid) { + app_metrics_.erase(pid); +} + base::FilePath App::GetAppPath() const { return app_path_; } @@ -923,42 +991,40 @@ void App::GetFileIcon(const base::FilePath& path, } } -std::vector App::GetAppMemoryInfo(v8::Isolate* isolate) { - AppIdProcessIterator process_iterator; - auto process_entry = process_iterator.NextProcessEntry(); +std::vector App::GetAppMetrics(v8::Isolate* isolate) { std::vector result; + int processor_count = base::SysInfo::NumberOfProcessors(); - while (process_entry != nullptr) { - int64_t pid = process_entry->pid(); - auto process = base::Process::OpenWithExtraPrivileges(pid); - -#if defined(OS_MACOSX) - std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics( - process.Handle(), content::BrowserChildProcessHost::GetPortProvider())); -#else - std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics(process.Handle())); -#endif - + for (const auto& process_metric : app_metrics_) { mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate); mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate); + mate::Dictionary cpu_dict = mate::Dictionary::CreateEmpty(isolate); memory_dict.Set("workingSetSize", - static_cast(metrics->GetWorkingSetSize() >> 10)); + static_cast( + process_metric.second->metrics->GetWorkingSetSize() >> 10)); memory_dict.Set("peakWorkingSetSize", - static_cast(metrics->GetPeakWorkingSetSize() >> 10)); + static_cast( + process_metric.second->metrics->GetPeakWorkingSetSize() >> 10)); size_t private_bytes, shared_bytes; - if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) { + if (process_metric.second->metrics->GetMemoryBytes( + &private_bytes, + &shared_bytes)) { memory_dict.Set("privateBytes", static_cast(private_bytes >> 10)); memory_dict.Set("sharedBytes", static_cast(shared_bytes >> 10)); } pid_dict.Set("memory", memory_dict); - pid_dict.Set("pid", pid); + cpu_dict.Set("percentCPUUsage", + process_metric.second->metrics->GetPlatformIndependentCPUUsage() + / processor_count); + cpu_dict.Set("idleWakeupsPerSecond", + process_metric.second->metrics->GetIdleWakeupsPerSecond()); + pid_dict.Set("cpu", cpu_dict); + pid_dict.Set("pid", process_metric.second->pid); + pid_dict.Set("type", process_metric.second->type); result.push_back(pid_dict); - process_entry = process_iterator.NextProcessEntry(); } return result; @@ -1036,7 +1102,9 @@ void App::BuildPrototype( .SetMethod("disableHardwareAcceleration", &App::DisableHardwareAcceleration) .SetMethod("getFileIcon", &App::GetFileIcon) - .SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo); + // TODO(juturu): Deprecate getAppMemoryInfo. + .SetMethod("getAppMemoryInfo", &App::GetAppMetrics) + .SetMethod("getAppMetrics", &App::GetAppMetrics); } } // namespace api diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 9543e4b74b22..30f7edcbc9b8 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -17,7 +17,9 @@ #include "base/task/cancelable_task_tracker.h" #include "chrome/browser/icon_manager.h" #include "chrome/browser/process_singleton.h" +#include "content/public/browser/browser_child_process_observer.h" #include "content/public/browser/gpu_data_manager_observer.h" +#include "content/public/browser/render_process_host.h" #include "native_mate/dictionary.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" @@ -40,12 +42,26 @@ namespace atom { enum class JumpListResult : int; #endif +struct ProcessMetric { + std::string type; + base::ProcessId pid; + std::unique_ptr metrics; + ProcessMetric(std::string type, + base::ProcessId pid, + std::unique_ptr metrics) { + this->type = type; + this->pid = pid; + this->metrics = std::move(metrics); + } +}; + namespace api { class App : public AtomBrowserClient::Delegate, public mate::EventEmitter, public BrowserObserver, - public content::GpuDataManagerObserver { + public content::GpuDataManagerObserver, + public content::BrowserChildProcessObserver { public: using FileIconCallback = base::Callback, const gfx::Image&)>; @@ -73,6 +89,10 @@ class App : public AtomBrowserClient::Delegate, #endif base::FilePath GetAppPath() const; + void RenderProcessReady( + content::RenderProcessHost* host); + void RenderProcessDisconnected( + content::RenderProcessHost* host); protected: explicit App(v8::Isolate* isolate); @@ -118,8 +138,19 @@ class App : public AtomBrowserClient::Delegate, // content::GpuDataManagerObserver: void OnGpuProcessCrashed(base::TerminationStatus status) override; + // content::BrowserChildProcessObserver: + void BrowserChildProcessLaunchedAndConnected( + const content::ChildProcessData& data) override; + void BrowserChildProcessHostDisconnected( + const content::ChildProcessData& data) override; + private: void SetAppPath(const base::FilePath& app_path); + void ChildProcessLaunched( + int process_type, + base::ProcessId id); + void ChildProcessDisconnected( + base::ProcessId pid); // Get/Set the pre-defined path in PathService. base::FilePath GetPath(mate::Arguments* args, const std::string& name); @@ -143,7 +174,7 @@ class App : public AtomBrowserClient::Delegate, void GetFileIcon(const base::FilePath& path, mate::Arguments* args); - std::vector GetAppMemoryInfo(v8::Isolate* isolate); + std::vector GetAppMetrics(v8::Isolate* isolate); #if defined(OS_WIN) // Get the current Jump List settings. @@ -164,6 +195,11 @@ class App : public AtomBrowserClient::Delegate, base::FilePath app_path_; + using ProcessMetricMap = + std::unordered_map>; + ProcessMetricMap app_metrics_; + DISALLOW_COPY_AND_ASSIGN(App); }; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index 6cede9c0112c..ad77ba814c61 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -408,6 +408,16 @@ void AtomBrowserClient::RenderProcessHostDestroyed( } } RemoveProcessPreferences(process_id); + if (delegate_) { + static_cast(delegate_)->RenderProcessDisconnected(host); + } +} + +void AtomBrowserClient::RenderProcessReady( + content::RenderProcessHost* host) { + if (delegate_) { + static_cast(delegate_)->RenderProcessReady(host); + } } } // namespace atom diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index c9a58981a2ce..ad18885d29a1 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -109,6 +109,7 @@ class AtomBrowserClient : public brightray::BrowserClient, // content::RenderProcessHostObserver: void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; + void RenderProcessReady(content::RenderProcessHost* host) override; private: bool ShouldCreateNewSiteInstance(content::RenderFrameHost* render_frame_host, diff --git a/docs/api/app.md b/docs/api/app.md index 614989dc99c6..f447d25491dc 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -762,9 +762,13 @@ Disables hardware acceleration for current app. This method can only be called before app is ready. -### `app.getAppMemoryInfo()` +### `app.getAppMemoryInfo()` _Deprecate_ -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. +Returns [ProcessMetric[]](structures/process-metric.md): Array of `ProcessMetric` objects that correspond to memory and cpu usage statistics of all the processes associated with the app. + +### `app.getAppMetrics()` + +Returns [ProcessMetric[]](structures/process-metric.md): Array of `ProcessMetric` objects that correspond to memory and cpu usage statistics of all the processes associated with the app. ### `app.setBadgeCount(count)` _Linux_ _macOS_ diff --git a/docs/api/structures/process-memory-info.md b/docs/api/structures/process-memory-info.md deleted file mode 100644 index 68198f2d4540..000000000000 --- a/docs/api/structures/process-memory-info.md +++ /dev/null @@ -1,4 +0,0 @@ -# ProcessMemoryInfo Object - -* `pid` Integer - Process id of the process. -* `memory` [MemoryInfo](memory-info.md) - Memory information of the process. diff --git a/docs/api/structures/process-metric.md b/docs/api/structures/process-metric.md new file mode 100644 index 000000000000..d7d476b9b441 --- /dev/null +++ b/docs/api/structures/process-metric.md @@ -0,0 +1,6 @@ +# ProcessMetric Object + +* `pid` Integer - Process id of the process. +* `type` String - Process type (Browser or Tab or GPU etc). +* `memory` [MemoryInfo](memory-info.md) - Memory information of the process. +* `cpu` [CPUUsage](cpu-usage.md) - CPU Of the process diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 1bcc1a5c6223..b73f058bdaeb 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -534,15 +534,18 @@ describe('app module', function () { }) }) - describe('getAppMemoryInfo() API', function () { + describe.only('getAppMetrics() 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) { + const appMetrics = app.getAppMetrics() + assert.ok(appMetrics.length > 0, 'App memory info object is not > 0') + for (const {memory, pid, type, cpu} of appMetrics) { 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') + assert.ok(type.length > 0, 'process type is null') + assert.equal(typeof cpu.percentCPUUsage, 'number') + assert.equal(typeof cpu.idleWakeupsPerSecond, 'number') } }) }) diff --git a/vendor/brightray b/vendor/brightray new file mode 160000 index 000000000000..28d713bb2a82 --- /dev/null +++ b/vendor/brightray @@ -0,0 +1 @@ +Subproject commit 28d713bb2a82ba690a21d62522ecd7bad09caba8 From d73004f1df32e594c999ff2e9d5cbf229e374da8 Mon Sep 17 00:00:00 2001 From: Hari Juturu Date: Wed, 17 May 2017 19:57:16 -0700 Subject: [PATCH 02/13] revert mistaken added brightray --- vendor/brightray | 1 - 1 file changed, 1 deletion(-) delete mode 160000 vendor/brightray diff --git a/vendor/brightray b/vendor/brightray deleted file mode 160000 index 28d713bb2a82..000000000000 --- a/vendor/brightray +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 28d713bb2a82ba690a21d62522ecd7bad09caba8 From 5e04fab2bab97208f29a864410e8cddae59f3a6f Mon Sep 17 00:00:00 2001 From: Hari Juturu Date: Wed, 17 May 2017 20:01:06 -0700 Subject: [PATCH 03/13] Adding deprecations --- docs/tutorial/planned-breaking-changes.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/tutorial/planned-breaking-changes.md b/docs/tutorial/planned-breaking-changes.md index b5771feea5c2..7544c0c4d821 100644 --- a/docs/tutorial/planned-breaking-changes.md +++ b/docs/tutorial/planned-breaking-changes.md @@ -5,6 +5,15 @@ The following list includes the APIs that will be removed in Electron 2.0. There is no timetable for when this release will occur but deprecation warnings will be added at least 90 days beforehand. +## `app` + +```js +// Deprecated +app.getAppMemoryInfo() +// Replace with +app.getAppMetrics() +``` + ## `BrowserWindow` ```js From de5eaf9336cc24ccd4337e17028e7ca56287e009 Mon Sep 17 00:00:00 2001 From: Hari Juturu Date: Wed, 17 May 2017 20:10:11 -0700 Subject: [PATCH 04/13] Remove .only --- spec/api-app-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index b73f058bdaeb..fe250910b755 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -534,7 +534,7 @@ describe('app module', function () { }) }) - describe.only('getAppMetrics() API', function () { + describe('getAppMetrics() API', function () { it('returns the process memory of all running electron processes', function () { const appMetrics = app.getAppMetrics() assert.ok(appMetrics.length > 0, 'App memory info object is not > 0') From e5a9ef296d98a8fc6fb9ad228db4dbfce93edc0d Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Fri, 19 May 2017 21:28:52 -0700 Subject: [PATCH 05/13] Using process handle from RenderProcessHost --- atom/browser/api/atom_api_app.cc | 12 ++++++------ atom/browser/api/atom_api_app.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 30fd54f1ecf1..4bd49731bfbc 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -686,7 +686,7 @@ void App::BrowserChildProcessLaunchedAndConnected( const content::ChildProcessData& data) { this->ChildProcessLaunched( data.process_type, - base::GetProcId(data.handle)); + data.handle); } void App::BrowserChildProcessHostDisconnected( @@ -699,7 +699,7 @@ void App::RenderProcessReady( content::RenderProcessHost* host) { this->ChildProcessLaunched( content::PROCESS_TYPE_RENDERER, - base::GetProcId(host->GetHandle())); + host->GetHandle()); } void App::RenderProcessDisconnected( @@ -710,16 +710,16 @@ void App::RenderProcessDisconnected( void App::ChildProcessLaunched( int process_type, - base::ProcessId pid) { - auto process = base::Process::OpenWithExtraPrivileges(pid); + base::ProcessHandle handle) { + auto pid = base::GetProcId(handle); #if defined(OS_MACOSX) std::unique_ptr metrics( base::ProcessMetrics::CreateProcessMetrics( - process.Handle(), content::BrowserChildProcessHost::GetPortProvider())); + handle, content::BrowserChildProcessHost::GetPortProvider())); #else std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics(process.Handle())); + base::ProcessMetrics::CreateProcessMetrics(handle)); #endif std::unique_ptr process_metric( new atom::ProcessMetric( diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 30f7edcbc9b8..b43327c9728d 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -148,7 +148,7 @@ class App : public AtomBrowserClient::Delegate, void SetAppPath(const base::FilePath& app_path); void ChildProcessLaunched( int process_type, - base::ProcessId id); + base::ProcessHandle handle); void ChildProcessDisconnected( base::ProcessId pid); From c4e5ba6015a24b6f68afd30719c2f3e9f09f11d5 Mon Sep 17 00:00:00 2001 From: Hari Krishna Reddy Juturu Date: Wed, 24 May 2017 21:15:34 -0700 Subject: [PATCH 06/13] Fixing indentations --- atom/browser/api/atom_api_app.cc | 13 +++---------- atom/browser/api/atom_api_app.h | 13 ++++--------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 4bd49731bfbc..12a9a4d058b4 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -508,12 +508,7 @@ App::App(v8::Isolate* isolate) { Browser::Get()->AddObserver(this); content::GpuDataManager::GetInstance()->AddObserver(this); content::BrowserChildProcessObserver::Add(this); - int pid = 0; - #if defined(OS_WIN) - pid = GetCurrentProcessId(); - #elif defined(OS_POSIX) - pid = getpid(); - #endif + base::ProcessId pid = base::GetCurrentProcId(); std::unique_ptr process_metric( new atom::ProcessMetric( "Browser", @@ -691,8 +686,7 @@ void App::BrowserChildProcessLaunchedAndConnected( void App::BrowserChildProcessHostDisconnected( const content::ChildProcessData& data) { - this->ChildProcessDisconnected( - base::GetProcId(data.handle)); + this->ChildProcessDisconnected(base::GetProcId(data.handle)); } void App::RenderProcessReady( @@ -704,8 +698,7 @@ void App::RenderProcessReady( void App::RenderProcessDisconnected( content::RenderProcessHost* host) { - this->ChildProcessDisconnected( - base::GetProcId(host->GetHandle())); + this->ChildProcessDisconnected(base::GetProcId(host->GetHandle())); } void App::ChildProcessLaunched( diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index b43327c9728d..b125f5ccfe24 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -89,10 +89,8 @@ class App : public AtomBrowserClient::Delegate, #endif base::FilePath GetAppPath() const; - void RenderProcessReady( - content::RenderProcessHost* host); - void RenderProcessDisconnected( - content::RenderProcessHost* host); + void RenderProcessReady(content::RenderProcessHost* host); + void RenderProcessDisconnected(content::RenderProcessHost* host); protected: explicit App(v8::Isolate* isolate); @@ -146,11 +144,8 @@ class App : public AtomBrowserClient::Delegate, private: void SetAppPath(const base::FilePath& app_path); - void ChildProcessLaunched( - int process_type, - base::ProcessHandle handle); - void ChildProcessDisconnected( - base::ProcessId pid); + void ChildProcessLaunched(int process_type, base::ProcessHandle handle); + void ChildProcessDisconnected(base::ProcessId pid); // Get/Set the pre-defined path in PathService. base::FilePath GetPath(mate::Arguments* args, const std::string& name); From b5879b739918937bd83f8404a8f69e99a8e7dc17 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 07:51:17 -0700 Subject: [PATCH 07/13] :art: Minor formatting/doc changes --- atom/browser/api/atom_api_app.cc | 53 +++++++++++++---------------- atom/browser/api/atom_api_app.h | 4 ++- atom/browser/atom_browser_client.cc | 3 +- docs/api/app.md | 5 +-- spec/api-app-spec.js | 2 +- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 12a9a4d058b4..5320db277577 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -510,10 +510,10 @@ App::App(v8::Isolate* isolate) { content::BrowserChildProcessObserver::Add(this); base::ProcessId pid = base::GetCurrentProcId(); std::unique_ptr process_metric( - new atom::ProcessMetric( - "Browser", - pid, - base::ProcessMetrics::CreateCurrentProcessMetrics())); + new atom::ProcessMetric( + "Browser", + pid, + base::ProcessMetrics::CreateCurrentProcessMetrics())); app_metrics_[pid] = std::move(process_metric); Init(isolate); } @@ -679,26 +679,20 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) { void App::BrowserChildProcessLaunchedAndConnected( const content::ChildProcessData& data) { - this->ChildProcessLaunched( - data.process_type, - data.handle); + ChildProcessLaunched(data.process_type, data.handle); } void App::BrowserChildProcessHostDisconnected( const content::ChildProcessData& data) { - this->ChildProcessDisconnected(base::GetProcId(data.handle)); + ChildProcessDisconnected(base::GetProcId(data.handle)); } -void App::RenderProcessReady( - content::RenderProcessHost* host) { - this->ChildProcessLaunched( - content::PROCESS_TYPE_RENDERER, - host->GetHandle()); +void App::RenderProcessReady(content::RenderProcessHost* host) { + ChildProcessLaunched(content::PROCESS_TYPE_RENDERER, host->GetHandle()); } -void App::RenderProcessDisconnected( - content::RenderProcessHost* host) { - this->ChildProcessDisconnected(base::GetProcId(host->GetHandle())); +void App::RenderProcessDisconnected(content::RenderProcessHost* host) { + ChildProcessDisconnected(base::GetProcId(host->GetHandle())); } void App::ChildProcessLaunched( @@ -707,23 +701,22 @@ void App::ChildProcessLaunched( auto pid = base::GetProcId(handle); #if defined(OS_MACOSX) - std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics( - handle, content::BrowserChildProcessHost::GetPortProvider())); + std::unique_ptr metrics( + base::ProcessMetrics::CreateProcessMetrics( + handle, content::BrowserChildProcessHost::GetPortProvider())); #else - std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics(handle)); + std::unique_ptr metrics( + base::ProcessMetrics::CreateProcessMetrics(handle)); #endif std::unique_ptr process_metric( - new atom::ProcessMetric( - content::GetProcessTypeNameInEnglish(process_type), - pid, - std::move(metrics))); + new atom::ProcessMetric( + content::GetProcessTypeNameInEnglish(process_type), + pid, + std::move(metrics))); app_metrics_[pid] = std::move(process_metric); } -void App::ChildProcessDisconnected( - base::ProcessId pid) { +void App::ChildProcessDisconnected(base::ProcessId pid) { app_metrics_.erase(pid); } @@ -1095,9 +1088,9 @@ void App::BuildPrototype( .SetMethod("disableHardwareAcceleration", &App::DisableHardwareAcceleration) .SetMethod("getFileIcon", &App::GetFileIcon) - // TODO(juturu): Deprecate getAppMemoryInfo. - .SetMethod("getAppMemoryInfo", &App::GetAppMetrics) - .SetMethod("getAppMetrics", &App::GetAppMetrics); + .SetMethod("getAppMetrics", &App::GetAppMetrics) + // TODO(juturu): Remove in 2.0, deprecate before then with warnings + .SetMethod("getAppMemoryInfo", &App::GetAppMetrics); } } // namespace api diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index b125f5ccfe24..16fd25a148bb 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -6,6 +6,7 @@ #define ATOM_BROWSER_API_ATOM_API_APP_H_ #include +#include #include #include "atom/browser/api/event_emitter.h" @@ -46,7 +47,8 @@ struct ProcessMetric { std::string type; base::ProcessId pid; std::unique_ptr metrics; - ProcessMetric(std::string type, + + ProcessMetric(const std::string& type, base::ProcessId pid, std::unique_ptr metrics) { this->type = type; diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index ad77ba814c61..a49c1f7e6169 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -413,8 +413,7 @@ void AtomBrowserClient::RenderProcessHostDestroyed( } } -void AtomBrowserClient::RenderProcessReady( - content::RenderProcessHost* host) { +void AtomBrowserClient::RenderProcessReady(content::RenderProcessHost* host) { if (delegate_) { static_cast(delegate_)->RenderProcessReady(host); } diff --git a/docs/api/app.md b/docs/api/app.md index f447d25491dc..044e6449a24b 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -127,7 +127,7 @@ Returns: Emitted when the application is activated. Various actions can trigger this event, such as launching the application for the first time, attempting -to re-launch the application when it's already running, or clicking on the +to re-launch the application when it's already running, or clicking on the application's dock or taskbar icon. ### Event: 'continue-activity' _macOS_ @@ -762,9 +762,10 @@ Disables hardware acceleration for current app. This method can only be called before app is ready. -### `app.getAppMemoryInfo()` _Deprecate_ +### `app.getAppMemoryInfo()` _Deprecated_ Returns [ProcessMetric[]](structures/process-metric.md): Array of `ProcessMetric` objects that correspond to memory and cpu usage statistics of all the processes associated with the app. +**Note:** This method is deprecated, use `app.getAppMetrics()` instead. ### `app.getAppMetrics()` diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index fe250910b755..6b0a3ca354ba 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -535,7 +535,7 @@ describe('app module', function () { }) describe('getAppMetrics() API', function () { - it('returns the process memory of all running electron processes', function () { + it('returns memory and cpu stats of all running electron processes', function () { const appMetrics = app.getAppMetrics() assert.ok(appMetrics.length > 0, 'App memory info object is not > 0') for (const {memory, pid, type, cpu} of appMetrics) { From d6e626c7e36655583e1ff60abf7b3ef2ba627bb7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 08:32:08 -0700 Subject: [PATCH 08/13] Remove crashed render processes from metrics --- atom/browser/api/atom_api_app.cc | 18 +++++++++++++----- atom/browser/api/atom_api_app.h | 7 ++++++- atom/browser/atom_browser_client.cc | 17 ++++++++++++++--- atom/browser/atom_browser_client.h | 4 ++++ 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 5320db277577..dbd44a40dc74 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -687,17 +687,25 @@ void App::BrowserChildProcessHostDisconnected( ChildProcessDisconnected(base::GetProcId(data.handle)); } +void App::BrowserChildProcessCrashed(const content::ChildProcessData& data, + int exit_code) { + ChildProcessDisconnected(base::GetProcId(data.handle)); +} + +void App::BrowserChildProcessKilled(const content::ChildProcessData& data, + int exit_code) { + ChildProcessDisconnected(base::GetProcId(data.handle)); +} + void App::RenderProcessReady(content::RenderProcessHost* host) { ChildProcessLaunched(content::PROCESS_TYPE_RENDERER, host->GetHandle()); } -void App::RenderProcessDisconnected(content::RenderProcessHost* host) { - ChildProcessDisconnected(base::GetProcId(host->GetHandle())); +void App::RenderProcessDisconnected(base::ProcessId host_pid) { + ChildProcessDisconnected(host_pid); } -void App::ChildProcessLaunched( - int process_type, - base::ProcessHandle handle) { +void App::ChildProcessLaunched(int process_type, base::ProcessHandle handle) { auto pid = base::GetProcId(handle); #if defined(OS_MACOSX) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 16fd25a148bb..353eba6883c1 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -5,6 +5,7 @@ #ifndef ATOM_BROWSER_API_ATOM_API_APP_H_ #define ATOM_BROWSER_API_ATOM_API_APP_H_ +#include #include #include #include @@ -92,7 +93,7 @@ class App : public AtomBrowserClient::Delegate, base::FilePath GetAppPath() const; void RenderProcessReady(content::RenderProcessHost* host); - void RenderProcessDisconnected(content::RenderProcessHost* host); + void RenderProcessDisconnected(base::ProcessId host_pid); protected: explicit App(v8::Isolate* isolate); @@ -143,6 +144,10 @@ class App : public AtomBrowserClient::Delegate, const content::ChildProcessData& data) override; void BrowserChildProcessHostDisconnected( const content::ChildProcessData& data) override; + void BrowserChildProcessCrashed( + const content::ChildProcessData& data, int exit_code) override; + void BrowserChildProcessKilled( + const content::ChildProcessData& data, int exit_code) override; private: void SetAppPath(const base::FilePath& app_path); diff --git a/atom/browser/atom_browser_client.cc b/atom/browser/atom_browser_client.cc index a49c1f7e6169..be4ee262adf1 100644 --- a/atom/browser/atom_browser_client.cc +++ b/atom/browser/atom_browser_client.cc @@ -408,15 +408,26 @@ void AtomBrowserClient::RenderProcessHostDestroyed( } } RemoveProcessPreferences(process_id); - if (delegate_) { - static_cast(delegate_)->RenderProcessDisconnected(host); - } } void AtomBrowserClient::RenderProcessReady(content::RenderProcessHost* host) { + render_process_host_pids_[host->GetID()] = base::GetProcId(host->GetHandle()); if (delegate_) { static_cast(delegate_)->RenderProcessReady(host); } } +void AtomBrowserClient::RenderProcessExited(content::RenderProcessHost* host, + base::TerminationStatus status, + int exit_code) { + auto host_pid = render_process_host_pids_.find(host->GetID()); + if (host_pid != render_process_host_pids_.end()) { + if (delegate_) { + static_cast(delegate_)->RenderProcessDisconnected( + host_pid->second); + } + render_process_host_pids_.erase(host_pid); + } +} + } // namespace atom diff --git a/atom/browser/atom_browser_client.h b/atom/browser/atom_browser_client.h index ad18885d29a1..69ac51c66310 100644 --- a/atom/browser/atom_browser_client.h +++ b/atom/browser/atom_browser_client.h @@ -110,6 +110,9 @@ class AtomBrowserClient : public brightray::BrowserClient, // content::RenderProcessHostObserver: void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; void RenderProcessReady(content::RenderProcessHost* host) override; + void RenderProcessExited(content::RenderProcessHost* host, + base::TerminationStatus status, + int exit_code) override; private: bool ShouldCreateNewSiteInstance(content::RenderFrameHost* render_frame_host, @@ -129,6 +132,7 @@ class AtomBrowserClient : public brightray::BrowserClient, std::map pending_processes_; std::map process_preferences_; + std::map render_process_host_pids_; base::Lock process_preferences_lock_; std::unique_ptr From 7794cabd130b905f649c8d0f5f9d6cfc7b3f7884 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 08:35:43 -0700 Subject: [PATCH 09/13] :art: --- atom/browser/api/atom_api_app.cc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index dbd44a40dc74..93cb4fd52a77 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -995,16 +995,15 @@ std::vector App::GetAppMetrics(v8::Isolate* isolate) { mate::Dictionary cpu_dict = mate::Dictionary::CreateEmpty(isolate); memory_dict.Set("workingSetSize", - static_cast( - process_metric.second->metrics->GetWorkingSetSize() >> 10)); + static_cast( + process_metric.second->metrics->GetWorkingSetSize() >> 10)); memory_dict.Set("peakWorkingSetSize", - static_cast( - process_metric.second->metrics->GetPeakWorkingSetSize() >> 10)); + static_cast( + process_metric.second->metrics->GetPeakWorkingSetSize() >> 10)); size_t private_bytes, shared_bytes; - if (process_metric.second->metrics->GetMemoryBytes( - &private_bytes, - &shared_bytes)) { + if (process_metric.second->metrics->GetMemoryBytes(&private_bytes, + &shared_bytes)) { memory_dict.Set("privateBytes", static_cast(private_bytes >> 10)); memory_dict.Set("sharedBytes", static_cast(shared_bytes >> 10)); } From cabcd0ef8f323f9989a0dc8d3b1b172c08b9f48d Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 08:36:51 -0700 Subject: [PATCH 10/13] Fix typos in ProcessMetric doc --- docs/api/structures/process-metric.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/structures/process-metric.md b/docs/api/structures/process-metric.md index d7d476b9b441..15a75a796647 100644 --- a/docs/api/structures/process-metric.md +++ b/docs/api/structures/process-metric.md @@ -2,5 +2,5 @@ * `pid` Integer - Process id of the process. * `type` String - Process type (Browser or Tab or GPU etc). -* `memory` [MemoryInfo](memory-info.md) - Memory information of the process. -* `cpu` [CPUUsage](cpu-usage.md) - CPU Of the process +* `memory` [MemoryInfo](memory-info.md) - Memory information for the process. +* `cpu` [CPUUsage](cpu-usage.md) - CPU usage of the process. From 1e4dd9b1631fba8aae5affe702f2dce28aaadb78 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 08:53:26 -0700 Subject: [PATCH 11/13] Store process type as int --- atom/browser/api/atom_api_app.cc | 10 ++++------ atom/browser/api/atom_api_app.h | 4 ++-- spec/api-app-spec.js | 6 ++++++ 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 93cb4fd52a77..ba70191f74cd 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -511,7 +511,7 @@ App::App(v8::Isolate* isolate) { base::ProcessId pid = base::GetCurrentProcId(); std::unique_ptr process_metric( new atom::ProcessMetric( - "Browser", + content::PROCESS_TYPE_BROWSER, pid, base::ProcessMetrics::CreateCurrentProcessMetrics())); app_metrics_[pid] = std::move(process_metric); @@ -717,10 +717,7 @@ void App::ChildProcessLaunched(int process_type, base::ProcessHandle handle) { base::ProcessMetrics::CreateProcessMetrics(handle)); #endif std::unique_ptr process_metric( - new atom::ProcessMetric( - content::GetProcessTypeNameInEnglish(process_type), - pid, - std::move(metrics))); + new atom::ProcessMetric(process_type, pid, std::move(metrics))); app_metrics_[pid] = std::move(process_metric); } @@ -1016,7 +1013,8 @@ std::vector App::GetAppMetrics(v8::Isolate* isolate) { process_metric.second->metrics->GetIdleWakeupsPerSecond()); pid_dict.Set("cpu", cpu_dict); pid_dict.Set("pid", process_metric.second->pid); - pid_dict.Set("type", process_metric.second->type); + pid_dict.Set("type", + content::GetProcessTypeNameInEnglish(process_metric.second->type)); result.push_back(pid_dict); } diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 353eba6883c1..d68b172a7fad 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -45,11 +45,11 @@ enum class JumpListResult : int; #endif struct ProcessMetric { - std::string type; + int type; base::ProcessId pid; std::unique_ptr metrics; - ProcessMetric(const std::string& type, + ProcessMetric(int type, base::ProcessId pid, std::unique_ptr metrics) { this->type = type; diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 6b0a3ca354ba..d2bab22b860e 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -538,15 +538,21 @@ describe('app module', function () { it('returns memory and cpu stats of all running electron processes', function () { const appMetrics = app.getAppMetrics() assert.ok(appMetrics.length > 0, 'App memory info object is not > 0') + const types = [] for (const {memory, pid, type, cpu} of appMetrics) { 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') assert.ok(type.length > 0, 'process type is null') + types.push(type) assert.equal(typeof cpu.percentCPUUsage, 'number') assert.equal(typeof cpu.idleWakeupsPerSecond, 'number') } + + assert.ok(types.includes('GPU')) + assert.ok(types.includes('Browser')) + assert.ok(types.includes('Tab')) }) }) }) From 8b14df143ac22ec9f6c1c9caaf11a87e8d790b93 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 09:14:17 -0700 Subject: [PATCH 12/13] Don't assert GPU process on Linux --- spec/api-app-spec.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index d2bab22b860e..60d87e9008ad 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -550,7 +550,10 @@ describe('app module', function () { assert.equal(typeof cpu.idleWakeupsPerSecond, 'number') } - assert.ok(types.includes('GPU')) + if (process.platform !== 'linux') { + assert.ok(types.includes('GPU')) + } + assert.ok(types.includes('Browser')) assert.ok(types.includes('Tab')) }) From 14c43f654fb6bb7747976abe014ade1382260aae Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 26 May 2017 09:25:35 -0700 Subject: [PATCH 13/13] :art: --- atom/browser/api/atom_api_app.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index ba70191f74cd..d6fe607de496 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -710,11 +710,11 @@ void App::ChildProcessLaunched(int process_type, base::ProcessHandle handle) { #if defined(OS_MACOSX) std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics( - handle, content::BrowserChildProcessHost::GetPortProvider())); + base::ProcessMetrics::CreateProcessMetrics( + handle, content::BrowserChildProcessHost::GetPortProvider())); #else std::unique_ptr metrics( - base::ProcessMetrics::CreateProcessMetrics(handle)); + base::ProcessMetrics::CreateProcessMetrics(handle)); #endif std::unique_ptr process_metric( new atom::ProcessMetric(process_type, pid, std::move(metrics)));