UNPKG

@thi.ng/bench

Version:

Benchmarking & profiling utilities w/ various statistics & formatters (CSV, JSON, Markdown etc.)

233 lines 6.91 kB
import type { FnAny, IDeref, IEnable, IObjectOf, IReset } from "@thi.ng/api"; import type { Timestamp } from "./api.js"; export interface Profile { t0: Timestamp[]; total: Timestamp; calls: number; maxDepth: number; } export interface ProfileResult { /** * User provided profile name/ID */ id: string; /** * Number of calls recorded */ calls: number; /** * Total number of milliseconds consumed by this profile (minus internal * computed overhead) */ total: number; /** * Mean number of milliseconds per call (aka `total / calls`) */ timePerCall: number; /** * Percentage of this profile's time contribution to the profiled grand * total (the grand total is _not_ wall clock time, but the sum of all * profiles). */ totalPercent: number; /** * Percentage of this profile's number of calls out of the profiled grand total. */ callsPercent: number; /** * Max recorded recursion depth. See {@link Profiler.start} for example. */ maxDepth: number; } export interface ProfilerOpts { /** * Number of warmup iterations to compute the profiler's internal overhead. * * @defaultValue 1_000_000 */ warmup: number; /** * Unless set to false, the profiler will be enabled by default. * * @defaultValue true */ enabled: boolean; } export declare class Profiler implements IDeref<IObjectOf<ProfileResult>>, IEnable<Profiler>, IReset { protected _session: Profile | undefined; protected _profiles: IObjectOf<Profile>; protected _enabled: boolean; protected _overhead: number; constructor(opts?: Partial<ProfilerOpts>); isEnabled(): boolean; /** * Disables profiler and clears all existing profiles. * * @remarks * Calls to {@link Profiler.start} and {@link Profiler.end} only are no-ops * if the profiler is currently disabled. */ disable(): void; /** * Enables profiler and clears all existing profiles. * * @remarks * Calls to {@link Profiler.start} and {@link Profiler.end} only are no-ops * if the profiler is currently disabled. */ enable(): void; /** * Resets profiler state and clears all recorded profiles. */ reset(): this; /** * Prepare and return all recorded profiles as object of * {@link ProfileResult}s. * * @remarks * Automatically computes and subtracts internal overhead from each * profile's total (Overhead is computed during profiler ctor and/or * {@link Profiler.warmup}). * * Also see {@link Profiler.asCSV} to obtain results in CSV format. */ deref(): IObjectOf<ProfileResult>; /** * Start a new profile (or add to an existing ID) by recording current * timestamp (via {@link now}), number of calls (to this method and for this * ID), as well as max. recursion depth. Use {@link Profiler.end} to * stop/update measurements. * * @remarks * Profiling only happens if the profiler is currently enabled, else a * no-op. * * * @example * ```ts tangle:../export/profiler.ts * import { Profiler } from "@thi.ng/bench"; * * const profiler = new Profiler(); * * // recursive function * const countdown = (n: number, acc: number[] = []) => { * profiler.start("countdown"); * if (n > 0) countdown(n - 1, (acc.push(n),acc)); * profiler.end("countdown"); * return acc; * } * * console.log(countdown(10)); * // [ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ] * * console.log(countdown(5)); * // [ 5, 4, 3, 2, 1 ] * * console.log(profiler.deref()); * // { * // countdown: { * // id: 'countdown', * // total: 0.029665688286, * // timePerCall: 0.0017450404874117648, * // totalPercent: 96.0872831622525, * // calls: 17, * // callsPercent: 100, * // maxDepth: 11 * // } * // } * ``` * * @param id */ start(id: string): void; /** * Ends/updates measurements for given profile ID. Throws error if `id` is * invalid or if no active profiling iteration exists for this ID (e.g. if * this method is called more often than a corresponding * {@link Profiler.start}). * * @remarks * Profiling only happens if the profiler is currently enabled, else a * no-op. * * @param id */ end(id: string): void; /** * Takes a profile `id`, function `fn` and any (optional) arguments. Calls * `fn` with given args and profiles it using provided ID. Returns result * of `fn`. * * @remarks * Also see {@link Profiler.wrap} * * @param id * @param fn */ profile<T>(id: string, fn: FnAny<T>, ...args: any[]): T; /** * Higher-order version of {@link Profiler.profile}. Takes a profile `id` * and vararg function `fn`. Returns new function which when called, calls * given `fn` and profiles it using provided `id`, then returns result of * `fn`. * * @example * ```ts tangle:../export/profiler-wrap.ts * import { Profiler } from "@thi.ng/bench"; * * const profiler = new Profiler(); * * const sum = profiler.wrap( * "sum", * (vec: number[]) => vec.reduce((acc, x) => acc + x, 0) * ); * * console.log(sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); * // 55 * * console.log(profiler.deref()); * // { * // sum: { * // id: 'sum', * // total: 0.015644915291, * // timePerCall: 0.015644915291, * // totalPercent: 100, * // calls: 1, * // callsPercent: 100, * // maxDepth: 1 * // } * // } * ``` * * @param id * @param fn */ wrap<T>(id: string, fn: FnAny<T>): (...args: any[]) => T; /** * Estimates the internal overhead of the {@link Profiler.start} and * {@link Profiler.end} methods by performing given number of `iter`ations * (distributed over 10 runs) and taking the mean duration of those runs. * * @remarks * The computed overhead (per iteration) will be subtracted from the all * recorded profiles (see {@link Profiler.deref} and * {@link Profiler.asCSV}). * * @param iter */ warmup(iter: number): void; /** * Same as {@link Profiler.deref}. */ toJSON(): IObjectOf<ProfileResult>; /** * Returns {@link Profiler.deref} formatted as CSV string. */ asCSV(): string; protected newProfile(t0: Timestamp): { t0: Timestamp[]; total: number | bigint; calls: number; maxDepth: number; }; } //# sourceMappingURL=profiler.d.ts.map