繁体   English   中英

通过 NodeJS 获取/查看 Memory 和 CPU 使用率

[英]Get/View Memory & CPU usage via NodeJS

我看到有几个节点包可以让你查找特定进程的使用情况,例如https://www.npmjs.com/package/usage

我正在尝试获取总体服务器使用情况/统计信息(CPU 和内存),而不仅仅是一个特定的进程或另一个。 甚至磁盘空间使用情况。

我目前找不到这样的东西,这可能吗?

本机模块os可以为您提供一些内存和 cpu 使用情况统计信息。

var os = require('os');

console.log(os.cpus());
console.log(os.totalmem());
console.log(os.freemem())

cpus() 函数为您提供平均值,但您可以使用公式和间隔来计算当前使用情况,如答案中所述。

还有一个包可以为您执行此操作,称为os-utils

取自github上的示例:

var os = require('os-utils');

os.cpuUsage(function(v){
    console.log( 'CPU Usage (%): ' + v );
});

有关磁盘的信息,您可以使用diskspace

检查node-os-utils

  • CPU平均使用率
  • 可用和已用驱动器空间
  • 可用和已用内存空间
  • 操作系统
  • 正在运行的所有进程
  • TTY/SSH 打开
  • 打开的文件总数
  • 网络速度(输入和输出)
 var osu = require('node-os-utils') var cpu = osu.cpu cpu.usage() .then(info => { console.log(info) })

由于我找不到解决此问题的代码,并且不想仅仅为了某些代码行而依赖其他包,因此我编写了一个 function 来计算两个连续的 function 调用之间的平均 CPU 负载。 我假设t_idle + t_user + t_sys = total cpu time and results are kind of similar to the ones of my Windows task manager, however, usage seems small more sensitive to me (eg music playback increases cpu load more than in the Windows任务管理器)。 如果我的假设是错误的,请纠正我。

const os = require('os');

// Initial value; wait at little amount of time before making a measurement.
let timesBefore = os.cpus().map(c => c.times);

// Call this function periodically e.g. using setInterval, 
function getAverageUsage() {
    let timesAfter = os.cpus().map(c => c.times);
    let timeDeltas = timesAfter.map((t, i) => ({
        user: t.user - timesBefore[i].user,
        sys: t.sys - timesBefore[i].sys,
        idle: t.idle - timesBefore[i].idle
    }));

    timesBefore = timesAfter;

    return timeDeltas
        .map(times => 1 - times.idle / (times.user + times.sys + times.idle))
        .reduce((l1, l2) => l1 + l2) / timeDeltas.length;
}

您还可以使用process.cpuUsage()以微秒为单位返回系统和用户 cpu 时间。 它还可以计算与先前调用的差异。

https://nodejs.org/api/process.html#process_process_cpuusage_previousvalue

Node.js 有os.loadavg()方法

// Require os module
const os = require('os');

// Printing os.loadavg() value
var avg_load = os.loadavg();

console.log("Load average (1 minute):"
            + String(avg_load[0]));

console.log("Load average (5 minute):"
            + String(avg_load[1]));

console.log("Load average (15 minute):"
            + String(avg_load[2]));

更多信息在这里

async function getinfo() {
 const cpu = await si.cpu();
 const disk = (await si.diskLayout())[0];
 const os = await si.osInfo();
 const versions = await si.versions();
 const ram = await si.mem();

 // CPU Info
 let info = `CPU: ${cpu.manufacturer} ${cpu.brand} ${cpu.speed}GHz\n`;
 info += `Cores: ${cpu.cores} (${cpu.physicalCores} Physical)\n`;

 // RAM Info
 const totalRam = Math.round(ram.total / 1024 / 1024 / 1024);
 info += `RAM: ${totalRam}GB\n`;

 // Disk Info
 const size = Math.round(disk.size / 1024 / 1024 / 1024);
 info += `Disk: ${disk.vendor} ${disk.name} ${size}GB ${disk.type} (${disk.interfaceType})\n`;

 //OS Info
 info += `OS: ${os.distro} ${os.codename} (${os.platform})\n`;
 info += `Kernel: ${os.kernel} ${os.arch}\n`;

 // Node Info
 info += `Node: v${versions.node}\n`;
 info += `V8: ${versions.v8}`;
 return info;
}

当然这是可能的。 但是您需要一个 C++ 本机模块来做到这一点。 请记住,每个操作系统都有自己的查询系统资源使用情况的方式。

例如,如果你在 Windows 上(这可能是你正在寻找的,因为usage不支持 Windows),你可以做类似的事情

性能.cpp

#include <node.h>
#include "performance_algorithm.hpp"

using namespace v8;

void InitAll(Handle<Object> exports) {
    PerformanceAlgorithm::Initialize();
    PerformanceAlgorithm::RegisterMethod(exports);
}

NODE_MODULE(Performance, InitAll)

性能算法.cpp

#include <algorithm>

#include "baton.hpp"
#include "structs.hpp"
#include "performance_algorithm.hpp"

void PerformanceAlgorithm::Initialize() {
    PdhOpenQuery(NULL, NULL, &cpuQuery);
    PdhAddCounter(cpuQuery, "\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);
    PdhCollectQueryData(cpuQuery);
}

void PerformanceAlgorithm::RegisterMethod(Handle<Object> exports) {
    NODE_SET_METHOD(exports, "getPerformanceData", PerformanceAlgorithm::GetPerformanceDataAsync);
}

void PerformanceAlgorithm::GetPerformanceDataAsync(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    if (args.Length() != 1) {
        isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
    } else {
        if (!args[0]->IsFunction()) {
            isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong arguments type")));
        } else {
            Local<Function> callbackFunction = Local<Function>::Cast(args[0]);

            Baton<string, PerformanceData>* baton = new Baton<string, PerformanceData>();
            baton->request.data = baton;
            baton->callbackFunction.Reset(isolate, callbackFunction);

            uv_queue_work(uv_default_loop(), &baton->request, PerformanceAlgorithm::GetPerformanceDataWork, PerformanceAlgorithm::GetPerformanceDataAsyncAfter);
        }
    }
}

void PerformanceAlgorithm::GetPerformanceDataWork(uv_work_t* request) {
    Baton<string, PerformanceData>* baton = static_cast<Baton<string, PerformanceData>*>(request->data);

    baton->result.memory_info.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&baton->result.memory_info);

    PDH_FMT_COUNTERVALUE counterVal;
    PdhCollectQueryData(cpuQuery);
    PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
    baton->result.cpu_usage = counterVal.doubleValue;

    DWORD processIDs[1024], bytesReturned;
    EnumProcesses(processIDs, sizeof(processIDs), &bytesReturned);

    DWORD numberOfProcesses = bytesReturned / sizeof(DWORD);
    for (int i = 0; i < numberOfProcesses; i++) {
        HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]);

        HMODULE hMods[1024];
        DWORD cbNeeded;
        if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
            for (int j = 0; j < (cbNeeded / sizeof(HMODULE)); j++) {
                TCHAR szModName[MAX_PATH];
                GetModuleFileNameEx(hProcess, hMods[j], szModName, sizeof(szModName) / sizeof(TCHAR));

                ProcessInfo info;
                info.process_id = processIDs[i];
                info.path = string(szModName);

                baton->result.processes.push_back(info);

                break;
            }
        }

        CloseHandle(hProcess);
    }

    sort(baton->result.processes.begin(), baton->result.processes.end(), [](ProcessInfo a, ProcessInfo b) -> bool {
        return a.process_id < b.process_id;
    });

    GetPerformanceInfo(&baton->result.performance_info, sizeof(PERFORMACE_INFORMATION));
}

void PerformanceAlgorithm::GetPerformanceDataAsyncAfter(uv_work_t* request, int status) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);
    EscapableHandleScope escapableHandleScope(isolate);

    Baton<string, PerformanceData>* baton = static_cast<Baton<string, PerformanceData>*>(request->data);
    Local<Function> callbackFunction = Local<Function>::New(isolate, baton->callbackFunction);

    Local<Object> returnValue = Object::New(isolate);
    returnValue->Set(String::NewFromUtf8(isolate, "cpu_usage"), Number::New(isolate, baton->result.cpu_usage));
    returnValue->Set(String::NewFromUtf8(isolate, "ram_usage"), Number::New(isolate, baton->result.memory_info.dwMemoryLoad));
    returnValue->Set(String::NewFromUtf8(isolate, "total_physical_memory"), Number::New(isolate, baton->result.memory_info.ullTotalPhys));
    returnValue->Set(String::NewFromUtf8(isolate, "available_physical_memory"), Number::New(isolate, baton->result.memory_info.ullAvailPhys));
    returnValue->Set(String::NewFromUtf8(isolate, "total_page_file"), Number::New(isolate, baton->result.memory_info.ullTotalPageFile));
    returnValue->Set(String::NewFromUtf8(isolate, "available_page_file"), Number::New(isolate, baton->result.memory_info.ullAvailPageFile));
    returnValue->Set(String::NewFromUtf8(isolate, "total_virtual"), Number::New(isolate, baton->result.memory_info.ullTotalVirtual));
    returnValue->Set(String::NewFromUtf8(isolate, "available_virtual"), Number::New(isolate, baton->result.memory_info.ullAvailVirtual));

    Local<Array> processes = Array::New(isolate, baton->result.processes.size());
    for (int i = 0; i < baton->result.processes.size(); i++) {
        Local<Object> processInfo = Object::New(isolate);
        processInfo->Set(String::NewFromUtf8(isolate, "process_id"), Number::New(isolate, baton->result.processes[i].process_id));
        processInfo->Set(String::NewFromUtf8(isolate, "path"), String::NewFromUtf8(isolate, baton->result.processes[i].path.c_str()));

        processes->Set(i, processInfo);
    }
    returnValue->Set(String::NewFromUtf8(isolate, "running_processes"), processes);

    const unsigned int argc = 1;
    Handle<Value> argv[argc] = { escapableHandleScope.Escape(returnValue) };
    callbackFunction->Call(isolate->GetCurrentContext()->Global(), argc, argv);

    baton->callbackFunction.Reset();
    delete baton;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM