【问题标题】:Get current CPU usage on Deno获取 Deno 上的当前 CPU 使用率
【发布时间】:2022-01-31 04:25:18
【问题描述】:

NodeJS 上有process.cpuUsage() 函数和Deno.memoryUsage() 函数来获取Deno 上的内存使用情况

https://deno.land/std@0.123.0/node/process.ts 也有一个 Deno 进程模块 但它不包括类似.cpuUsage()

那么有没有办法在Deno 上获取当前的 cpu 使用情况?

【问题讨论】:

  • 您可能需要(并且出于性能原因更喜欢)为此的本机插件(请参阅FFI API)。
  • 您的目标是哪个操作系统平台(win、mac 或 linux)?
  • @jsejcksn 全部
  • 您是否在相关设备上的PATH 中安装并使用了 Node.js? (例如,你可以运行node -e "console.log('hello')",然后你会在下一个stdout 行看到hello 吗?)
  • 另外,您能否分享一下您的用例:您打算如何使用当前 CPU 负载的单点瞬时样本?大多数抽象提供平均值(例如,与上次相比的平均值 1/5/15 min)

标签: cpu-usage deno


【解决方案1】:

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

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

  1. 使用Foreign Function Interface API

  2. 使用subprocess 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 │
└───────┴──────┴──────┴─────┴──────┴─────┘

【讨论】:

    【解决方案2】:

    您可以使用https://deno.land/std@0.123.0/node/os.ts,其中cpus() 给出CPUCoreInfo[]

    【讨论】:

    • 我如何知道cpu使用率是多少百分比
    • Guess deno.land/std@0.123.0/node/os.ts#L29 为每种类型(系统、用户等)提供 ms,但我猜你只希望它用于 Deno 进程,而不是“获取当前 CPU 使用情况”。
    • 这是错误的。该函数的值are hardcoded to zeros。尝试在您的控制台中运行它以亲自查看:deno eval --unstable --print "(await import('https://deno.land/std@0.123.0/node/os.ts')).cpus()"
    • @ClemensTolboom 不,我想获取系统当前的 CPU 使用率,而不仅仅是 deno 进程
    • 根据deno.land/std@0.123.0/nodeos部分,它是一个node compatibility模块作为一个整体。您可以按照测试说明检查什么是有效的。 6 天前 github.com/denoland/deno/pull/13475 进来了。猜猜我们需要 deno v1.18
    猜你喜欢
    • 2019-02-12
    • 1970-01-01
    • 1970-01-01
    • 2010-09-06
    • 1970-01-01
    • 2021-01-14
    • 2022-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多