8000 feat: add memory to app.getAppMetrics() by miniak · Pull Request #18831 · electron/electron · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: add memory to app.getAppMetrics() #18831

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/api/structures/memory-info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# MemoryInfo Object

* `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 (optional) _Windows_ - The amount of memory not shared by other processes, such as
JS heap or HTML content.

Note that all statistics are reported in Kilobytes.
1 change: 1 addition & 0 deletions docs/api/structures/process-metric.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
The time is represented as number of milliseconds since epoch.
Since the `pid` can be reused after a process dies,
it is useful to use both the `pid` and the `creationTime` to uniquely identify a process.
* `memory` [MemoryInfo](memory-info.md) - Memory information for the process.
* `sandboxed` Boolean (optional) _macOS_ _Windows_ - Whether the process is sandboxed on OS level.
* `integrityLevel` String (optional) _Windows_ - One of the following values:
* `untrusted`
Expand Down
1 change: 1 addition & 0 deletions filenames.auto.gni
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ auto_filenames = {
"docs/api/structures/jump-list-category.md",
"docs/api/structures/jump-list-item.md",
"docs/api/structures/keyboard-event.md",
"docs/api/structures/memory-info.md",
"docs/api/structures/memory-usage-details.md",
"docs/api/structures/mime-typed-buffer.md",
"docs/api/structures/notification-action.md",
Expand Down
38 changes: 38 additions & 0 deletions lib/browser/api/app.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as fs from 'fs'
import * as path from 'path'

import { deprecate, Menu } from 'electron'
Expand Down Expand Up @@ -66,6 +67,43 @@ if (process.platform === 'darwin') {
app.dock!.getMenu = () => dockMenu
}

if (process.platform === 'linux') {
const patternVmRSS = /^VmRSS:\s*(\d+) kB$/m
const patternVmHWM = /^VmHWM:\s*(\d+) kB$/m

const getStatus = (pid: number) => {
try {
return fs.readFileSync(`/proc/${pid}/status`, 'utf8')
} catch {
return ''
}
}

const getEntry = (file: string, pattern: RegExp) => {
const match = file.match(pattern)
return match ? parseInt(match[1], 10) : 0
}

const getProcessMemoryInfo = (pid: number) => {
const file = getStatus(pid)

return {
workingSetSize: getEntry(file, patternVmRSS),
peakWorkingSetSize: getEntry(file, patternVmHWM)
}
}

const nativeFn = app.getAppMetrics
app.getAppMetrics = () => {
const metrics = nativeFn.call(app)
for (const metric of metrics) {
metric.memory = getProcessMemoryInfo(metric.pid)
}

return metrics
}
}

// Routes the events to webContents.
const events = ['login', 'certificate-error', 'select-client-certificate']
for (const name of events) {
Expand Down
19 changes: 19 additions & 0 deletions shell/browser/api/atom_api_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,25 @@ std::vector<mate::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
pid_dict.Set("creationTime",
process_metric.second->process.CreationTime().ToJsTime());

#if !defined(OS_LINUX)
auto memory_info = process_metric.second->GetMemoryInfo();

mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate);
memory_dict.SetHidden("simple", true);
memory_dict.Set("workingSetSize",
static_cast<double>(memory_info.working_set_size >> 10));
memory_dict.Set(
"peakWorkingSetSize",
static_cast<double>(memory_info.peak_working_set_size >> 10));

#if defined(OS_WIN)
memory_dict.Set("privateBytes",
static_cast<double>(memory_info.private_bytes >> 10));
#endif

pid_dict.Set("memory", memory_dict);
#endif

#if defined(OS_MACOSX)
pid_dict.Set("sandboxed", process_metric.second->IsSandboxed());
#elif defined(OS_WIN)
Expand Down
61 changes: 60 additions & 1 deletion shell/browser/api/process_metric.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,46 @@
#include <memory>
#include <utility>

#include "base/optional.h"

#if defined(OS_WIN)
#include <windows.h>

#include <psapi.h>
#include "base/win/win_util.h"
#endif

#if defined(OS_MACOSX)
#include <mach/mach.h>
#include "base/process/port_provider_mac.h"
#include "content/public/browser/browser_child_process_host.h"

extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);
#endif

namespace {

mach_port_t TaskForPid(pid_t pid) {
mach_port_t task = MACH_PORT_NULL;
if (auto* port_provider = content::BrowserChildProcessHost::GetPortProvider())
task = port_provider->TaskForPid(pid);
if (task == MACH_PORT_NULL && pid == getpid())
task = mach_task_self();
return task;
}

base::Optional<mach_task_basic_info_data_t> GetTaskInfo(mach_port_t task) {
if (task == MACH_PORT_NULL)
return base::nullopt;
mach_task_basic_info_data_t info = {};
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t kr = task_info(task, MACH_TASK_BASIC_INFO,
reinterpret_cast<task_info_t>(&info), &count);
return (kr == KERN_SUCCESS) ? base::make_optional(info) : base::nullopt;
}

} // namespace

#endif // defined(OS_MACOSX)

namespace electron {

Expand All @@ -37,6 +70,21 @@ ProcessMetric::~ProcessMetric() = default;

#if defined(OS_WIN)

ProcessMemoryInfo ProcessMetric::GetMemoryInfo() const {
ProcessMemoryInfo result;

PROCESS_MEMORY_COUNTERS_EX info = {};
if (::GetProcessMemoryInfo(process.Handle(),
reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&info),
sizeof(info))) {
result.working_set_size = info.WorkingSetSize;
result.peak_working_set_size = info.PeakWorkingSetSize;
result.private_bytes = info.PrivateUsage;
}

return result;
}

ProcessIntegrityLevel ProcessMetric::GetIntegrityLevel() const {
HANDLE token = nullptr;
if (!::OpenProcessToken(process.Handle(), TOKEN_QUERY, &token)) {
Expand Down Expand Up @@ -96,6 +144,17 @@ bool 2E18 ProcessMetric::IsSandboxed(ProcessIntegrityLevel integrity_level) {

#elif defined(OS_MACOSX)

ProcessMemoryInfo ProcessMetric::GetMemoryInfo() const {
ProcessMemoryInfo result;

if (auto info = GetTaskInfo(TaskForPid(process.Pid()))) {
result.working_set_size = info->resident_size;
result.peak_working_set_size = info->resident_size_max;
}

return result;
}

bool ProcessMetric::IsSandboxed() const {
#if defined(MAS_BUILD)
return true;
Expand Down
14 changes: 14 additions & 0 deletions shell/browser/api/process_metric.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@

namespace electron {

#if !defined(OS_LINUX)
struct ProcessMemoryInfo {
size_t working_set_size = 0;
size_t peak_working_set_size = 0;
#if defined(OS_WIN)
size_t private_bytes = 0;
#endif
};
#endif

#if defined(OS_WIN)
enum class ProcessIntegrityLevel {
Unknown,
Expand All @@ -33,6 +43,10 @@ struct ProcessMetric {
std::unique_ptr<base::ProcessMetrics> metrics);
~ProcessMetric();

#if !defined(OS_LINUX)
ProcessMemoryInfo GetMemoryInfo() const;
#endif

#if defined(OS_WIN)
ProcessIntegrityLevel GetIntegrityLevel() const;
static bool IsSandboxed(ProcessIntegrityLevel integrity_level);
Expand Down
7 changes: 7 additions & 0 deletions spec-main/api-app-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,13 @@ describe('app module', () => {
expect(entry.cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number')
expect(entry.cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number')

expect(entry.memory).to.have.property('workingSetSize').that.is.greaterThan(0)
expect(entry.memory).to.have.property('peakWorkingSetSize').that.is.greaterThan(0)

if (process.platform === 'win32') {
expect(entry.memory).to.have.property('privateBytes').that.is.greaterThan(0)
}

if (process.platform !== 'linux') {
expect(entry.sandboxed).to.be.a('boolean')
}
Expand Down
0