diff --git a/CHANGELOG.md b/CHANGELOG.md index 75d38b6..9042abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 2.23.0 + +- Added new module `/performance` for performance-related utilities + - `measureCpuUsage()` to measure the CPU usage in percent of the provided runner function + - `measurePerformanceMetrics()` to measure `Server-Timing` duration and CPU usage percent +- Update dependency versions to latest + ## 2.22.0 - Add new function `parseServerTimingMetrics()` for parsing a `Server-Timing` header into an array of metric objects diff --git a/README.md b/README.md index 2de5250..be99b41 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,12 @@ Useful utilities for your Bun projects The code is organized into logical modules and exported accordingly as follows: -| Export Name | Documentation | Description | -| ----------------------------- | ---------------------------------------- | ------------------------------------ | -| `@mangs/bun-utils/build` | [Link](documentation/buildUtils.md) | Build- and bundler-related utilities | -| `@mangs/bun-utils/console` | [Link](documentation/consoleUtils.md) | Console-related utilities | -| `@mangs/bun-utils/filesystem` | [Link](documentation/filesystemUtils.md) | Filesystem-related utilities | -| `@mangs/bun-utils/network` | [Link](documentation/networkUtils.md) | Network-related utilities | -| `@mangs/bun-utils/router` | [Link](documentation/routerUtils.md) | Router-related utilities | -| `@mangs/bun-utils/time` | [Link](documentation/timeUtils.md) | Time-related utilities | +| Export Name | Documentation | Description | +| ------------------------------ | ----------------------------------------- | ------------------------------------ | +| `@mangs/bun-utils/build` | [Link](documentation/buildUtils.md) | Build- and bundler-related utilities | +| `@mangs/bun-utils/console` | [Link](documentation/consoleUtils.md) | Console-related utilities | +| `@mangs/bun-utils/filesystem` | [Link](documentation/filesystemUtils.md) | Filesystem-related utilities | +| `@mangs/bun-utils/network` | [Link](documentation/networkUtils.md) | Network-related utilities | +| `@mangs/bun-utils/performance` | [Link](documentation/performanceUtils.md) | Performance-related utilities | +| `@mangs/bun-utils/router` | [Link](documentation/routerUtils.md) | Router-related utilities | +| `@mangs/bun-utils/time` | [Link](documentation/timeUtils.md) | Time-related utilities | diff --git a/bun.lockb b/bun.lockb index 70236ce..b1f7f68 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index befe755..71cf639 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mangs/bun-utils", - "version": "2.22.0", + "version": "2.23.0", "author": "Eric L. Goldstein", "description": "Useful utils for your Bun projects", "engines": { @@ -33,6 +33,7 @@ "./console": "./src/consoleUtils.mts", "./filesystem": "./src/filesystemUtils.mts", "./network": "./src/networkUtils.mts", + "./performance": "./src/performanceUtils.mts", "./router": "./src/routerUtils.mts", "./time": "./src/timeUtils.mts" }, @@ -64,10 +65,10 @@ "@types/bun": "1.1.6", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-jsdoc": "48.5.0", + "eslint-plugin-jsdoc": "48.5.2", "prettier": "3.3.2", "typedoc": "0.26.3", - "typedoc-plugin-markdown": "4.1.1", + "typedoc-plugin-markdown": "4.1.2", "typescript": "5.5.3" } } diff --git a/src/performanceUtils.mts b/src/performanceUtils.mts new file mode 100644 index 0000000..a37f48a --- /dev/null +++ b/src/performanceUtils.mts @@ -0,0 +1,56 @@ +/** + * @file Performance-related utilities. + */ + +// External Imports +import { availableParallelism } from 'node:os'; + +// Internal Imports +import { buildServerTimingHeader } from './timeUtils.mts'; + +// Local Functions +/** + * Measure the CPU usage in percent of the provided runner function. + * @param runner Function whose CPU usage to measure. + * @param startTime Optional time in milliseconds when the elapsed time starts counting. + * @returns A tuple containing the return value of the passed-in function and the CPU usage in percent. + */ +async function measureCpuUsage(runner: () => T | Promise, startTime = performance.now()) { + const startCpuUsage = process.cpuUsage(); + + const runnerReturnValue = await runner(); + + const elapsedTime = performance.now() - startTime; + const elapsedCpuUsage = process.cpuUsage(startCpuUsage); + const cpuCount = availableParallelism(); + const cpuPercent = + (100 * ((elapsedCpuUsage.system + elapsedCpuUsage.user) / (1_000 * elapsedTime))) / cpuCount; + + return [runnerReturnValue, cpuPercent] as const; +} + +/** + * Measure performance metrics of the provided runner function. Specifically, `Server-Timing` + * duration and CPU usage percent is computed. + * @param metricName Name of the `Server-Timing` metric being measured. + * @param request `Request` object to which the `Server-Timing` header will be appended. + * @param runner Function whose execution duration and CPU usage percentage will be computed. + * @param metricDescription Optional description of the `Server-Timing` metric being measured. + * @returns A tuple containing the return value of the passed-in function, the execution duration, and the CPU usage in percent. + */ +async function measurePerformanceMetrics( + metricName: string, + request: Request, + runner: () => T | Promise, + metricDescription?: string, +) { + const startTime = performance.now(); + const [runnerReturnValue, cpuPercent] = await measureCpuUsage(runner, startTime); + const [header, duration] = buildServerTimingHeader(metricName, startTime, metricDescription); + request.headers.append(...header); + + return [runnerReturnValue, duration, cpuPercent] as const; +} + +// Module Exports +export { measureCpuUsage, measurePerformanceMetrics }; diff --git a/src/timeUtils.mts b/src/timeUtils.mts index e97a34b..49082c1 100644 --- a/src/timeUtils.mts +++ b/src/timeUtils.mts @@ -38,7 +38,7 @@ interface ServerTimingMetricParsed { * @param name The name of the performance metric. * @param startTime The recorded start time used to compute the metric duration; computed by subtracting the time at which this function is called by the start time. [Milliseconds is the unit recommended by the W3C](https://w3c.github.io/server-timing/#duration-attribute). * @param description A description of the metric. - * @returns A tuple containing a tuple representing the header value and the duration. + * @returns A tuple containing a tuple representing the header value and the execution duration. * @example * ```ts * import { buildServerTimingHeader } from '@mangs/bun-utils/time'; @@ -118,7 +118,7 @@ async function measureElapsedTime(runner: () => T | Promise) { * @param request `Request` object to which the `Server-Timing` header will be appended. * @param runner Function whose execution duration will be measured. * @param metricDescription Optional description of the `Server-Timing` metric being measured. - * @returns A tuple containing the return value of the passed-in function and the duration. + * @returns A tuple containing the return value of the passed-in function and the execution duration. * @example * ```ts * import { measureServerTiming } from '@mangs/bun-utils/time';