Skip to content

Performance Regression: v4.0.0 is >40% slower than v2.1.3 #273

@DeyualSimu

Description

@DeyualSimu

Performance Regression: v4.0.0 is >40% slower than v2.1.3

  • Library: ms
  • Versions Compared:
    • v2.1.3 (CommonJS)
    • v4.0.0 (TypeScript/ESM)

Description

After benchmarking the new TypeScript-based version (v4.0.0) against the legacy version (v2.1.3), I observed a significant performance degradation. While the type safety and ESM support in v4 are excellent additions, the runtime overhead for parsing and formatting has increased notably.

Steps to Reproduce / Benchmark Code

The following benchmark was executed using benchmark.js in a Node.js 20.x environment.

import Benchmark from 'benchmark';
import msV2 from 'ms'; // v2.1.3
import {ms as msV4} from './dist/index.js'; // v4.0.0 compiled

const runBenchmarkSuite = (iterations) => {
    const suite = new Benchmark.Suite(`Prueba: ${iterations} iteraciones`);
    console.log(`--- Iniciando Benchmark: ${iterations} ops ---`);
    suite
        .add('[email protected]', () => {
            for (let i = 0; i < iterations; i++) {
                msV2('2 days');
                msV2(60000);
            }
        })
        .add('[email protected]', () => {
            for (let i = 0; i < iterations; i++) {
                msV4('2 days');
                msV4(60000);
            }
        })
        .on('cycle', (event) => console.log(String(event.target)))
        .on('complete', function() {
            const fastest = this.filter('fastest').map('name')[0];
            const fastestHz = this.filter('fastest')[0].hz;
            const slowestHz = this.filter('slowest')[0].hz;
            const percentDiff = ((fastestHz - slowestHz) / slowestHz * 100).toFixed(2);
            console.log(`Fastest is ${fastest} (${percentDiff}% faster)`)
        })
        .run({ async: false });
};

const magnitudes = [10,100, 1_000,10_000,100_000];
magnitudes.forEach(m => runBenchmarkSuite(m));

Observed Results

--- Iniciando Benchmark: 10 ops ---
[email protected] x 1,149,452 ops/sec ±1.85% (90 runs sampled)
[email protected] x 781,224 ops/sec ±2.19% (88 runs sampled)
Fastest is [email protected] (47.13% faster)
--- Iniciando Benchmark: 100 ops ---
[email protected] x 123,077 ops/sec ±2.54% (86 runs sampled)
[email protected] x 82,772 ops/sec ±0.91% (86 runs sampled)
Fastest is [email protected] (48.69% faster)
--- Iniciando Benchmark: 1000 ops ---
[email protected] x 12,489 ops/sec ±0.60% (90 runs sampled)
[email protected] x 7,768 ops/sec ±0.96% (92 runs sampled)
Fastest is [email protected] (60.77% faster)
--- Iniciando Benchmark: 10000 ops ---
[email protected] x 1,333 ops/sec ±0.88% (97 runs sampled)
[email protected] x 794 ops/sec ±1.02% (90 runs sampled)
Fastest is [email protected] (67.95% faster)
--- Iniciando Benchmark: 100000 ops ---
[email protected] x 135 ops/sec ±0.71% (87 runs sampled)
[email protected] x 78.41 ops/sec ±1.17% (74 runs sampled)
Fastest is [email protected] (72.73% faster)

Technical Hypothesis

The degradation seems to stem from the added complexity in the TypeScript rewrite, specifically:

  1. Regex Overhead: Possible re-evaluation or more complex matching patterns to satisfy strict type validations.
  2. Transpilation Artifacts: The resulting code in dist/ might include extra logic or helpers that are less optimized by the V8 engine compared to the original handwritten JS.

Impact

In high-throughput environments, this overhead accumulates. While negligible for single calls, it represents a regression in the library's core efficiency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions