| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent fed1dac commit 9782ca2
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,47 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common.js'); | ||
| 4 | + const { crc32 } = require('zlib'); | ||
| 5 | + | ||
| 6 | + // Benchmark crc32 on Buffer and String inputs across sizes. | ||
| 7 | + // Iteration count is scaled inversely with input length to keep runtime sane. | ||
| 8 | + // Example: | ||
| 9 | + // node benchmark/zlib/crc32.js type=buffer len=4096 n=4000000 | ||
| 10 | + // ./out/Release/node benchmark/zlib/crc32.js --test | ||
| 11 | + | ||
| 12 | + const bench = common.createBenchmark(main, { | ||
| 13 | + type: ['buffer', 'string'], | ||
| 14 | + len: [32, 256, 4096, 65536], | ||
| 15 | + n: [4e6], | ||
| 16 | + }); | ||
| 17 | + | ||
| 18 | + function makeBuffer(size) { | ||
| 19 | + const buf = Buffer.allocUnsafe(size); | ||
| 20 | + for (let i = 0; i < size; i++) buf[i] = (i * 1103515245 + 12345) & 0xff; | ||
| 21 | + return buf; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + function makeAsciiString(size) { | ||
| 25 | + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; | ||
| 26 | + let out = ''; | ||
| 27 | + for (let i = 0, j = 0; i < size; i++, j = (j + 7) % chars.length) out += chars[j]; | ||
| 28 | + return out; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + function main({ type, len, n }) { | ||
| 32 | + // Scale iterations so that total processed bytes roughly constant around n*4096 bytes. | ||
| 33 | + const scale = 4096 / len; | ||
| 34 | + const iters = Math.max(1, Math.floor(n * scale)); | ||
| 35 | + | ||
| 36 | + const data = type === 'buffer' ? makeBuffer(len) : makeAsciiString(len); | ||
| 37 | + | ||
| 38 | + let acc = 0; | ||
| 39 | + for (let i = 0; i < Math.min(iters, 10000); i++) acc ^= crc32(data, 0); | ||
| 40 | + | ||
| 41 | + bench.start(); | ||
| 42 | + let sum = 0; | ||
| 43 | + for (let i = 0; i < iters; i++) sum ^= crc32(data, 0); | ||
| 44 | + bench.end(iters); | ||
| 45 | + | ||
| 46 | + if (sum === acc - 1) process.stderr.write(''); | ||
| 47 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,6 +30,8 @@ | |||
| 30 | 30 | #include "threadpoolwork-inl.h" | |
| 31 | 31 | #include "util-inl.h" | |
| 32 | 32 | ||
| 33 | + #include "node_debug.h" | ||
| 34 | + #include "v8-fast-api-calls.h" | ||
| 33 | 35 | #include "v8.h" | |
| 34 | 36 | ||
| 35 | 37 | #include "brotli/decode.h" | |
@@ -48,6 +50,7 @@ | |||
| 48 | 50 | namespace node { | |
| 49 | 51 | ||
| 50 | 52 | using v8::ArrayBuffer; | |
| 53 | + using v8::CFunction; | ||
| 51 | 54 | using v8::Context; | |
| 52 | 55 | using v8::Function; | |
| 53 | 56 | using v8::FunctionCallbackInfo; | |
@@ -1657,22 +1660,35 @@ T CallOnSequence(v8::Isolate* isolate, Local<Value> value, F callback) { | |||
| 1657 | 1660 | } | |
| 1658 | 1661 | } | |
| 1659 | 1662 | ||
| 1660 | - // TODO(joyeecheung): use fast API | ||
| 1663 | + static inline uint32_t CRC32Impl(Isolate* isolate, | ||
| 1664 | + Local<Value> data, | ||
| 1665 | + uint32_t value) { | ||
| 1666 | + return CallOnSequence<uint32_t>( | ||
| 1667 | + isolate, data, [&](const char* ptr, size_t size) -> uint32_t { | ||
| 1668 | + return static_cast<uint32_t>( | ||
| 1669 | + crc32(value, reinterpret_cast<const Bytef*>(ptr), size)); | ||
| 1670 | + }); | ||
| 1671 | + } | ||
| 1672 | + | ||
| 1661 | 1673 | static void CRC32(const FunctionCallbackInfo<Value>& args) { | |
| 1662 | 1674 | CHECK(args[0]->IsArrayBufferView() || args[0]->IsString()); | |
| 1663 | 1675 | CHECK(args[1]->IsUint32()); | |
| 1664 | 1676 | uint32_t value = args[1].As<v8::Uint32>()->Value(); | |
| 1677 | + args.GetReturnValue().Set(CRC32Impl(args.GetIsolate(), args[0], value)); | ||
| 1678 | + } | ||
| 1665 | 1679 | ||
| 1666 | - uint32_t result = CallOnSequence<uint32_t>( | ||
| 1667 | - args.GetIsolate(), | ||
| 1668 | - args[0], | ||
| 1669 | - [&](const char* data, size_t size) -> uint32_t { | ||
| 1670 | - return crc32(value, reinterpret_cast<const Bytef*>(data), size); | ||
| 1671 | - }); | ||
| 1672 | - | ||
| 1673 | - args.GetReturnValue().Set(result); | ||
| 1680 | + static uint32_t FastCRC32(v8::Local<v8::Value> receiver, | ||
| 1681 | + v8::Local<v8::Value> data, | ||
| 1682 | + uint32_t value, | ||
| 1683 | + // NOLINTNEXTLINE(runtime/references) | ||
| 1684 | + v8::FastApiCallbackOptions& options) { | ||
| 1685 | + TRACK_V8_FAST_API_CALL("zlib.crc32"); | ||
| 1686 | + v8::HandleScope handle_scope(options.isolate); | ||
| 1687 | + return CRC32Impl(options.isolate, data, value); | ||
| 1674 | 1688 | } | |
| 1675 | 1689 | ||
| 1690 | + static CFunction fast_crc32_(CFunction::Make(FastCRC32)); | ||
| 1691 | + | ||
| 1676 | 1692 | void Initialize(Local<Object> target, | |
| 1677 | 1693 | Local<Value> unused, | |
| 1678 | 1694 | Local<Context> context, | |
@@ -1685,7 +1701,7 @@ void Initialize(Local<Object> target, | |||
| 1685 | 1701 | MakeClass<ZstdCompressStream>::Make(env, target, "ZstdCompress"); | |
| 1686 | 1702 | MakeClass<ZstdDecompressStream>::Make(env, target, "ZstdDecompress"); | |
| 1687 | 1703 | ||
| 1688 | - SetMethod(context, target, "crc32", CRC32); | ||
| 1704 | + SetFastMethodNoSideEffect(context, target, "crc32", CRC32, &fast_crc32_); | ||
| 1689 | 1705 | target->Set(env->context(), | |
| 1690 | 1706 | FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"), | |
| 1691 | 1707 | FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check(); | |
@@ -1698,6 +1714,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |||
| 1698 | 1714 | MakeClass<ZstdCompressStream>::Make(registry); | |
| 1699 | 1715 | MakeClass<ZstdDecompressStream>::Make(registry); | |
| 1700 | 1716 | registry->Register(CRC32); | |
| 1717 | + registry->Register(fast_crc32_); | ||
| 1701 | 1718 | } | |
| 1702 | 1719 | ||
| 1703 | 1720 | } // anonymous namespace | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,26 @@ | |||
| 1 | + // Flags: --expose-internals --no-warnings --allow-natives-syntax | ||
| 2 | + 'use strict'; | ||
| 3 | + | ||
| 4 | + const common = require('../common'); | ||
| 5 | + const assert = require('assert'); | ||
| 6 | + const zlib = require('zlib'); | ||
| 7 | + | ||
| 8 | + { | ||
| 9 | + function testFastPath() { | ||
| 10 | + const expected = 0xd87f7e0c; // zlib.crc32('test', 0) | ||
| 11 | + assert.strictEqual(zlib.crc32('test', 0), expected); | ||
| 12 | + return expected; | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + eval('%PrepareFunctionForOptimization(zlib.crc32)'); | ||
| 16 | + testFastPath(); | ||
| 17 | + eval('%OptimizeFunctionOnNextCall(zlib.crc32)'); | ||
| 18 | + testFastPath(); | ||
| 19 | + testFastPath(); | ||
| 20 | + | ||
| 21 | + if (common.isDebug) { | ||
| 22 | + const { internalBinding } = require('internal/test/binding'); | ||
| 23 | + const { getV8FastApiCallCount } = internalBinding('debug'); | ||
| 24 | + assert.strictEqual(getV8FastApiCallCount('zlib.crc32'), 2); | ||
| 25 | + } | ||
| 26 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments