Adding CPU & Memory metrics for App

This commit is contained in:
Hari Juturu 2017-05-15 17:41:45 -07:00 committed by Hari Krishna Reddy Juturu
parent 0d2aa5c027
commit 939747945e
9 changed files with 159 additions and 34 deletions

View file

@ -29,12 +29,14 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "brightray/browser/brightray_paths.h" #include "brightray/browser/brightray_paths.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/icon_manager.h" #include "chrome/browser/icon_manager.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
#include "content/public/browser/browser_accessibility_state.h" #include "content/public/browser/browser_accessibility_state.h"
#include "content/public/browser/browser_child_process_host.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/client_certificate_delegate.h"
#include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
@ -505,6 +507,19 @@ App::App(v8::Isolate* isolate) {
static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this); static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())->set_delegate(this);
Browser::Get()->AddObserver(this); Browser::Get()->AddObserver(this);
content::GpuDataManager::GetInstance()->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<atom::ProcessMetric> process_metric(
new atom::ProcessMetric(
"Browser",
pid,
base::ProcessMetrics::CreateCurrentProcessMetrics()));
app_metrics_[pid] = std::move(process_metric);
Init(isolate); Init(isolate);
} }
@ -513,6 +528,7 @@ App::~App() {
nullptr); nullptr);
Browser::Get()->RemoveObserver(this); Browser::Get()->RemoveObserver(this);
content::GpuDataManager::GetInstance()->RemoveObserver(this); content::GpuDataManager::GetInstance()->RemoveObserver(this);
content::BrowserChildProcessObserver::Remove(this);
} }
void App::OnBeforeQuit(bool* prevent_default) { void App::OnBeforeQuit(bool* prevent_default) {
@ -666,6 +682,58 @@ void App::OnGpuProcessCrashed(base::TerminationStatus status) {
status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); 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<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(
process.Handle(), content::BrowserChildProcessHost::GetPortProvider()));
#else
std::unique_ptr<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(process.Handle()));
#endif
std::unique_ptr<atom::ProcessMetric> 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 { base::FilePath App::GetAppPath() const {
return app_path_; return app_path_;
} }
@ -923,42 +991,40 @@ void App::GetFileIcon(const base::FilePath& path,
} }
} }
std::vector<mate::Dictionary> App::GetAppMemoryInfo(v8::Isolate* isolate) { std::vector<mate::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
AppIdProcessIterator process_iterator;
auto process_entry = process_iterator.NextProcessEntry();
std::vector<mate::Dictionary> result; std::vector<mate::Dictionary> result;
int processor_count = base::SysInfo::NumberOfProcessors();
while (process_entry != nullptr) { for (const auto& process_metric : app_metrics_) {
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 pid_dict = mate::Dictionary::CreateEmpty(isolate);
mate::Dictionary memory_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", memory_dict.Set("workingSetSize",
static_cast<double>(metrics->GetWorkingSetSize() >> 10)); static_cast<double>(
process_metric.second->metrics->GetWorkingSetSize() >> 10));
memory_dict.Set("peakWorkingSetSize", memory_dict.Set("peakWorkingSetSize",
static_cast<double>(metrics->GetPeakWorkingSetSize() >> 10)); static_cast<double>(
process_metric.second->metrics->GetPeakWorkingSetSize() >> 10));
size_t private_bytes, shared_bytes; 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<double>(private_bytes >> 10)); memory_dict.Set("privateBytes", static_cast<double>(private_bytes >> 10));
memory_dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10)); memory_dict.Set("sharedBytes", static_cast<double>(shared_bytes >> 10));
} }
pid_dict.Set("memory", memory_dict); 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); result.push_back(pid_dict);
process_entry = process_iterator.NextProcessEntry();
} }
return result; return result;
@ -1036,7 +1102,9 @@ void App::BuildPrototype(
.SetMethod("disableHardwareAcceleration", .SetMethod("disableHardwareAcceleration",
&App::DisableHardwareAcceleration) &App::DisableHardwareAcceleration)
.SetMethod("getFileIcon", &App::GetFileIcon) .SetMethod("getFileIcon", &App::GetFileIcon)
.SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo); // TODO(juturu): Deprecate getAppMemoryInfo.
.SetMethod("getAppMemoryInfo", &App::GetAppMetrics)
.SetMethod("getAppMetrics", &App::GetAppMetrics);
} }
} // namespace api } // namespace api

View file

@ -17,7 +17,9 @@
#include "base/task/cancelable_task_tracker.h" #include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/icon_manager.h" #include "chrome/browser/icon_manager.h"
#include "chrome/browser/process_singleton.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/gpu_data_manager_observer.h"
#include "content/public/browser/render_process_host.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "net/base/completion_callback.h" #include "net/base/completion_callback.h"
@ -40,12 +42,26 @@ namespace atom {
enum class JumpListResult : int; enum class JumpListResult : int;
#endif #endif
struct ProcessMetric {
std::string type;
base::ProcessId pid;
std::unique_ptr<base::ProcessMetrics> metrics;
ProcessMetric(std::string type,
base::ProcessId pid,
std::unique_ptr<base::ProcessMetrics> metrics) {
this->type = type;
this->pid = pid;
this->metrics = std::move(metrics);
}
};
namespace api { namespace api {
class App : public AtomBrowserClient::Delegate, class App : public AtomBrowserClient::Delegate,
public mate::EventEmitter<App>, public mate::EventEmitter<App>,
public BrowserObserver, public BrowserObserver,
public content::GpuDataManagerObserver { public content::GpuDataManagerObserver,
public content::BrowserChildProcessObserver {
public: public:
using FileIconCallback = base::Callback<void(v8::Local<v8::Value>, using FileIconCallback = base::Callback<void(v8::Local<v8::Value>,
const gfx::Image&)>; const gfx::Image&)>;
@ -73,6 +89,10 @@ class App : public AtomBrowserClient::Delegate,
#endif #endif
base::FilePath GetAppPath() const; base::FilePath GetAppPath() const;
void RenderProcessReady(
content::RenderProcessHost* host);
void RenderProcessDisconnected(
content::RenderProcessHost* host);
protected: protected:
explicit App(v8::Isolate* isolate); explicit App(v8::Isolate* isolate);
@ -118,8 +138,19 @@ class App : public AtomBrowserClient::Delegate,
// content::GpuDataManagerObserver: // content::GpuDataManagerObserver:
void OnGpuProcessCrashed(base::TerminationStatus status) override; void OnGpuProcessCrashed(base::TerminationStatus status) override;
// content::BrowserChildProcessObserver:
void BrowserChildProcessLaunchedAndConnected(
const content::ChildProcessData& data) override;
void BrowserChildProcessHostDisconnected(
const content::ChildProcessData& data) override;
private: private:
void SetAppPath(const base::FilePath& app_path); 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. // Get/Set the pre-defined path in PathService.
base::FilePath GetPath(mate::Arguments* args, const std::string& name); 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, void GetFileIcon(const base::FilePath& path,
mate::Arguments* args); mate::Arguments* args);
std::vector<mate::Dictionary> GetAppMemoryInfo(v8::Isolate* isolate); std::vector<mate::Dictionary> GetAppMetrics(v8::Isolate* isolate);
#if defined(OS_WIN) #if defined(OS_WIN)
// Get the current Jump List settings. // Get the current Jump List settings.
@ -164,6 +195,11 @@ class App : public AtomBrowserClient::Delegate,
base::FilePath app_path_; base::FilePath app_path_;
using ProcessMetricMap =
std::unordered_map<base::ProcessId,
std::unique_ptr<atom::ProcessMetric>>;
ProcessMetricMap app_metrics_;
DISALLOW_COPY_AND_ASSIGN(App); DISALLOW_COPY_AND_ASSIGN(App);
}; };

View file

@ -408,6 +408,16 @@ void AtomBrowserClient::RenderProcessHostDestroyed(
} }
} }
RemoveProcessPreferences(process_id); RemoveProcessPreferences(process_id);
if (delegate_) {
static_cast<api::App*>(delegate_)->RenderProcessDisconnected(host);
}
}
void AtomBrowserClient::RenderProcessReady(
content::RenderProcessHost* host) {
if (delegate_) {
static_cast<api::App*>(delegate_)->RenderProcessReady(host);
}
} }
} // namespace atom } // namespace atom

View file

@ -109,6 +109,7 @@ class AtomBrowserClient : public brightray::BrowserClient,
// content::RenderProcessHostObserver: // content::RenderProcessHostObserver:
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
void RenderProcessReady(content::RenderProcessHost* host) override;
private: private:
bool ShouldCreateNewSiteInstance(content::RenderFrameHost* render_frame_host, bool ShouldCreateNewSiteInstance(content::RenderFrameHost* render_frame_host,

View file

@ -762,9 +762,13 @@ Disables hardware acceleration for current app.
This method can only be called before app is ready. 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_ ### `app.setBadgeCount(count)` _Linux_ _macOS_

View file

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

View file

@ -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

View file

@ -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 () { it('returns the process memory of all running electron processes', function () {
const appMemoryInfo = app.getAppMemoryInfo() const appMetrics = app.getAppMetrics()
assert.ok(appMemoryInfo.length > 0, 'App memory info object is not > 0') assert.ok(appMetrics.length > 0, 'App memory info object is not > 0')
for (const {memory, pid} of appMemoryInfo) { for (const {memory, pid, type, cpu} of appMetrics) {
assert.ok(memory.workingSetSize > 0, 'working set size is not > 0') assert.ok(memory.workingSetSize > 0, 'working set size is not > 0')
assert.ok(memory.privateBytes > 0, 'private bytes 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(memory.sharedBytes > 0, 'shared bytes is not > 0')
assert.ok(pid > 0, 'pid 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')
} }
}) })
}) })

1
vendor/brightray vendored Submodule

@ -0,0 +1 @@
Subproject commit 28d713bb2a82ba690a21d62522ecd7bad09caba8