Skip to content

Instantly share code, notes, and snippets.

@trevnorris
Last active September 1, 2016 08:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trevnorris/939c7f3990b0e19a71bb2999002c893e to your computer and use it in GitHub Desktop.
Save trevnorris/939c7f3990b0e19a71bb2999002c893e to your computer and use it in GitHub Desktop.
V8 + libuv API to return the CPU% utilization for given duration.
#include <v8.h>
#include <node.h>
#include <uv.h>
#include <assert.h>
#define MICROS_PER_SEC 1e6
static uint64_t cpu_speed_hz;
static uint64_t previous_total;
static uint64_t previous_time;
namespace bmod {
using v8::Array;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Map;
using v8::NewStringType;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
static Local<String> NewFromOneByte(Isolate* isolate, const char* name) {
// kInternalized strings are created in the old space.
const NewStringType type = NewStringType::kInternalized;
Local<String> t_name =
String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(name),
type).ToLocalChecked();
return t_name;
}
void Run(const FunctionCallbackInfo<Value>& args) {
uv_cpu_info_t* cpus;
int count;
int err;
err = uv_cpu_info(&cpus, &count);
assert(err == 0);
assert(count > 0);
// Grab the max CPU speed.
int max_cpu_speed = 0;
for (int i = 0; i < count; i++) {
auto cpu_times = cpus[i].cpu_times;
fprintf(stderr, "user: %lu nice: %lu sys: %lu idle: %lu irq: %lu\n",
cpu_times.user, cpu_times.nice, cpu_times.sys, cpu_times.idle,
cpu_times.irq);
fprintf(stderr, "sum: %lu\n",
cpu_times.user + cpu_times.sys + cpu_times.idle);
if (max_cpu_speed < cpus[i].speed)
max_cpu_speed = cpus[i].speed;
}
cpu_speed_hz = max_cpu_speed * 1e6L;
uv_free_cpu_info(cpus, count);
args.GetReturnValue().Set(max_cpu_speed);
}
void CpuUsage(const FunctionCallbackInfo<Value>& args) {
uv_rusage_t rusage;
int err;
err = uv_getrusage(&rusage);
assert(err == 0);
Local<Object> vals = Object::New(args.GetIsolate());
double user =
MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
double sys =
MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
vals->Set(NewFromOneByte(args.GetIsolate(), "user"),
Number::New(args.GetIsolate(), user));
vals->Set(NewFromOneByte(args.GetIsolate(), "system"),
Number::New(args.GetIsolate(), sys));
args.GetReturnValue().Set(user);
}
void ProcessUsage(const FunctionCallbackInfo<Value>& args) {
uv_rusage_t rusage;
int err;
err = uv_getrusage(&rusage);
assert(err == 0);
uint64_t current_time = uv_hrtime();
// uv_hrtime() returns nanoseconds, so convert to microseconds up ahead.
uint64_t elapsed_us = (current_time - previous_time);
// Convert this to microseconds.
uint64_t total =
(MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec) +
(MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec);
// * 100 so it's a %, * 1000 to turn microseconds to nanoseconds. For saftey
// of not dividing by zero.
double percent = (total - previous_total) * 100.0 * 1000.0 / elapsed_us;
previous_total = total;
previous_time = current_time;
args.GetReturnValue().Set(percent);
}
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "run", Run);
NODE_SET_METHOD(exports, "cpuUsage", CpuUsage);
NODE_SET_METHOD(exports, "processUsage", ProcessUsage);
// Set the first previous_total correctly or the first call will return
// gibberish.
uv_rusage_t rusage;
assert(uv_getrusage(&rusage) == 0);
previous_total =
(MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec) +
(MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec);
previous_time = uv_hrtime();
}
} // namespace bmod
NODE_MODULE(addon, bmod::Init)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment