Last active
September 1, 2016 08:31
-
-
Save trevnorris/939c7f3990b0e19a71bb2999002c893e to your computer and use it in GitHub Desktop.
V8 + libuv API to return the CPU% utilization for given duration.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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