From 574cd89522e3a71f98bef5be553204082c303032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Guti=C3=A9rrez=20Hermoso?= Date: Thu, 17 Mar 2022 12:14:20 -0400 Subject: [PATCH] RUSageMeter: remove C++ class and associated bindings and tests The native CPU metric instrumentation isn't needed anymore since Node.js version 12 provides bindings of its own for this data. We don't use the non-CPU metrics provided by RUSageMeter (memory, context switches, etc) so it's okay to remove this feature wholesale. A corresponding change in the calling code in the main agent repo is forthcoming. Fixes https://github.com/newrelic/node-native-metrics/issues/154 --- binding.gyp | 4 +- index.js | 56 +------------------- src/RUsageMeter.cpp | 103 ------------------------------------- src/RUsageMeter.hpp | 77 --------------------------- src/native_metrics.cpp | 2 - tests/unit/ru-meter.tap.js | 89 -------------------------------- 6 files changed, 2 insertions(+), 329 deletions(-) delete mode 100644 src/RUsageMeter.cpp delete mode 100644 src/RUsageMeter.hpp delete mode 100644 tests/unit/ru-meter.tap.js diff --git a/binding.gyp b/binding.gyp index 9caf9d8..7cd9fc4 100644 --- a/binding.gyp +++ b/binding.gyp @@ -7,9 +7,7 @@ "src/GCBinder.cpp", "src/LoopChecker.hpp", "src/LoopChecker.cpp", - "src/Metric.hpp", - "src/RUsageMeter.hpp", - "src/RUsageMeter.cpp" + "src/Metric.hpp" ], "defines": [ "NOMINMAX" diff --git a/index.js b/index.js index 177ae75..2b3235b 100644 --- a/index.js +++ b/index.js @@ -39,9 +39,6 @@ function NativeMetricEmitter(opts) { this.bound = false this._timeout = null - this._rusageMeter = new natives.RUsageMeter() - this.usageEnabled = true - this._gcBinder = new natives.GCBinder() this.gcEnabled = true @@ -52,36 +49,6 @@ function NativeMetricEmitter(opts) { } util.inherits(NativeMetricEmitter, EventEmitter) -/** - * @interface RUsageStats - * - * @description - * Resource usage statistics. - * - * Properties marked (X) are unmaintained by the operating system and are - * likely to be just `0`. - * - * @property {number} ru_utime - user CPU time used in milliseconds - * @property {number} ru_stime - system CPU time used in milliseconds - * @property {number} ru_maxrss - maximum resident set size in bytes - * @property {number} ru_ixrss - integral shared memory size (X) - * @property {number} ru_idrss - integral unshared data size (X) - * @property {number} ru_isrss - integral unshared stack size (X) - * @property {number} ru_minflt - page reclaims (soft page faults) (X) - * @property {number} ru_majflt - page faults (hard page faults) - * @property {number} ru_nswap - swaps (X) - * @property {number} ru_inblock - block input operations - * @property {number} ru_oublock - block output operations - * @property {number} ru_msgsnd - IPC messages sent (X) - * @property {number} ru_msgrcv - IPC messages received (X) - * @property {number} ru_nsignals - signals received (X) - * @property {number} ru_nvcsw - voluntary context switches (X) - * @property {number} ru_nivcsw - involuntary context switches (X) - * - * @see http://docs.libuv.org/en/v1.x/misc.html#c.uv_getrusage - * @see http://docs.libuv.org/en/v1.x/misc.html#c.uv_rusage_t - */ - /** * @interface LoopMetrics * @@ -125,34 +92,14 @@ util.inherits(NativeMetricEmitter, EventEmitter) * @param {number} [timeout] * The number of milliseconds between samplings. Defaults to 15 seconds. */ -NativeMetricEmitter.prototype.bind = function bind(timeout) { +NativeMetricEmitter.prototype.bind = function bind() { if (this.bound) { return } - timeout = timeout || DEFAULT_TIMEOUT this._gcBinder.bind() this._loopChecker.bind() - this._timeout = setTimeout(nativeMetricTimeout.bind(this), timeout).unref() - function nativeMetricTimeout() { - if (this._rusageMeter) { - /** - * Resource usage sampling event. - * - * @event NativeMetricEmitter#usage - * @type {object} - * - * @property {RUsageStats} diff - The change in stats since last sampling. - * @property {RUsageStats} current - The current usage statistics. - */ - this.emit('usage', this._rusageMeter.read()) - } - if (this.bound) { - this._timeout = setTimeout(nativeMetricTimeout.bind(this), timeout).unref() - } - } - this.bound = true } @@ -166,7 +113,6 @@ NativeMetricEmitter.prototype.unbind = function unbind() { this._gcBinder.unbind() this._loopChecker.unbind() - clearTimeout(this._timeout) this.bound = false } diff --git a/src/RUsageMeter.cpp b/src/RUsageMeter.cpp deleted file mode 100644 index ef35340..0000000 --- a/src/RUsageMeter.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - - -#include -#include -#include - -#include "RUsageMeter.hpp" - -namespace nr { - -NAN_METHOD(RUsageMeter::Read) { - Nan::HandleScope scope; - - // Update our stats. - RUsageMeter* self = RUsageMeter::Unwrap(info.This()); - self->_read(); - - // Build the results object. - v8::Local results = Nan::New(); - Nan::Set( - results, - Nan::New("diff").ToLocalChecked(), - self->_usageToJSObj(self->_usageDiff) - ); - Nan::Set( - results, - Nan::New("current").ToLocalChecked(), - self->_usageToJSObj(self->_lastUsage) - ); - - // Return the results. - info.GetReturnValue().Set(results); -} - -void RUsageMeter::_read() { - uv_rusage_t nextUsage; - uv_getrusage(&nextUsage); - - #define DIFF(X) _usageDiff.X = nextUsage.X - _lastUsage.X - DIFF(ru_utime.tv_sec); - DIFF(ru_utime.tv_usec); - DIFF(ru_stime.tv_sec); - DIFF(ru_stime.tv_usec); - DIFF(ru_maxrss); - DIFF(ru_ixrss); - DIFF(ru_idrss); - DIFF(ru_isrss); - DIFF(ru_minflt); - DIFF(ru_majflt); - DIFF(ru_nswap); - DIFF(ru_inblock); - DIFF(ru_oublock); - DIFF(ru_msgsnd); - DIFF(ru_msgrcv); - DIFF(ru_nsignals); - DIFF(ru_nvcsw); - DIFF(ru_nivcsw); - #undef DIFF - - std::memcpy(&_lastUsage, &nextUsage, sizeof(uv_rusage_t)); -} - -v8::Local RUsageMeter::_usageToJSObj(const uv_rusage_t& usage) { - // Convert the CPU times into millisecond floating point values. - double utime = ( - (double)(usage.ru_utime.tv_sec * 1000.0) + - (double)(usage.ru_utime.tv_usec / 1000.0) - ); - double stime = ( - (double)(usage.ru_stime.tv_sec * 1000.0) + - (double)(usage.ru_stime.tv_usec / 1000.0) - ); - - // Copy all the values to V8 objects. - v8::Local obj = Nan::New(); - #define SET(key, val) \ - Nan::Set(obj, Nan::New(key).ToLocalChecked(), Nan::New((double)val)) - SET("ru_utime", utime); - SET("ru_stime", stime); - SET("ru_maxrss", usage.ru_maxrss); - SET("ru_ixrss", usage.ru_ixrss); - SET("ru_idrss", usage.ru_idrss); - SET("ru_isrss", usage.ru_isrss); - SET("ru_minflt", usage.ru_minflt); - SET("ru_majflt", usage.ru_majflt); - SET("ru_nswap", usage.ru_nswap); - SET("ru_inblock", usage.ru_inblock); - SET("ru_oublock", usage.ru_oublock); - SET("ru_msgsnd", usage.ru_msgsnd); - SET("ru_msgrcv", usage.ru_msgrcv); - SET("ru_nsignals", usage.ru_nsignals); - SET("ru_nvcsw", usage.ru_nvcsw); - SET("ru_nivcsw", usage.ru_nivcsw); - #undef SET - - return obj; -} - -} diff --git a/src/RUsageMeter.hpp b/src/RUsageMeter.hpp deleted file mode 100644 index 472d5af..0000000 --- a/src/RUsageMeter.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include - -namespace nr { - -class RUsageMeter : public Nan::ObjectWrap { -public: - /** - * Initialze the RUsageMeter JS class. - */ - static NAN_MODULE_INIT(Init) { - v8::Local clas = Nan::New(New); - clas->SetClassName(Nan::New("RUsageMeter").ToLocalChecked()); - clas->InstanceTemplate()->SetInternalFieldCount(1); - - SetPrototypeMethod(clas, "read", Read); - - constructor().Reset(Nan::GetFunction(clas).ToLocalChecked()); - Nan::Set( - target, - Nan::New("RUsageMeter").ToLocalChecked(), - Nan::GetFunction(clas).ToLocalChecked() - ); - } - - /** - * JS constructor. - */ - static NAN_METHOD(New) { - RUsageMeter* obj = new RUsageMeter(); - obj->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - } - - /** - * Performs internal update of resource usage and returns the diff. - * - * @return The diff of the last usage reading and this one. - */ - static NAN_METHOD(Read); - - RUsageMeter() { - std::memset(&_lastUsage, 0, sizeof(uv_rusage_t)); - } - -private: - static inline Nan::Persistent & constructor() { - // ??? - static Nan::Persistent _constructor; - return _constructor; - } - - /** - * Fetches the latest resource usage numbers from libuv and updates the diff. - */ - void _read(); - - /** - * Copies `uv_rusage_t` instances into new JS objects. - * - * @param usage The resource usage stats to copy. - * - * @return A JS object containing all the values of the given usage data. - */ - v8::Local _usageToJSObj(const uv_rusage_t& usage); - - uv_rusage_t _usageDiff; - uv_rusage_t _lastUsage; -}; - -} diff --git a/src/native_metrics.cpp b/src/native_metrics.cpp index 84e903a..9003e81 100644 --- a/src/native_metrics.cpp +++ b/src/native_metrics.cpp @@ -8,14 +8,12 @@ #include "GCBinder.hpp" #include "LoopChecker.hpp" -#include "RUsageMeter.hpp" namespace nr { NAN_MODULE_INIT(Init) { Nan::HandleScope scope; GCBinder::Init(target); - RUsageMeter::Init(target); LoopChecker::Init(target); } diff --git a/tests/unit/ru-meter.tap.js b/tests/unit/ru-meter.tap.js deleted file mode 100644 index 5b0fd4e..0000000 --- a/tests/unit/ru-meter.tap.js +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const tap = require('tap') - -tap.test('Resource Usage Meter', function (t) { - const CPU_EPSILON = 50 // Allowed fudge factor for CPU times in MS - const SPIN_TIME = 2000 - const metricEmitter = require('../../')({ timeout: 200 }) - - // set a timeout to keep the process from closing before the tests - // complete - setTimeout(function () {}, SPIN_TIME) - - t.teardown(function () { - metricEmitter.unbind() - }) - - let firstUsage = null - metricEmitter.on('usage', function (data) { - t.comment('usage emitted') - if (!t.type(data, Object, 'should have usage data object')) { - return t.end() - } - t.type(data.diff, Object, 'should have usage diff data object') - t.type(data.current, Object, 'should have usage current data object') - if (!t.passing()) { - return t.end() - } - - if (!firstUsage) { - firstUsage = data - process.nextTick(spin) - } else { - checkValues(firstUsage, data) - } - }) - - function spin() { - const start = Date.now() - while (Date.now() - start < SPIN_TIME) {} // Spin the CPU for 2 seconds. - t.comment('cpu spin completed') - } - - function checkValues(startUsage, usage) { - const keys = [ - 'ru_utime', - 'ru_stime', - 'ru_maxrss', - 'ru_ixrss', - 'ru_idrss', - 'ru_isrss', - 'ru_minflt', - 'ru_majflt', - 'ru_nswap', - 'ru_inblock', - 'ru_oublock', - 'ru_msgsnd', - 'ru_msgrcv', - 'ru_nsignals', - 'ru_nvcsw', - 'ru_nivcsw' - ] - keys.forEach(function (key) { - t.comment(key) - t.type(usage.diff[key], 'number', 'usage.diff should have key') - t.type(usage.current[key], 'number', 'usage.current should have key') - - t.equal( - cleanFloat(usage.diff[key]), - cleanFloat(usage.current[key] - startUsage.current[key]), - 'usage.diff should be difference between last reading and this reading' - ) - }) - - t.comment('cpu usage') - const time = usage.diff.ru_utime + usage.diff.ru_stime - t.ok(time > SPIN_TIME - CPU_EPSILON, 'should have expected CPU usage time (is ' + time + ')') - t.end() - } -}) - -function cleanFloat(num) { - return Math.round(num * 1000) / 1000 -}