Trying to get normalized CPU usage for node process - javascript

I'm trying to calculate the normalized cpu percentage for my node process. My goal is to get it to match the output that I have in my htop for the pid but I'm unable to do so. My code is below along with my htop output.
import { cpuUsage } from "node:process";
import { cpus } from "os";
function basicCpuUsage() {
const startTime = process.hrtime();
const startUsage = cpuUsage();
const numCpus = cpus().length;
const add = 1 + 1; // make cpu do work?
const usageDiff = cpuUsage(startUsage); // get diff time from start
const endTime = process.hrtime(startTime); // total amount of time that has elapsed
const usageMS = (usageDiff.user + usageDiff.system) / 1e3;
const totalMS = endTime[0] * 1e3 + endTime[1] / 1e6;
const cpuPercent = (usageMS / totalMS) * 100;
const normTotal = usageMS / numCpus; // average usage time per cpu
const normPercent = (normTotal / totalMS) * 100;
console.log({
cpuPercent: cpuPercent.toFixed(2),
normPercent: normPercent.toFixed(2),
});
}
process.title = "CPU Test";
const { pid } = process;
console.log({ pid });
const title = setInterval(() => {
basicCpuUsage();
}, 1000);
Here is my output, as you can see my code cpu output does no match my htop cpu output. Which part of my calculation is incorrect? I was thinking this might have to do with my setInterval function call, but not sure. I am attempting to create a long running process where I can view the cpu usage.

Turns out I was making an incorrect calculation. I was dividing my totalTimeMS twice when I should have done it once. Additionally I moved the currentUsage and currentTime to the outside of the function.
Below is the correct calculation:
import { cpus } from "os";
let currentUsage = process.cpuUsage();
let currentTime = process.hrtime();
function basicCpuUsage() {
const numCpus = cpus().length;
const usageDiff = process.cpuUsage(currentUsage); // get diff time from start
const endTime = process.hrtime(currentTime); // total amount of time that has elapsed
currentUsage = process.cpuUsage()
currentTime = process.hrtime();
const usageMS = (usageDiff.user + usageDiff.system) / 1e3;
const totalMS = endTime[0] * 1e3 + endTime[1] / 1e6;
const cpuPercent = (usageMS / totalMS) * 100;
const normPercent = (usageMS / totalMS / numCpus) * 100; // average usage time per cpu
console.log({
cpuPercent: cpuPercent.toFixed(2),
normPercent: normPercent.toFixed(2),
});
}
process.title = "CPU Test";
setInterval(() => {
for (let i = 0; i < 25; i++) {
const add = 1 + 1;
}
basicCpuUsage();
}, 5000);

Related

Are clusters of nodejs processes the optimal choice for executing a function repeatedly

My goal is to repeatedly call a function to generate a random key as fast as possible. I've tried the following script and it takes around ~30ms to execute the function which seems slow.
const cluster = require("node:cluster");
const { cpus } = require("node:os");
const process = require("node:process");
const ethers = require("ethers");
const numCPUs = cpus().length;
// Get number of leading zeros from ethereum address
const getLeadingZeros = (address) => {
const leadingZeros = address.slice(2, address.length).match(/^0+/);
return leadingZeros ? leadingZeros[0].length : 0;
};
if (cluster.isPrimary) {
console.log(`Primary ${process.pid}: starting workers...`);
// Fork workers.
for (let i = 0; i < numCPUs / 2; i++) {
cluster.fork();
}
} else {
console.log(`Worker ${process.pid} started`);
let num = 5;
while (true) {
let wallet = ethers.Wallet.createRandom();
let address = wallet.address;
if (getLeadingZeros(address) > num) {
console.log(
`Found ${num} zeros in ${address}`
);
}
}
}

What is the best way to download a file with a speed limit using NodeJS?

I am trying to figure out the best way to download files with a speed limit using NodeJS's builtin HTTPS module. (There is a fully working python implementation of what I am trying to do at the bottom.) I have written two different functions and both of them seem to get the job as expected.
download1 function, checks whether the speed limit has been exceeded in the current second and if so, pauses the download and creates a timeout that gets triggered at the end of that second that resumes the download.
download2 however, instead of creating a timeout, creates an interval that gets triggered once every 1000 miliseconds and resumes the download if it has been paused.
I was wondering which one of these two approaches is better or if I should go about it with a whole diffent approach.
Here are the functions:
export const download1 = (url: string, fileName: string, speedLimitInKb: number) => {
return new Promise((resolve, _reject) => {
https.get(url, res => {
const stream = fs.createWriteStream(fileName);
let totalSize = 0;
let size = 0;
let speedLimit = kbToBytes(speedLimitInKb);
let startDate: number;
let lastSecond = Date.now();
res.pipe(stream);
res.once("resume", () => {
startDate = Date.now();
console.log(`Started at ${new Date(startDate)}`)
})
res.on("data", (chunk) => {
size += chunk.length;
const now = Date.now();
if (now - lastSecond > 1000) {
lastSecond = Date.now();
totalSize += size;
size = 0;
} else if (size >= speedLimit) {
res.pause();
setTimeout(() => res.resume(), 1000 - (now - lastSecond));
}
});
res.on("resume", () => {
lastSecond = Date.now();
totalSize += size;
size = 0;
})
res.on("end", () => {
const elapsed = (Date.now() - startDate) / 1000;
totalSize += size
stream.end();
console.log(`${bytesToMb(totalSize)} mb of data downloaded in ${elapsed} seconds with a speed of ${bytesToKb(totalSize) / elapsed}`)
resolve(undefined);
});
res.on("error", console.log);
})
})
};
export const download2 = (url: string, fileName: string, speedLimitInKb: number) => {
return new Promise((resolve, _reject) => {
https.get(url, res => {
const stream = fs.createWriteStream(fileName);
let totalSize = 0;
let size = 0;
let speedLimit = kbToBytes(speedLimitInKb);
let startDate: number;
res.pipe(stream);
res.once("resume", () => {
startDate = Date.now();
console.log(`Started at ${new Date(startDate)}`)
})
const interval = setInterval(() => {
if (res.isPaused()) {
res.resume();
}
totalSize += size;
size = 0;
}, 1000);
res.on("data", (chunk) => {
size += chunk.length;
if (size >= speedLimit) {
res.pause();
}
});
res.on("end", () => {
clearInterval(interval);
const elapsed = (Date.now() - startDate) / 1000;
totalSize += size
stream.end();
console.log(`${bytesToMb(totalSize)} mb of data downloaded in ${elapsed} seconds with a speed of ${bytesToKb(totalSize) / elapsed}`)
resolve(undefined);
});
res.on("error", console.log);
});
})
}
Additional functions:
export const bytesToKb = (bytes: number) => bytes / 1024;
export const kbToMb = (kb: number) => kb / 1024;
export const kbToBytes = (kb: number) => kb * 1024;
export const mbToKb = (mb: number) => mb * 1024;
export const mbToBytes = (mb: number) => mb * 1024 * 1024;
export const bytesToMb = (bytes: number) => bytes / 1024 / 1024;
export const bytesToGb = (bytes: number) => bytes / 1024 / 1024 / 1024;
export const secondsToMs = (seconds: number) => seconds * 1000;
export const msToSeconds = (ms: number) => ms / 1000;
I have written a Python version of what I am trying to achieve and this works with any speed limit and file size. I would like to figure out how I can implement this in nodejs:
import requests
import time
def download(url, file_name, speed_limit_in_kb):
start = time.time()
size = 0
total_size = 0
with open(file_name, "wb") as f:
with requests.get(url, stream=True) as res:
last_second = time.time()
for part in res.iter_content(1024):
f.write(part)
total_size += len(part)
size += len(part)
offset = time.time() - last_second
if offset > 1:
size = 0
last_second = time.time()
elif size > (1024 * speed_limit_in_kb):
time.sleep(1 - offset)
size = 0
last_second = time.time()
elapsed = time.time() - start
print(f"{total_size / 1024 / 1024} mb of data downloaded in {elapsed} seconds with a speed of {total_size / 1024 / elapsed}")
This type of question is bound to get opinionated answers. Personally, I would use nodejs' built-in streams capabilities to do the throttling. Observations using this approach:
Minimal code
The code relies on (nodejs) library code rather than custom code
High performance. Minimal overhead, also wrt. memory
CON: the code seems complex for those unfamiliar with streams
import fs from "fs";
import https from "https";
import stream from "stream";
import util from "util";
async function downloadWithBackpressure(url, filename, byteRate) {
let totalBytesDownloaded = 0;
const timeBeforeStart = Date.now();
await util.promisify(stream.pipeline)(
// Start the download stream
await new Promise(resolve => https.get(url, resolve)),
// Throttle data by combining setTimeout with a stream.Transform
new stream.Transform({
transform: async (chunk, encoding, next) => {
// Accumulate the total number of bytes received
totalBytesDownloaded += chunk.byteLength;
// Sleep to throttle towards desired transfer speed
const sleepMs = Math.max(0, (totalBytesDownloaded / byteRate * 1000) - Date.now() + timeBeforeStart);
sleepMs && await new Promise(resolve => setTimeout(resolve, sleepMs));
// Propagate the chunk to the stream writable
next(null, chunk);
}
}),
// Save the file to disk
fs.createWriteStream(filename)
);
}

Why i keep getting NaN value in my tip calculator?

I can't find out what is going wrong in my code. Thank you.
I have attached the link to code via codepen.
https://codepen.io/tenzin12/pen/rNmmPbv
`const confirmBtn = document.querySelector(".confirm");
const tipField = document.querySelector(".p1");
const totalField = document.querySelector(".p2");
const tipPercentage = document.querySelector("#tip").children;
const customTip = document.querySelector(".custom").value;
const inputAmt = document.querySelector("#amount").value;
const totalPerson = document.querySelector(".number_of_people").value;
const calcFunction = (bill, percent, diners) => {
const percentage = percent / 100;
const tipPerPerson = (bill * percentage) / diners;
const finalBillPerPerson = bill / diners;
const finalWithTip = finalBillPerPerson + tipPerPerson;
tipField.textContent = tipPerPerson;
totalField.textContent = finalWithTip;
};
for (let i = 0; i < tipPercentage.length; i++) {
tipPercentage[i].addEventListener("click", () => {
if (parseInt(totalPerson) > 0) {
if (tipPercentage[i].value.toUpperCase() === "CUSTOM") {
calcFunction(parseFloat(inputAmt), parseInt(customTip), parseInt(totalPerson));
}
}
calcFunction(parseFloat(inputAmt), parseInt(tipPercentage[i].value), parseInt(totalPerson));
});
}
`
When you need to run calculations on element values, you need to collect those values at the time of calculation. You were collecting them up front - but then when you were calculating the function, it was using those old values. I moved those into your function. Note how I got rid of most of the parseInt and parseFloat functions in favor of the minimal + operator which does the same thing.
Additionally, I simplified the code a little and put in a validation to prevent totals being run on 0 people or 0 amounts. Finally, I changed your for loop into an HTMLCollection forEach loop. I find it is easier to read and maintain
const confirmBtn = document.querySelector(".confirm");
const tipField = document.querySelector(".p1");
const totalField = document.querySelector(".p2");
const tipPercButtons = document.querySelectorAll("#tip input.percentage");
const calcFunction = (bill, percent, diners) => {
const percentage = percent / 100;
const tipPerPerson = (bill * percentage) / diners;
const finalBillPerPerson = bill / diners;
const finalWithTip = finalBillPerPerson + tipPerPerson;
tipField.textContent = tipPerPerson;
totalField.textContent = finalWithTip;
};
tipPercButtons.forEach((el) =>
el.addEventListener("click", (e) => {
const customTip = +document.querySelector(".custom").value;
const inputAmt = +document.querySelector("#amount").value;
const totalPerson = +document.querySelector(".number_of_people").value;
if (isNaN(totalPerson) || isNaN(inputAmt)) {
alert("Please designate the number of people and the amount of the bill")
return;
}
if (totalPerson === 0) return;
let val
if (e.target.value.toUpperCase() === "CUSTOM") val = customTip;
else val = parseInt(e.target.value);
calcFunction(inputAmt, val, totalPerson);
})
);
Updated pen: https://codepen.io/john-tyner/pen/MWmmLMQ?editors=1111
i analysed your code there is some error in fetching the input value in the code.
below is the correct code. Hope this might work
make the following little changes in your code:
const inputAmt = document.querySelector("#amount");
const totalPerson = document.querySelector(".number_of_people");
and this at the bottom outside the if block
calcFunction(
parseFloat(inputAmt.value),
parseInt(tipPercentage[i].value),
parseInt(totalPerson.value)
);
overall your calculator is So interesting.

Find values in array depending on a pattern in Javascript

I have an array:
var videoSources = ["0000.mp4", "0015.mp4", "0030.mp4", "0045.mp4", "0100.mp4"];
I would play videos based on current time; mp4 are recorded every 15minutes;
if time = 0044 play 0030.mp4
So I need something like a pattern [0-15] to find and play correct video.
Here function to play video at the moment:
var currentIndex = 0;
// listener function changes src
function myNewSrc() {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = videoSources[currentIndex];
myVideo.load();
}
I'd suggest parseing the file name to an integer and then finding if a minute mark is within the range of the file:
var videoSources =
["0000.mp4",
"0015.mp4",
"0030.mp4",
"0045.mp4",
"0100.mp4"]
var getTimestamp = (ts, sources) =>
sources.find(name => {
const startStr = name.split(".")[0]; // e.g.: "0015"
const startMin = parseInt(startStr, 10); // e.g.: 15
const endMin = startMin + 15;
return ts >= startMin && ts < endMin;
});
console.log(getTimestamp(44, videoSources));
If the ranges aren't guaranteed to be 15 minutes, you could do a "look ahead" to find the end of a range. In my current example, I've hardcoded it to be 15 minutes, and expect the file name to be the start of the file.
Edit: to support hours and minutes
var videoSources =
["0000.mp4",
"0015.mp4",
"0030.mp4",
"0045.mp4",
"0100.mp4",
"1145.mp4",
"1230.mp4",
"1245.mp4"]
var getTimestamp = (h, m, sources) =>
sources
.sort()
.find(name => {
const hours = parseInt(name.slice(0, 2), 10);
const minutesStart = parseInt(name.slice(2, 4), 10);
const minutesEnd = minutesStart + 15;
return h <= hours && m >= minutesStart && m < minutesEnd;
});
console.log(getTimestamp(12, 44, videoSources));
You could map your times array and time to numbers and then use findIndex method to return index of correct time element from array.
var videoSources = ["0000.mp4", "0015.mp4", "0030.mp4", "0045.mp4", "0100.mp4"]
const getIndex = (arr, time) => {
time = parseInt(time);
arr = arr.map(e => parseInt(e.split('.')[0]));
return arr.findIndex((e, i) => time >= e && !arr[i + 1] || time < arr[i + 1]);
}
console.log(getIndex(videoSources, "0044"))
console.log(getIndex(videoSources, "0015"))
console.log(getIndex(videoSources, "0099"))
console.log(getIndex(videoSources, "0120"))

Measure process time with Node Js?

I would like to do the following:
console.time("processA");
for(let i; i < 10000; i++) {
// Just to simulate the process
}
console.timeEnd("processA");
but I want to capture the time end and use my own logger of information with it.
Is it possible to handle the console output of the timeEnd?
How can I measure the time interval of a process in nodejs?
Since you are targeting nodejs, you can use process.hrtime as stated in the docs
The process.hrtime() method returns the current high-resolution real time in a [seconds, nanoseconds] tuple Array, where nanoseconds is the remaining part of the real time that can't be represented in second precision.
So you can measure timings up to nanosecond, something that console.time can't, as you can see in your example console.time or Date difference measures 0s.
For example:
const NS_PER_SEC = 1e9;
const MS_PER_NS = 1e-6
const time = process.hrtime();
for (let i; i < 10000; i++) {
// Just to simulate the process
}
const diff = process.hrtime(time);
console.log(`Benchmark took ${diff[0] * NS_PER_SEC + diff[1]} nanoseconds`);
console.log(`Benchmark took ${ (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS } milliseconds`);
Since I'm using timers in multiple places, I wrote a simple class based on Alex's answer:
const t = new Timer('For Loop')
// your code
t.runtimeMs() // => 1212.34
t.runtimeMsStr() // => 'For Loop took 1232.34 milliseconds'
Here's the code:
class Timer {
// Automatically starts the timer
constructor(name = 'Benchmark') {
this.NS_PER_SEC = 1e9;
this.MS_PER_NS = 1e-6
this.name = name;
this.startTime = process.hrtime();
}
// returns the time in ms since instantiation
// can be called multiple times
runtimeMs() {
const diff = process.hrtime(this.startTime);
return (diff[0] * this.NS_PER_SEC + diff[1]) * this.MS_PER_NS;
}
// retuns a string: the time in ms since instantiation
runtimeMsStr() {
return `${this.name} took ${this.runtimeMs()} milliseconds`;
}
}
Starting from Node v8.5, you can use browser-equivalent performance.now() which is easier to use than process.hrtime because it outputs the time in milliseconds directly, therefore you don't have to do a conversion as in process.hrtime
const { performance } = require("perf_hooks");
const start = performance.now();
doSomething();
const end = performance.now();
console.log(`time taken: ${end - start}ms`);
You can find more info from Node.js Docs on Performance API.
var startTime = new Date();
for(let i; i < 10000; i++) {
// Just to simulate the process
}
var endTime = new Date() - startTime;
You will get the total time that it takes to complete the operation
See here https://alligator.io/js/console-time-timeend/
var begin=console.time('t');
for(let i; i < 100000; i++) {
// Just to simulate the process
}
var end= console.timeEnd('t');
var timeSpent=(end-begin) / 1000 + "secs";

Categories