From 768a36a706265402e02de3eee7cbcfab4007b24e Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Tue, 25 Jun 2024 20:26:18 -0700 Subject: [PATCH] Faster Bun.hash.crc32 --- bench/snippets/bun-hash.mjs | 26 ++++++++++++++++++++++++ src/bun.js/api/BunObject.zig | 5 ++--- src/deps/zlib.posix.zig | 3 +++ src/deps/zlib.win32.zig | 6 +++--- src/zlib.zig | 39 ++++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 bench/snippets/bun-hash.mjs diff --git a/bench/snippets/bun-hash.mjs b/bench/snippets/bun-hash.mjs new file mode 100644 index 0000000000..ce78744417 --- /dev/null +++ b/bench/snippets/bun-hash.mjs @@ -0,0 +1,26 @@ +import { bench, group, run } from "./runner.mjs"; + +const hashes = ["wyhash", "adler32", "crc32", "cityHash32", "cityHash64", "murmur32v3", "murmur32v2", "murmur64v2"]; + +group("hello world", () => { + for (const name of hashes) { + const fn = Bun.hash[name]; + + bench(`${name}`, () => { + return fn("hello world"); + }); + } +}); + +group("hello world (x 1024)", () => { + for (const name of hashes) { + const fn = Bun.hash[name]; + + const repeated = Buffer.alloc("hello world".length * 1024, "hello world").toString(); + bench(`${name}`, () => { + return fn(repeated); + }); + } +}); + +await run(); diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 15e07c086a..0be3af48f9 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -3613,11 +3613,10 @@ pub fn getHashObject( ) callconv(.C) JSC.JSValue { return HashObject.create(globalThis); } - const HashObject = struct { pub const wyhash = hashWrap(std.hash.Wyhash).hash; - pub const adler32 = hashWrap(std.hash.Adler32).hash; - pub const crc32 = hashWrap(std.hash.Crc32).hash; + pub const adler32 = hashWrap(bun.zlib.Adler32).hash; + pub const crc32 = hashWrap(bun.zlib.Crc32).hash; pub const cityHash32 = hashWrap(std.hash.CityHash32).hash; pub const cityHash64 = hashWrap(std.hash.CityHash64).hash; pub const murmur32v2 = hashWrap(std.hash.murmur.Murmur2_32).hash; diff --git a/src/deps/zlib.posix.zig b/src/deps/zlib.posix.zig index b38cf14379..d4da2c5f2b 100644 --- a/src/deps/zlib.posix.zig +++ b/src/deps/zlib.posix.zig @@ -87,3 +87,6 @@ pub inline fn inflateInit2(strm: anytype, windowBits: anytype) ReturnCode { pub inline fn inflateBackInit(strm: anytype, windowBits: anytype, window: anytype) ReturnCode { return inflateBackInit_(strm, windowBits, window, zlibVersion(), @import("std").zig.c_translation.cast(c_int, @import("std").zig.c_translation.sizeof(z_stream))); } + +pub extern fn adler32(uLong, ptr: ?[*]const u8, len: uInt) uLong; +pub extern fn crc32(uLong, ptr: ?[*]const u8, len: uInt) uLong; diff --git a/src/deps/zlib.win32.zig b/src/deps/zlib.win32.zig index 6560576c20..8a4dc7f92f 100644 --- a/src/deps/zlib.win32.zig +++ b/src/deps/zlib.win32.zig @@ -119,10 +119,10 @@ pub extern fn gzclose_r(file: gzFile) ReturnCode; pub extern fn gzclose_w(file: gzFile) ReturnCode; pub extern fn gzerror(file: gzFile, errnum: [*c]c_int) [*c]const u8; pub extern fn gzclearerr(file: gzFile) void; -pub extern fn adler32(adler: uLong, buf: [*c]const Bytef, len: uInt) uLong; +pub extern fn adler32(adler: uLong, buf: ?[*]const Bytef, len: uInt) uLong; pub extern fn adler32_z(adler: uLong, buf: [*c]const Bytef, len: z_size_t) uLong; -pub extern fn crc32(crc: uLong, buf: [*c]const Bytef, len: uInt) uLong; -pub extern fn crc32_z(crc: uLong, buf: [*c]const Bytef, len: z_size_t) uLong; +pub extern fn crc32(crc: uLong, buf: ?[*]const Bytef, len: uInt) uLong; +pub extern fn crc32_z(crc: uLong, buf: ?[*]const Bytef, len: z_size_t) uLong; pub extern fn crc32_combine_op(crc1: uLong, crc2: uLong, op: uLong) uLong; pub extern fn deflateInit_(strm: z_streamp, level: c_int, version: [*c]const u8, stream_size: c_int) ReturnCode; pub extern fn inflateInit_(strm: z_streamp, version: [*c]const u8, stream_size: c_int) ReturnCode; diff --git a/src/zlib.zig b/src/zlib.zig index 05a42be769..8d11a80609 100644 --- a/src/zlib.zig +++ b/src/zlib.zig @@ -901,3 +901,42 @@ pub const ZlibCompressorArrayList = struct { } } }; + +pub const adler32 = @import("zlib-internal").adler32; +pub const crc32 = @import("zlib-internal").crc32; + +fn HasherFn(comptime function: anytype) type { + return struct { + state: uLong = 0, + + const Hasher = @This(); + + pub fn init(this: *Hasher) void { + this.state = function(0, null, 0); + } + + pub fn update(this: *Hasher, data: []const u8) void { + this.state = function(this.state, data.ptr, @intCast(data.len)); + } + + pub fn finish(this: *Hasher) uLong { + return this.state; + } + + pub fn hash(data: []const u8) uLong { + var hasher = @This(){}; + hasher.init(); + hasher.update(data); + return hasher.finish(); + } + + pub fn hashWithSeed(data: []const u8, seed: uLong) uLong { + var hasher = @This(){ .state = seed }; + hasher.update(data); + return hasher.finish(); + } + }; +} + +pub const Adler32 = HasherFn(adler32); +pub const Crc32 = HasherFn(crc32);