获取 Deno 上当前的 CPU 使用率

问题描述 投票:0回答:3

process.cpuUsage()
上有
NodeJS
函数和
Deno.memoryUsage()
函数可以获取
Deno

上的内存使用情况

还有 Deno 的流程模块,位于 https://deno.land/[email protected]/node/process.ts 但它不包括类似

.cpuUsage()

的内容

那么有没有办法获取当前的CPU使用率

Deno

cpu-usage deno
3个回答
2
投票

在我写这个答案时,在 Deno 中本身不可能获取采样的 CPU 负载数据。

如果您现在想要此数据,可以通过以下两种方式之一获取:

  1. 使用外部函数接口API

  2. 使用子流程API

我将在下面提供一个代码示例,介绍如何通过安装 Node.js 并使用第二种方法来获取数据:


node_eval.ts

type MaybePromise<T> = T | Promise<T>;
type Decodable = Parameters<TextDecoder['decode']>[0];

const decoder = new TextDecoder();

async function trimDecodable (decodable: MaybePromise<Decodable>): Promise<string> {
  return decoder.decode(await decodable).trim();
}

/**
 * Evaluates the provided script using Node.js (like
 * [`eval`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval))
 * and returns `stdout`.
 *
 * Uses the resolved version of `node` according to the host environemnt.
 *
 * Requires `node` to be available in `$PATH`.
 * Requires permission `--allow-run=node`.
 */
export async function evaluateUsingNodeJS (script: string): Promise<string> {
  const cmd = ['node', '-e', script];
  const proc = Deno.run({cmd, stderr: 'piped', stdout: 'piped'});

  const [{code}, stderr, stdout] = await Promise.all([
    proc.status(),
    trimDecodable(proc.stderrOutput()),
    trimDecodable(proc.output()),
  ]);

  if (code !== 0) {
    const msg = stderr ? `\n${stderr}` : '';
    throw new Error(`The "node" subprocess exited with a non-zero status code (${code}). If output was emitted to stderr, it is included below.${msg}`);
  }

  return stdout;
}

mod.ts

import {evaluateUsingNodeJS} from './node_eval.ts';

export const cpuTimesKeys: readonly (keyof CPUTimes)[] =
  ['user', 'nice', 'sys', 'idle', 'irq'];

export type CPUTimes = {
  /** The number of milliseconds the CPU has spent in user mode */
  user: number;

  /**
   * The number of milliseconds the CPU has spent in nice mode
   * 
   * `nice` values are POSIX-only.
   * On Windows, the nice values of all processors are always `0`.
   */
  nice: number;

  /** The number of milliseconds the CPU has spent in sys mode */
  sys: number;

  /** The number of milliseconds the CPU has spent in idle mode */
  idle: number;

  /** The number of milliseconds the CPU has spent in irq mode */
  irq: number;
};

export type CPUCoreInfo = {
  model: string;

  /** in MHz */
  speed: number;

  times: CPUTimes;
};

/**
 * Requires `node` to be available in `$PATH`.
 * Requires permission `--allow-run=node`.
 */
export async function sampleCPUsUsingNodeJS (): Promise<CPUCoreInfo[]> {
  const script = `console.log(JSON.stringify(require('os').cpus()));`;
  const stdout = await evaluateUsingNodeJS(script);

  try {
    return JSON.parse(stdout) as CPUCoreInfo[];
  }
  catch (ex) {
    const cause = ex instanceof Error ? ex : new Error(String(ex));
    throw new Error(`The "node" subprocess output couldn't be parsed`, {cause});
  }
}

/**
 * (Same as `CPUCoreInfo`, but) aliased in recognition of the transfromation,
 * in order to provide JSDoc info regarding the transformed type
 */
export type TransformedCoreInfo = Omit<CPUCoreInfo, 'times'> & {
  /** Properties are decimal percentage of total time */
  times: Record<keyof CPUCoreInfo['times'], number>;
};

/** Converts each time value (in ms) to a decimal percentage of their sum */
export function coreInfoAsPercentages (coreInfo: CPUCoreInfo): TransformedCoreInfo {
  const timeEntries = Object.entries(coreInfo.times) as [
    name: keyof CPUCoreInfo['times'],
    ms: number,
  ][];

  const sum = timeEntries.reduce((sum, [, ms]) => sum + ms, 0);

  for (const [index, [, ms]] of timeEntries.entries()) {
    timeEntries[index][1] = ms / sum;
  }

  const times = Object.fromEntries(timeEntries) as TransformedCoreInfo['times'];
  return {...coreInfo, times};
}

example.ts

import {
  coreInfoAsPercentages,
  cpuTimesKeys,
  sampleCPUsUsingNodeJS,
  type CPUCoreInfo,
} from './mod.ts';

function anonymizeProcessorAttributes <T extends CPUCoreInfo>(coreInfoArray: T[]): T[] {
  return coreInfoArray.map(info => ({
    ...info,
    model: 'REDACTED',
    speed: NaN,
  }));
}

// Get the CPU info
const cpuCoreInfoArr = await sampleCPUsUsingNodeJS();

// Anonymizing my personal device details (but you would probably not use this)
const anonymized = anonymizeProcessorAttributes(cpuCoreInfoArr);

// JSON for log data
const jsonLogData = JSON.stringify(anonymized);
console.log(jsonLogData);

// Or, for purely visual inspection,
// round the percentages for greater scannability...

const roundedPercentages = anonymized.map(coreInfo => {
  const asPercentages = coreInfoAsPercentages(coreInfo);
  for (const key of cpuTimesKeys) {
    asPercentages.times[key] = Math.round(asPercentages.times[key] * 100);
  }
  return asPercentages;
});

// and log in tabular format
console.table(roundedPercentages.map(({times}) => times));

在控制台中:

% deno run --allow-run=node example.ts
[{"model":"REDACTED","speed":null,"times":{"user":2890870,"nice":0,"sys":2290610,"idle":17913530,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":218270,"nice":0,"sys":188200,"idle":22687790,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":2509660,"nice":0,"sys":1473010,"idle":19111680,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":221630,"nice":0,"sys":174140,"idle":22698480,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":2161140,"nice":0,"sys":1086970,"idle":19846200,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":221800,"nice":0,"sys":157620,"idle":22714800,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":1905230,"nice":0,"sys":897140,"idle":20291910,"irq":0}},{"model":"REDACTED","speed":null,"times":{"user":224060,"nice":0,"sys":146460,"idle":22723700,"irq":0}}]
┌───────┬──────┬──────┬─────┬──────┬─────┐
│ (idx) │ user │ nice │ sys │ idle │ irq │
├───────┼──────┼──────┼─────┼──────┼─────┤
│     0 │   13 │    0 │  10 │   78 │   0 │
│     1 │    1 │    0 │   1 │   98 │   0 │
│     2 │   11 │    0 │   6 │   83 │   0 │
│     3 │    1 │    0 │   1 │   98 │   0 │
│     4 │    9 │    0 │   5 │   86 │   0 │
│     5 │    1 │    0 │   1 │   98 │   0 │
│     6 │    8 │    0 │   4 │   88 │   0 │
│     7 │    1 │    0 │   1 │   98 │   0 │
└───────┴──────┴──────┴─────┴──────┴─────┘

0
投票

截至 2024 年,该功能运行良好(使用 Deno v1.45.2 进行测试):

import { cpus } from "node:os";
console.log(Deno.loadavg()[0] / cpus().length);

Deno.loadavg()
返回一个 3 元素数组 - 1 分钟、5 分钟、15 分钟的 CPU 使用率平均值,其中值 1 表示当前正在使用相当于 1 个完整逻辑 CPU 核心(即“线程”)。所以我们需要将它除以逻辑核心的数量,我们可以通过节点
cpus
函数得到。


-1
投票

您可以使用 https://deno.land/[email protected]/node/os.ts,其中

cpus()
提供
CPUCoreInfo[]

© www.soinside.com 2019 - 2024. All rights reserved.