Skip to content

Instantly share code, notes, and snippets.

@trevnorris
Created December 1, 2016 22:28
Show Gist options
  • Save trevnorris/ac05bbbef5433c7701b492e8c71352b8 to your computer and use it in GitHub Desktop.
Save trevnorris/ac05bbbef5433c7701b492e8c71352b8 to your computer and use it in GitHub Desktop.
Example of returning all values from uv_rusage() as tuples w/ no overhead. Values are only valid until getrusage() is called again.
{
"targets": [{
"target_name": "addon",
"sources": [ "main.cc" ]
}]
}
#include <v8.h>
#include <node.h>
#include <uv.h>
#define RUSAGE_FIELDS(V) \
V(ru_maxrss) \
V(ru_ixrss) \
V(ru_idrss) \
V(ru_isrss) \
V(ru_minflt) \
V(ru_majflt) \
V(ru_nswap) \
V(ru_inblock) \
V(ru_oublock) \
V(ru_msgsnd) \
V(ru_msgrcv) \
V(ru_nsignals) \
V(ru_nvcsw) \
V(ru_nivcsw)
// Depends on the Isolate being named "isolate" and Local<Context> being
// named "context". Bad me!
#define FORCE_SET_PROP(obj, key, val) \
obj->ForceSet( \
context, NewFromOneByte(isolate, key), val, v8::ReadOnly).FromJust()
namespace bmod {
using namespace v8;
Eternal<Uint32Array> rusage_array_e;
enum rusage_fields {
#define V(field) \
field,
RUSAGE_FIELDS(V)
#undef V
ru_utime,
ru_stime,
rusage_length,
};
static Local<String> NewFromOneByte(Isolate* isolate, const char* name) {
EscapableHandleScope escope(isolate);
const NewStringType type = NewStringType::kInternalized;
Local<String> t_name =
String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(name),
type).ToLocalChecked();
return escope.Escape(t_name);
}
void Setup(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Object> constants = Object::New(isolate);
#define V(field) \
FORCE_SET_PROP(constants, \
#field, \
Integer::New(isolate, rusage_fields::field));
RUSAGE_FIELDS(V)
#undef V
FORCE_SET_PROP(constants,
"ru_utime",
Integer::New(isolate, rusage_fields::ru_utime));
FORCE_SET_PROP(constants,
"ru_stime",
Integer::New(isolate, rusage_fields::ru_stime));
Local<ArrayBuffer> rusage_ab =
ArrayBuffer::New(isolate,
rusage_fields::rusage_length * sizeof(uint32_t) * 2);
Local<Uint32Array> rusage_array =
Uint32Array::New(rusage_ab, 0, rusage_fields::rusage_length * 2);
rusage_array_e.Set(isolate, rusage_array);
FORCE_SET_PROP(constants, "rusage_array", rusage_array);
Local<Object> return_obj = Object::New(isolate);
#define V(field) \
FORCE_SET_PROP( \
return_obj, #field, Uint32Array::New( \
rusage_ab, rusage_fields::field * sizeof(uint32_t) * 2, 2));
RUSAGE_FIELDS(V)
#undef V
FORCE_SET_PROP(
return_obj, "ru_utime", Uint32Array::New(
rusage_ab, rusage_fields::ru_utime * sizeof(uint32_t) * 2, 2));
FORCE_SET_PROP(
return_obj, "ru_stime", Uint32Array::New(
rusage_ab, rusage_fields::ru_stime * sizeof(uint32_t) * 2, 2));
FORCE_SET_PROP(constants, "return_obj", return_obj);
args.GetReturnValue().Set(constants);
}
void GetRusage(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
uv_rusage_t ru;
int err;
err = uv_getrusage(&ru);
if (err) {
fprintf(stderr, "uv_getrusage error\n");
return;
}
uint32_t* data_array = static_cast<uint32_t*>(
rusage_array_e.Get(isolate)->Buffer()->GetContents().Data());
#define V(field) \
data_array[rusage_fields::field * 2] = ru.field & 0xFFFFFFFF; \
data_array[rusage_fields::field * 2 + 1] = ru.field >> 32;
RUSAGE_FIELDS(V)
#undef V
data_array[rusage_fields::ru_utime * 2] = ru.ru_utime.tv_sec;
data_array[rusage_fields::ru_utime * 2 + 1] = ru.ru_utime.tv_usec;
data_array[rusage_fields::ru_stime * 2] = ru.ru_stime.tv_sec;
data_array[rusage_fields::ru_stime * 2 + 1] = ru.ru_stime.tv_usec;
}
void init(Handle<Object> exports) {
NODE_SET_METHOD(exports, "setup", Setup);
NODE_SET_METHOD(exports, "getRusage", GetRusage);
}
} // namespace bmod
NODE_MODULE(addon, bmod::init)
'use strict';
const addon = require('./build/Release/addon');
const print = process._rawDebug;
const data_obj = addon.setup();
const frozen_return_obj = Object.freeze(data_obj.return_obj);
// Return a frozen object that contains all the uint64_t fields of
// uv_getrusage() as a tuple from slices of a single Uint32Array and allow
// the user to retrieve/convert only the values they're looking for. The
// returned values must be copied out because they're only guaranteed for
// the duration of the function call.
function getrusage() {
addon.getRusage();
return frozen_return_obj;
}
// Convert a uint32 tuple into a double. Useful if exact precision isn't
// needed.
function two32ToDouble(tuple) {
return tuple[0] + tuple[1] * 0x100000000;
}
const ITER = 1e6;
var t = process.hrtime();
(function runner() {
for (var i = 0; i < ITER; i++) {
// Every time getrusage() is called the previous set of values is
// overwritten.
const obj = getrusage();
two32ToDouble(obj.ru_maxrss);
}
})();
printTime();
print(getrusage());
function printTime() {
t = process.hrtime(t);
print(((t[0] * 1e9 + t[1]) / ITER).toFixed(1) + ' ns/op');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment