-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Performance improvements * Heavily optimize string read/write functions * Update dependencies * Change to 1 minute runs for each benchmark * Add RPC benchmarks * Remove benchmark
- Loading branch information
1 parent
13770d1
commit 3dcf22b
Showing
20 changed files
with
1,903 additions
and
200 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ isolate-* | |
*.ignore | ||
coverage | ||
dist | ||
.yarn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
nodeLinker: node-modules |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
export const asciiToUint8Array = ( | ||
str: string, | ||
strLength: number, | ||
buffer: Uint8Array, | ||
offset: number | ||
) => { | ||
for (let i = 0; i < strLength; i++) { | ||
buffer[offset + i] = str.charCodeAt(i); | ||
} | ||
return strLength; | ||
}; | ||
|
||
const fns = new Array(66).fill(0).map((_, i) => { | ||
const codes = new Array(i) | ||
.fill(0) | ||
.map((_, j) => `buf[offset + ${j}]`) | ||
.join(", "); | ||
return new Function( | ||
"buf", | ||
"length", | ||
"offset", | ||
`return String.fromCharCode(${codes});` | ||
); | ||
}); | ||
|
||
export const uint8ArrayToAscii = ( | ||
buffer: Uint8Array, | ||
byteLength: number, | ||
offset: number | ||
) => { | ||
return fns[byteLength](buffer, byteLength, offset); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Bench } from "tinybench"; | ||
import { | ||
siaFiveThousandUsers, | ||
siaFiveThousandUsersDecode, | ||
} from "./tests/sia.js"; | ||
import { | ||
jsonFiveThousandUsers, | ||
jsonFiveThousandUsersDecode, | ||
} from "./tests/json.js"; | ||
import { | ||
cborFiveThousandUsers, | ||
cborFiveThousandUsersDecode, | ||
} from "./tests/cbor.js"; | ||
import { | ||
siaOneFiveThousandUsers, | ||
siaOneFiveThousandUsersDecode, | ||
} from "./tests/sia-v1.js"; | ||
import { | ||
msgpackrFiveThousandUsers, | ||
msgpackrFiveThousandUsersDecode, | ||
} from "./tests/msgpackr.js"; | ||
|
||
const bench = new Bench({ name: "serialization", time: 60 * 1000 }); | ||
|
||
bench.add("JSON", () => jsonFiveThousandUsers()); | ||
bench.add("Sializer", () => siaFiveThousandUsers()); | ||
bench.add("Sializer (v1)", () => siaOneFiveThousandUsers()); | ||
bench.add("CBOR-X", () => cborFiveThousandUsers()); | ||
bench.add("MsgPackr", () => msgpackrFiveThousandUsers()); | ||
|
||
console.log(`Running ${bench.name} benchmark...`); | ||
await bench.run(); | ||
|
||
console.table(bench.table()); | ||
|
||
const deserializeBench = new Bench({ | ||
name: "deserialization", | ||
time: 60 * 1000, | ||
}); | ||
|
||
deserializeBench.add("JSON", () => jsonFiveThousandUsersDecode()); | ||
deserializeBench.add("Sializer", () => siaFiveThousandUsersDecode()); | ||
deserializeBench.add("Sializer (v1)", () => siaOneFiveThousandUsersDecode()); | ||
deserializeBench.add("CBOR-X", () => cborFiveThousandUsersDecode()); | ||
deserializeBench.add("MsgPackr", () => msgpackrFiveThousandUsersDecode()); | ||
|
||
console.log(`Running ${deserializeBench.name} benchmark...`); | ||
await deserializeBench.run(); | ||
|
||
console.table(deserializeBench.table()); | ||
|
||
console.log("Sia file size:", siaFiveThousandUsers().length); | ||
console.log("Sia v1 file size:", siaOneFiveThousandUsers().length); | ||
console.log("JSON file size:", jsonFiveThousandUsers().length); | ||
console.log("MsgPackr file size:", cborFiveThousandUsers().length); | ||
console.log("CBOR-X file size:", msgpackrFiveThousandUsers().length); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { fiveThousandUsers } from "./common.js"; | ||
import { encode, decode } from "cbor-x"; | ||
|
||
export const cborFiveThousandUsers = () => encode(fiveThousandUsers); | ||
|
||
const encoded = cborFiveThousandUsers(); | ||
|
||
export const cborFiveThousandUsersDecode = () => decode(encoded); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { faker } from "@faker-js/faker"; | ||
|
||
export function createRandomUser() { | ||
return { | ||
userId: faker.string.uuid(), | ||
username: faker.internet.username(), | ||
email: faker.internet.email(), | ||
avatar: faker.image.avatar(), | ||
password: faker.internet.password(), | ||
birthdate: faker.date.birthdate(), | ||
registeredAt: faker.date.past(), | ||
}; | ||
} | ||
|
||
export const fiveUsers = faker.helpers.multiple(createRandomUser, { | ||
count: 5, | ||
}); | ||
|
||
export const fiveHundredUsers = faker.helpers.multiple(createRandomUser, { | ||
count: 500, | ||
}); | ||
|
||
export const fiveThousandUsers = faker.helpers.multiple(createRandomUser, { | ||
count: 5_000, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { fiveThousandUsers } from "./common.js"; | ||
|
||
export const jsonFiveThousandUsers = () => | ||
Buffer.from(JSON.stringify(fiveThousandUsers)); | ||
|
||
const encoded = jsonFiveThousandUsers(); | ||
|
||
export const jsonFiveThousandUsersDecode = () => JSON.parse(encoded.toString()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { fiveThousandUsers } from "./common.js"; | ||
import { pack, unpack } from "msgpackr"; | ||
|
||
export const msgpackrFiveThousandUsers = () => pack(fiveThousandUsers); | ||
|
||
const encoded = msgpackrFiveThousandUsers(); | ||
|
||
export const msgpackrFiveThousandUsersDecode = () => unpack(encoded); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { fiveThousandUsers } from "./common.js"; | ||
import { sia, desia } from "sializer"; | ||
|
||
export const siaOneFiveThousandUsers = () => sia(fiveThousandUsers); | ||
|
||
const encoded = siaOneFiveThousandUsers(); | ||
|
||
export const siaOneFiveThousandUsersDecode = () => desia(encoded); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { fiveThousandUsers } from "./common.js"; | ||
import { Sia } from "../../index.js"; | ||
import assert from "assert"; | ||
|
||
const sia = new Sia(); | ||
|
||
export const siaFiveThousandUsers = () => | ||
sia | ||
.seek(0) | ||
.addArray16(fiveThousandUsers, (sia, user) => { | ||
sia | ||
.addAscii(user.userId) | ||
.addAscii(user.username) | ||
.addAscii(user.email) | ||
.addAscii(user.avatar) | ||
.addAscii(user.password) | ||
.addInt64(user.birthdate.valueOf()) | ||
.addInt64(user.registeredAt.valueOf()); | ||
}) | ||
.toUint8ArrayReference(); | ||
|
||
const encoded = siaFiveThousandUsers(); | ||
const desia = new Sia(encoded); | ||
|
||
const decodeUser = (sia: Sia) => ({ | ||
userId: sia.readAscii(), | ||
username: sia.readAscii(), | ||
email: sia.readAscii(), | ||
avatar: sia.readAscii(), | ||
password: sia.readAscii(), | ||
birthdate: new Date(sia.readInt64()), | ||
registeredAt: new Date(sia.readInt64()), | ||
}); | ||
|
||
export const siaFiveThousandUsersDecode = () => | ||
desia.seek(0).readArray16(decodeUser); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { Bench } from "tinybench"; | ||
import WebSocket from "ws"; | ||
import { Sia } from "../../../index.js"; | ||
import { pack, unpack } from "msgpackr"; | ||
import { decode, encode } from "cbor-x"; | ||
import { fiveHundredUsers } from "../../tests/common.js"; | ||
|
||
const sia = new Sia(); | ||
|
||
const rpcRequest = { | ||
method: "batchCalculateUserAges", | ||
params: fiveHundredUsers, | ||
}; | ||
|
||
export const payloads = { | ||
sia: () => | ||
sia | ||
.seek(0) | ||
.addAscii(rpcRequest.method) | ||
.addArray16(rpcRequest.params, (sia, user) => { | ||
sia | ||
.addAscii(user.userId) | ||
.addAscii(user.username) | ||
.addAscii(user.email) | ||
.addAscii(user.avatar) | ||
.addAscii(user.password) | ||
.addInt64(user.birthdate.getTime()) | ||
.addInt64(user.registeredAt.getTime()); | ||
}) | ||
.toUint8ArrayReference(), | ||
json: () => new Uint8Array(Buffer.from(JSON.stringify(rpcRequest))), | ||
cbor: () => new Uint8Array(encode(rpcRequest)), | ||
msgpack: () => new Uint8Array(pack(rpcRequest)), | ||
}; | ||
|
||
const clients = { | ||
sia: new WebSocket("ws://localhost:8080"), | ||
cbor: new WebSocket("ws://localhost:8081"), | ||
msgpack: new WebSocket("ws://localhost:8082"), | ||
json: new WebSocket("ws://localhost:8083"), | ||
}; | ||
|
||
const callbacks = { | ||
sia: (data: Buffer) => { | ||
return new Sia(new Uint8Array(data)).readArray16((sia) => { | ||
const userId = sia.readAscii(); | ||
const age = sia.readUInt8(); | ||
return { userId, age }; | ||
}); | ||
}, | ||
cbor: (data: Buffer) => decode(data), | ||
msgpack: (data: Buffer) => unpack(data), | ||
json: (data: Buffer) => JSON.parse(data.toString()), | ||
}; | ||
|
||
console.log("Waiting for connections..."); | ||
await new Promise((resolve) => setTimeout(resolve, 15 * 1000)); | ||
|
||
const bench = new Bench({ name: "RPC", time: 10 * 1000 }); | ||
|
||
const makeRpcCall = async ( | ||
ws: WebSocket, | ||
ondata: (data: Buffer) => void, | ||
payload: Uint8Array | ||
) => | ||
new Promise((resolve) => { | ||
ws.send(payload, { binary: true }); | ||
const done = (data: Buffer) => { | ||
ws.off("message", done); | ||
ondata(data); | ||
resolve(null); | ||
}; | ||
ws.on("message", done); | ||
}); | ||
|
||
bench | ||
.add( | ||
"JSON", | ||
async () => await makeRpcCall(clients.json, callbacks.json, payloads.json()) | ||
) | ||
.addEventListener("complete", () => clients.json.close()); | ||
|
||
bench | ||
.add( | ||
"Sia", | ||
async () => await makeRpcCall(clients.sia, callbacks.sia, payloads.sia()) | ||
) | ||
.addEventListener("complete", () => clients.sia.close()); | ||
|
||
bench | ||
.add( | ||
"CBOR", | ||
async () => await makeRpcCall(clients.cbor, callbacks.cbor, payloads.cbor()) | ||
) | ||
.addEventListener("complete", () => clients.cbor.close()); | ||
|
||
bench | ||
.add( | ||
"MsgPack", | ||
async () => | ||
await makeRpcCall(clients.msgpack, callbacks.msgpack, payloads.msgpack()) | ||
) | ||
.addEventListener("complete", () => clients.msgpack.close()); | ||
|
||
console.log(`Running ${bench.name} benchmark...`); | ||
await bench.run(); | ||
|
||
console.table(bench.table()); |
Oops, something went wrong.