Skip to content

Commit f43c931

Browse files
authored
Merge pull request #39 from louisabraham/perf/count-separation-and-inlining
Separate logical word count from buffer capacity
2 parents 3deb852 + 709588c commit f43c931

8 files changed

Lines changed: 466 additions & 310 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: Test
2-
on: push
2+
on: [push, pull_request]
33
jobs:
44
test:
55
timeout-minutes: 15

README.md

Lines changed: 211 additions & 139 deletions
Large diffs are not rendered by default.

benchmark/test.js

Lines changed: 53 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const tBitSet = require("bitset");
1111
const fBitSet = require("fast-bitset");
1212
const roaring = require("roaring");
1313
const os = require("os");
14+
const minimist = require("minimist");
1415

1516
const smallgap = 3;
1617
const largegap = 210;
@@ -1360,23 +1361,67 @@ function XORBench() {
13601361
.run({ async: false });
13611362
}
13621363

1364+
const benchmarks = {
1365+
"or": { fn: OrBench, desc: "union (new bitmap)" },
1366+
"xor": { fn: XORBench, desc: "change/XOR (new bitmap)" },
1367+
"and": { fn: AndBench, desc: "intersection (new bitmap)" },
1368+
"difference": { fn: DifferenceBench, desc: "difference (new bitmap)" },
1369+
"xor-inplace": { fn: XORInplaceBench, desc: "change/XOR (in-place)" },
1370+
"or-inplace": { fn: OrInplaceBench, desc: "union (in-place)" },
1371+
"and-inplace": { fn: AndInplaceBench, desc: "intersection (in-place)" },
1372+
"andnot-inplace": { fn: AndNotInplaceBench, desc: "difference (in-place)" },
1373+
"cardinality": { fn: CardBench, desc: "cardinality / size()" },
1374+
"or-card": { fn: OrCardBench, desc: "union cardinality" },
1375+
"and-card": { fn: AndCardBench, desc: "intersection cardinality" },
1376+
"difference-card": { fn: DifferenceCardBench, desc: "difference cardinality" },
1377+
"create": { fn: CreateBench, desc: "dynamic bitmap creation" },
1378+
"query": { fn: QueryBench, desc: "has() query" },
1379+
"array": { fn: ArrayBench, desc: "array extraction" },
1380+
"foreach": { fn: ForEachBench, desc: "forEach iteration" },
1381+
"clone": { fn: CloneBench, desc: "clone" },
1382+
};
1383+
13631384
const main = function () {
1385+
const args = minimist(process.argv.slice(2));
1386+
1387+
if (args.list) {
1388+
console.log("Available benchmarks:");
1389+
for (const [name, { desc }] of Object.entries(benchmarks)) {
1390+
console.log(` ${name.padEnd(20)} ${desc}`);
1391+
}
1392+
return;
1393+
}
1394+
1395+
const selected = args.select
1396+
? Object.entries(benchmarks).filter(([name, { desc }]) =>
1397+
name.includes(args.select) || desc.toLowerCase().includes(args.select.toLowerCase())
1398+
)
1399+
: Object.entries(benchmarks);
1400+
1401+
if (selected.length === 0) {
1402+
console.log(`No benchmarks matching "${args.select}". Use --list to see available benchmarks.`);
1403+
return;
1404+
}
1405+
1406+
function tryVersion(pkg) {
1407+
try { return require(pkg + "/package.json").version; } catch { return ""; }
1408+
}
13641409
console.log("Benchmarking against:");
13651410
console.log(
13661411
"TypedFastBitSet.js: https://github.com/lemire/TypedFastBitSet.js"
13671412
);
13681413
console.log("roaring: https://www.npmjs.com/package/roaring");
13691414
console.log(
13701415
"infusion.BitSet.js from https://github.com/infusion/BitSet.js",
1371-
require("bitset.js/package.json").version
1416+
tryVersion("bitset.js")
13721417
);
13731418
console.log(
13741419
"tdegrunt.BitSet from https://github.com/tdegrunt/bitset",
1375-
require("bitset/package.json").version
1420+
tryVersion("bitset")
13761421
);
13771422
console.log(
13781423
"mattkrick.fast-bitset from https://github.com/mattkrick/fast-bitset",
1379-
require("fast-bitset/package.json").version
1424+
tryVersion("fast-bitset")
13801425
);
13811426
console.log("standard Set object from JavaScript");
13821427
console.log("");
@@ -1395,50 +1440,11 @@ const main = function () {
13951440
process.versions.v8
13961441
);
13971442
console.log();
1398-
console.log(
1399-
"We proceed with the logical operations generating new bitmaps: "
1400-
);
1401-
console.log("");
1402-
OrBench();
1403-
console.log("");
1404-
XORBench();
1405-
console.log("");
1406-
AndBench();
1407-
console.log("");
1408-
DifferenceBench();
1409-
console.log("");
1410-
console.log("We benchmark the in-place logical operations: ");
1411-
console.log("(Notice how much faster they are.)");
1412-
console.log("");
1413-
XORInplaceBench();
1414-
console.log("");
1415-
OrInplaceBench();
1416-
console.log("");
1417-
AndInplaceBench();
1418-
console.log("");
1419-
AndNotInplaceBench();
1420-
console.log("");
1421-
console.log("We benchmark the operations computing the set sizes: ");
1422-
console.log("");
1423-
CardBench();
1424-
console.log("");
1425-
OrCardBench();
1426-
console.log("");
1427-
AndCardBench();
1428-
console.log("");
1429-
DifferenceCardBench();
1430-
console.log("");
1431-
console.log("We conclude with other benchmarks: ");
1432-
console.log("");
1433-
CreateBench();
1434-
console.log("");
1435-
QueryBench();
1436-
console.log("");
1437-
ArrayBench();
1438-
console.log("");
1439-
ForEachBench();
1440-
console.log("");
1441-
CloneBench();
1443+
1444+
for (const [name, { fn, desc }] of selected) {
1445+
fn();
1446+
console.log("");
1447+
}
14421448
};
14431449

14441450
if (require.main === module) {

package-lock.json

Lines changed: 22 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
"build:package": "tsc -p tsconfig.build.json --outDir lib",
1919
"check:types": "tsc",
2020
"test": "node --expose-gc ./node_modules/jest/bin/jest",
21-
"release": "npm run build:package && npm run test && release-it"
21+
"release": "npm run build:package && npm run test && release-it",
22+
"benchmark": "node benchmark/test.js",
23+
"benchmark:ablation": "node benchmark/ablation.js"
2224
},
2325
"license": "Apache-2.0",
2426
"bugs": {
@@ -34,7 +36,7 @@
3436
"release-it": "^15.6.0",
3537
"ts-jest": "^29.0.5",
3638
"ts-node": "^10.9.1",
37-
"typescript": "^4.8.4"
39+
"typescript": "^5.7.0"
3840
},
3941
"author": "Daniel Lemire <lemire@gmail.com> (http://lemire.me/en/)"
4042
}

src/SparseTypedFastBitSet.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class SparseTypedFastBitSet implements BitSet {
7979
}
8080
}
8181

82-
private toBitset(): Uint32Array {
82+
private toBitset(): Uint32Array<ArrayBuffer> {
8383
const array = this.data;
8484
// currently converts its internal type to bitset
8585
const count = (array[0] + 32) >>> 5;

0 commit comments

Comments
 (0)