davidmarkclements / fast-redact

very fast object redaction
MIT License
278 stars 30 forks source link

fast-redact seems to add significantly more than 1% overhead on top of JSON.stringify #39

Closed aabdelhafez closed 2 years ago

aabdelhafez commented 2 years ago

It is mentioned in the Benchmarks section of the README file that:

In the direct calling case, fast-redact is ~30x faster than pino-noir, however a more realistic comparison is overhead on JSON.stringify.

For a static redaction case (no wildcards) pino-noir adds ~25% overhead on top of JSON.stringify whereas fast-redact adds ~1% overhead.

I attempted to measure the overhead firsthand. In this benchmark, fast-redact performed orders of magnitude slower than JSON.stringify (using the Default Usage example from the README file), which makes the overhead astronomical:

jsonStringify x 1,094,634 ops/sec ±0.74% (89 runs sampled)
fastRedactWithSerialization x 791 ops/sec ±5.98% (74 runs sampled)
fastRedactWithoutSerialization x 841 ops/sec ±4.94% (78 runs sampled)
Fastest is jsonStringify

The benchmarks were run on a MacBook Pro (15-inch, 2019) with the following specs:

Could you please help me make sense of those results? You can find the benchmarking code here.

Thanks!

aabdelhafez commented 2 years ago

The reason behind that is that my benchmarks were using fast-redact incorrectly. The right way is to supply it with options once, and then use the returned function to redact.

Incorrect usage ❌

fastRedact({
    paths: ['x.y'],
    censor: '[REDACTED]',
})({ x: { y: 1, z: 2 } }); // { x: { y: '[REDACTED]', z: 2 } }

Correct usage ✅

const redact = fastRedact({
    paths: ['x.y'],
    censor: '[REDACTED]',
});

redact({ x: { y: 1, z: 2 } }); // { x: { y: '[REDACTED]', z: 2 } }

I understand that all the usage examples in the README use fast-redact the right way, but I strongly believe that the correct usage needs to be highlighted more. It cannot be overstated that using fast-redact incorrectly incurs a massive penalty, especially if you're redacting logs on each HTTP request, for example.

fast-redact (incorrect usage) x 676 ops/sec ±5.28% (71 runs sampled)
fast-redact (correct usage) x 161,399,154 ops/sec ±1.34% (85 runs sampled)
Fastest is fast-redact (correct usage)
kruchkamgar commented 2 years ago

Yes, perhaps amend the readme where it speaks about initialized template functions, using the Function constructor…

seems to imply that templates or Function constructors themselves offer performance improvements— yet the performance improvement appears* to derive from reusable functions (see Dfkaye - JS eval and Function constructor )

*or please enlighten me/us on other benefits I may have missed.