Skip to content

Commit

Permalink
report: support RUSAGE_SELF stats on Windows
Browse files Browse the repository at this point in the history
This commit adds support for the resourceUsage report section
on Windows by using uv_getrusage() instead of getrusage().

PR-URL: nodejs#26406
Reviewed-By: Richard Lau <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
  • Loading branch information
cjihrig authored and BridgeAR committed Mar 12, 2019
1 parent 2a3cca7 commit 0abb724
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 38 deletions.
26 changes: 10 additions & 16 deletions src/node_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ static void PrintJavaScriptStack(JSONWriter* writer,
Local<String> stackstr,
const char* trigger);
static void PrintNativeStack(JSONWriter* writer);
#ifndef _WIN32
static void PrintResourceUsage(JSONWriter* writer);
#endif
static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate);
static void PrintSystemInformation(JSONWriter* writer);
static void PrintLoadedLibraries(JSONWriter* writer);
Expand Down Expand Up @@ -289,9 +287,7 @@ static void WriteNodeReport(Isolate* isolate,
PrintGCStatistics(&writer, isolate);

// Report OS and current thread resource usage
#ifndef _WIN32
PrintResourceUsage(&writer);
#endif

writer.json_arraystart("libuv");
if (env != nullptr) {
Expand Down Expand Up @@ -466,39 +462,38 @@ static void PrintGCStatistics(JSONWriter* writer, Isolate* isolate) {
writer->json_objectend();
}

#ifndef _WIN32
// Report resource usage (Linux/OSX only).
static void PrintResourceUsage(JSONWriter* writer) {
// Get process uptime in seconds
uint64_t uptime =
(uv_hrtime() - node::per_process::node_start_time) / (NANOS_PER_SEC);
if (uptime == 0) uptime = 1; // avoid division by zero.

// Process and current thread usage statistics
struct rusage stats;
uv_rusage_t rusage;
writer->json_objectstart("resourceUsage");
if (getrusage(RUSAGE_SELF, &stats) == 0) {
if (uv_getrusage(&rusage) == 0) {
double user_cpu =
stats.ru_utime.tv_sec + SEC_PER_MICROS * stats.ru_utime.tv_usec;
rusage.ru_utime.tv_sec + SEC_PER_MICROS * rusage.ru_utime.tv_usec;
double kernel_cpu =
stats.ru_stime.tv_sec + SEC_PER_MICROS * stats.ru_stime.tv_usec;
rusage.ru_stime.tv_sec + SEC_PER_MICROS * rusage.ru_stime.tv_usec;
writer->json_keyvalue("userCpuSeconds", user_cpu);
writer->json_keyvalue("kernelCpuSeconds", kernel_cpu);
double cpu_abs = user_cpu + kernel_cpu;
double cpu_percentage = (cpu_abs / uptime) * 100.0;
writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
writer->json_keyvalue("maxRss", stats.ru_maxrss * 1024);
writer->json_keyvalue("maxRss", rusage.ru_maxrss * 1024);
writer->json_objectstart("pageFaults");
writer->json_keyvalue("IORequired", stats.ru_majflt);
writer->json_keyvalue("IONotRequired", stats.ru_minflt);
writer->json_keyvalue("IORequired", rusage.ru_majflt);
writer->json_keyvalue("IONotRequired", rusage.ru_minflt);
writer->json_objectend();
writer->json_objectstart("fsActivity");
writer->json_keyvalue("reads", stats.ru_inblock);
writer->json_keyvalue("writes", stats.ru_oublock);
writer->json_keyvalue("reads", rusage.ru_inblock);
writer->json_keyvalue("writes", rusage.ru_oublock);
writer->json_objectend();
}
writer->json_objectend();
#ifdef RUSAGE_THREAD
struct rusage stats;
if (getrusage(RUSAGE_THREAD, &stats) == 0) {
writer->json_objectstart("uvthreadResourceUsage");
double user_cpu =
Expand All @@ -518,7 +513,6 @@ static void PrintResourceUsage(JSONWriter* writer) {
}
#endif
}
#endif

// Report operating system information.
static void PrintSystemInformation(JSONWriter* writer) {
Expand Down
42 changes: 20 additions & 22 deletions test/common/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ function _validateContent(data) {
// Verify that all sections are present as own properties of the report.
const sections = ['header', 'javascriptStack', 'nativeStack',
'javascriptHeap', 'libuv', 'environmentVariables',
'sharedObjects'];
'sharedObjects', 'resourceUsage'];
if (!isWindows)
sections.push('resourceUsage', 'userLimits');
sections.push('userLimits');

if (report.uvthreadResourceUsage)
sections.push('uvthreadResourceUsage');
Expand Down Expand Up @@ -133,26 +133,24 @@ function _validateContent(data) {
});
});

// Verify the format of the resourceUsage section on non-Windows platforms.
if (!isWindows) {
const usage = report.resourceUsage;
const resourceUsageFields = ['userCpuSeconds', 'kernelCpuSeconds',
'cpuConsumptionPercent', 'maxRss',
'pageFaults', 'fsActivity'];
checkForUnknownFields(usage, resourceUsageFields);
assert.strictEqual(typeof usage.userCpuSeconds, 'number');
assert.strictEqual(typeof usage.kernelCpuSeconds, 'number');
assert.strictEqual(typeof usage.cpuConsumptionPercent, 'number');
assert(Number.isSafeInteger(usage.maxRss));
assert(typeof usage.pageFaults === 'object' && usage.pageFaults !== null);
checkForUnknownFields(usage.pageFaults, ['IORequired', 'IONotRequired']);
assert(Number.isSafeInteger(usage.pageFaults.IORequired));
assert(Number.isSafeInteger(usage.pageFaults.IONotRequired));
assert(typeof usage.fsActivity === 'object' && usage.fsActivity !== null);
checkForUnknownFields(usage.fsActivity, ['reads', 'writes']);
assert(Number.isSafeInteger(usage.fsActivity.reads));
assert(Number.isSafeInteger(usage.fsActivity.writes));
}
// Verify the format of the resourceUsage section.
const usage = report.resourceUsage;
const resourceUsageFields = ['userCpuSeconds', 'kernelCpuSeconds',
'cpuConsumptionPercent', 'maxRss',
'pageFaults', 'fsActivity'];
checkForUnknownFields(usage, resourceUsageFields);
assert.strictEqual(typeof usage.userCpuSeconds, 'number');
assert.strictEqual(typeof usage.kernelCpuSeconds, 'number');
assert.strictEqual(typeof usage.cpuConsumptionPercent, 'number');
assert(Number.isSafeInteger(usage.maxRss));
assert(typeof usage.pageFaults === 'object' && usage.pageFaults !== null);
checkForUnknownFields(usage.pageFaults, ['IORequired', 'IONotRequired']);
assert(Number.isSafeInteger(usage.pageFaults.IORequired));
assert(Number.isSafeInteger(usage.pageFaults.IONotRequired));
assert(typeof usage.fsActivity === 'object' && usage.fsActivity !== null);
checkForUnknownFields(usage.fsActivity, ['reads', 'writes']);
assert(Number.isSafeInteger(usage.fsActivity.reads));
assert(Number.isSafeInteger(usage.fsActivity.writes));

// Verify the format of the uvthreadResourceUsage section, if present.
if (report.uvthreadResourceUsage) {
Expand Down

0 comments on commit 0abb724

Please sign in to comment.