Commit bef8976f2a564cf623b6149280f7efe17f4a2886
added benchmarkds
wanderer committed on 8/4/2017, 9:43:36 PMParent: fb6c040c6945375f945c7613513fc1a550c557fc
Files changed
index.js | changed |
package.json | changed |
tests/index.js | changed |
.travis.yml | added |
benchmark/ethereum.js | added |
benchmark/multikey.js | added |
benchmark/package.json | added |
benchmark/radixTree.js | added |
benchmark/results.md | added |
index.js | ||
---|---|---|
@@ -222,12 +222,12 @@ | ||
222 | 222 … | } |
223 | 223 … | } |
224 | 224 … | |
225 | 225 … | /** |
226 | - * creates a merkle root for the current tree | |
226 … | + * creates a merkle root for the current tree and stores the data perstantly | |
227 | 227 … | * @returns {Promise} |
228 | 228 … | */ |
229 | - createMerkleRoot () { | |
229 … | + flush () { | |
230 | 230 … | return this.graph.flush(this.root) |
231 | 231 … | } |
232 | 232 … | |
233 | 233 … | static formatKey (key) { |
package.json | ||
---|---|---|
@@ -1,18 +1,18 @@ | ||
1 | 1 … | { |
2 | - "name": "ipld-radix-tree", | |
2 … | + "name": "merkle-radix-tree", | |
3 | 3 … | "version": "0.0.0", |
4 | - "description": "", | |
4 … | + "description": "This implements a binary merkle radix tree", | |
5 | 5 … | "main": "index.js", |
6 | 6 … | "scripts": { |
7 | - "coverage": "node --expose-wasm --harmony ./node_modules/istanbul/lib/cli.js cover ./tests/index.js", | |
7 … | + "coverage": "node ./node_modules/istanbul/lib/cli.js cover ./tests/index.js", | |
8 | 8 … | "coveralls": "npm run coverage && coveralls <coverage/lcov.info", |
9 | 9 … | "lint": "standard", |
10 | - "test": "node --expose-wasm --harmony ./tests/index.js" | |
10 … | + "test": "node ./tests/index.js" | |
11 | 11 … | }, |
12 | 12 … | "author": "mjbecze <mjbecze@gmail.com>", |
13 | 13 … | "license": "MPL-2.0", |
14 | - "keywords": [], | |
14 … | + "keywords": ["merkle", "tree", "ipfs"], | |
15 | 15 … | "devDependencies": { |
16 | 16 … | "coveralls": "^2.13.1", |
17 | 17 … | "ipfs": "^0.25.0", |
18 | 18 … | "istanbul": "^1.1.0-alpha.1", |
tests/index.js | ||
---|---|---|
@@ -32,9 +32,9 @@ | ||
32 | 32 … | await tree.set('test', 'cat111') |
33 | 33 … | val = await tree.get('test') |
34 | 34 … | t.equals(val, 'cat111') |
35 | 35 … | |
36 | - const stateRoot = await tree.createMerkleRoot() | |
36 … | + const stateRoot = await tree.flush() | |
37 | 37 … | |
38 | 38 … | // try reteriving node from ipfs |
39 | 39 … | tree = new RadixTree({ |
40 | 40 … | dag: node.dag, |
@@ -67,8 +67,17 @@ | ||
67 | 67 … | let key2 = new RadixTree.ArrayConstructor([1, 0]) |
68 | 68 … | await tree.set(key2, 'cat') |
69 | 69 … | let key3 = new RadixTree.ArrayConstructor([0, 0]) |
70 | 70 … | await tree.set(key3, 'cat3') |
71 … | + | |
72 … | + let val = await tree.get(key0) | |
73 … | + t.equals(val, 'cat') | |
74 … | + val = await tree.get(key1) | |
75 … | + t.equals(val, 'cat2') | |
76 … | + val = await tree.get(key2) | |
77 … | + t.equals(val, 'cat') | |
78 … | + val = await tree.get(key3) | |
79 … | + t.equals(val, 'cat3') | |
71 | 80 … | // console.log(JSON.stringify(tree.root, null, 2)) |
72 | 81 … | |
73 | 82 … | t.end() |
74 | 83 … | }) |
.travis.yml | |||
---|---|---|---|
@@ -1,0 +1,24 @@ | |||
1 … | +language: node_js | ||
2 … | +node_js: | ||
3 … | + - "8" | ||
4 … | +env: | ||
5 … | + global: | ||
6 … | + - CXX=g++-4.8 | ||
7 … | + matrix: | ||
8 … | + - TEST_SUITE=test | ||
9 … | +addons: | ||
10 … | + apt: | ||
11 … | + sources: | ||
12 … | + - ubuntu-toolchain-r-test | ||
13 … | + packages: | ||
14 … | + - g++-4.8 | ||
15 … | +matrix: | ||
16 … | + fast_finish: true | ||
17 … | + include: | ||
18 … | + - os: linux | ||
19 … | + node_js: "8" | ||
20 … | + env: TEST_SUITE=coveralls | ||
21 … | + - os: linux | ||
22 … | + node_js: "8" | ||
23 … | + env: TEST_SUITE=lint | ||
24 … | +script: npm run $TEST_SUITE |
benchmark/ethereum.js | ||
---|---|---|
@@ -1,0 +1,36 @@ | ||
1 … | +var Trie = require('merkle-patricia-tree') | |
2 … | +const crypto = require('crypto') | |
3 … | +const rlp = require('rlp') | |
4 … | + | |
5 … | +const trie = new Trie() | |
6 … | + | |
7 … | +const entries = 100000 | |
8 … | +console.log('entries', entries) | |
9 … | + | |
10 … | +async function run () { | |
11 … | + for (let i = 0; i < entries; i++) { | |
12 … | + const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20) | |
13 … | + await new Promise((resolve, reject) => { | |
14 … | + trie.put(key, i, resolve) | |
15 … | + }) | |
16 … | + } | |
17 … | + | |
18 … | + let proofSize = 0 | |
19 … | + for (let i = 0; i < entries; i++) { | |
20 … | + const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20) | |
21 … | + const promise = new Promise((resolve, reject) => { | |
22 … | + trie.findPath(key, (err, node, remainder, stack) => { | |
23 … | + let proof = stack.map(el => { | |
24 … | + return el.raw | |
25 … | + }) | |
26 … | + let encoded = rlp.encode(proof) | |
27 … | + proofSize += encoded.length | |
28 … | + resolve() | |
29 … | + }) | |
30 … | + }) | |
31 … | + await promise | |
32 … | + } | |
33 … | + console.log('rlp size', proofSize / entries) | |
34 … | +} | |
35 … | + | |
36 … | +run() |
benchmark/multikey.js | ||
---|---|---|
@@ -1,0 +1,75 @@ | ||
1 … | +const IPFS = require('ipfs') | |
2 … | +const crypto = require('crypto') | |
3 … | +const RadixTree = require('../') | |
4 … | +const cbor = require('borc') | |
5 … | +const zlib = require('zlib') | |
6 … | + | |
7 … | +// start ipfs | |
8 … | +const node = new IPFS({ | |
9 … | + start: false, | |
10 … | + repo: './ipfs-repo' | |
11 … | +}) | |
12 … | + | |
13 … | +node.on('ready', async () => { | |
14 … | + const tree = new RadixTree({ | |
15 … | + dag: node.dag, | |
16 … | + // root: { '/': 'zdpuArkpWFfw49S1tNLY26YNkHCoKt2CG7rJ6iCaqkcwsGqH7' } | |
17 … | + }) | |
18 … | + | |
19 … | + const entries = 10000 //5117051 | |
20 … | + console.log('entries', entries) | |
21 … | + for (let i = 0; i < entries; i++) { | |
22 … | + const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20) | |
23 … | + await tree.set(key, i) | |
24 … | + } | |
25 … | + console.log('flushing') | |
26 … | + const sr = await tree.flush() | |
27 … | + console.log('done', sr) | |
28 … | + | |
29 … | + let proofSize = 0 | |
30 … | + let compressedSize = 0 | |
31 … | + | |
32 … | + const gzip = zlib.createGzip() | |
33 … | + gzip.on('data', (data) => { | |
34 … | + compressedSize += data.length | |
35 … | + }) | |
36 … | + | |
37 … | + const numOfKeys = 3 | |
38 … | + for (let i = 0; i < numOfKeys; i++) { | |
39 … | + const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20) | |
40 … | + await tree.get(key) | |
41 … | + } | |
42 … | + | |
43 … | + const encoded = cbor.encode(tree.root) | |
44 … | + proofSize += encoded.length | |
45 … | + | |
46 … | + const promise = new Promise((resolve, reject) => { | |
47 … | + gzip.on('end', () => { | |
48 … | + resolve() | |
49 … | + }) | |
50 … | + }) | |
51 … | + gzip.end(encoded) | |
52 … | + await promise | |
53 … | + console.log('cbor size', proofSize) | |
54 … | + console.log('compressed size', compressedSize) | |
55 … | +}) | |
56 … | + | |
57 … | +// if (i % 10000 === 0) { | |
58 … | +// console.log(i) | |
59 … | +// console.log(JSON.stringify(tree.root, null, 2)) | |
60 … | +// try { | |
61 … | +// let start = new Date() | |
62 … | +// let hrstart = process.hrtime() | |
63 … | +// await tree.flush() | |
64 … | +// const end = new Date() - start | |
65 … | +// const hrend = process.hrtime(hrstart) | |
66 … | + | |
67 … | +// console.info('Execution time: %dms', end) | |
68 … | +// console.info('Execution time (hr): %ds %dms', hrend[0], hrend[1] / 1000000) | |
69 … | +// console.log(tree.root) | |
70 … | +// start = new Date() | |
71 … | +// hrstart = process.hrtime() | |
72 … | +// } catch (e) { | |
73 … | +// console.log(e) | |
74 … | +// } | |
75 … | +// } |
benchmark/package.json | ||
---|---|---|
@@ -1,0 +1,15 @@ | ||
1 … | +{ | |
2 … | + "name": "benchmark", | |
3 … | + "version": "1.0.0", | |
4 … | + "description": "", | |
5 … | + "main": "index.js", | |
6 … | + "scripts": { | |
7 … | + "test": "echo \"Error: no test specified\" && exit 1" | |
8 … | + }, | |
9 … | + "author": "", | |
10 … | + "license": "ISC", | |
11 … | + "dependencies": { | |
12 … | + "borc": "^2.0.2", | |
13 … | + "merkle-patricia-tree": "^2.2.0" | |
14 … | + } | |
15 … | +} |
benchmark/radixTree.js | ||
---|---|---|
@@ -1,0 +1,77 @@ | ||
1 … | +const IPFS = require('ipfs') | |
2 … | +const crypto = require('crypto') | |
3 … | +const RadixTree = require('../') | |
4 … | +const cbor = require('borc') | |
5 … | +const zlib = require('zlib') | |
6 … | + | |
7 … | +// start ipfs | |
8 … | +const node = new IPFS({ | |
9 … | + start: false, | |
10 … | + repo: './ipfs-repo' | |
11 … | +}) | |
12 … | + | |
13 … | +node.on('ready', async () => { | |
14 … | + const tree = new RadixTree({ | |
15 … | + dag: node.dag, | |
16 … | + // root: { '/': 'zdpuArkpWFfw49S1tNLY26YNkHCoKt2CG7rJ6iCaqkcwsGqH7' } | |
17 … | + }) | |
18 … | + | |
19 … | + const entries = 100000 //5117051 | |
20 … | + console.log('entries', entries) | |
21 … | + for (let i = 0; i < entries; i++) { | |
22 … | + const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20) | |
23 … | + await tree.set(key, i) | |
24 … | + } | |
25 … | + console.log('flushing') | |
26 … | + const sr = await tree.flush() | |
27 … | + console.log('done', sr) | |
28 … | + | |
29 … | + let proofSize = 0 | |
30 … | + let compressedSize = 0 | |
31 … | + | |
32 … | + for (let i = 0; i < entries; i++) { | |
33 … | + const tree = new RadixTree({ | |
34 … | + dag: node.dag, | |
35 … | + root: {'/': sr['/']} | |
36 … | + }) | |
37 … | + const key = crypto.createHash('sha256').update(i.toString()).digest().slice(0, 20) | |
38 … | + await tree.get(key) | |
39 … | + // console.log(JSON.stringify(tree.root, null, 2)) | |
40 … | + const encoded = cbor.encode(tree.root) | |
41 … | + proofSize += encoded.length | |
42 … | + | |
43 … | + const gzip = zlib.createGzip() | |
44 … | + gzip.on('data', (data) => { | |
45 … | + compressedSize += data.length | |
46 … | + }) | |
47 … | + const promise = new Promise((resolve, reject) => { | |
48 … | + gzip.on('end', () => { | |
49 … | + resolve() | |
50 … | + }) | |
51 … | + }) | |
52 … | + gzip.end(encoded) | |
53 … | + await promise | |
54 … | + } | |
55 … | + console.log('cbor size', proofSize / entries) | |
56 … | + console.log('compressed size', compressedSize / entries) | |
57 … | +}) | |
58 … | + | |
59 … | +// if (i % 10000 === 0) { | |
60 … | +// console.log(i) | |
61 … | +// console.log(JSON.stringify(tree.root, null, 2)) | |
62 … | +// try { | |
63 … | +// let start = new Date() | |
64 … | +// let hrstart = process.hrtime() | |
65 … | +// await tree.flush() | |
66 … | +// const end = new Date() - start | |
67 … | +// const hrend = process.hrtime(hrstart) | |
68 … | + | |
69 … | +// console.info('Execution time: %dms', end) | |
70 … | +// console.info('Execution time (hr): %ds %dms', hrend[0], hrend[1] / 1000000) | |
71 … | +// console.log(tree.root) | |
72 … | +// start = new Date() | |
73 … | +// hrstart = process.hrtime() | |
74 … | +// } catch (e) { | |
75 … | +// console.log(e) | |
76 … | +// } | |
77 … | +// } |
benchmark/results.md | ||
---|---|---|
@@ -1,0 +1,163 @@ | ||
1 … | +This compares the binary radix tree's proof to Ethereum tree. The proofs where | |
2 … | +encoded in cbor and compressed with gzip. Etherum's proof where encoded using | |
3 … | +rlp. The compressed results for Ethereum where not recoded since they where | |
4 … | +larger then the uncompressed proofs | |
5 … | + | |
6 … | +## 10000 keys | |
7 … | +### Binary Radix Tree | |
8 … | +``` | |
9 … | +cbor 660 bytes | |
10 … | +compressed size 572 | |
11 … | +``` | |
12 … | + | |
13 … | +### Ethereum | |
14 … | +``` | |
15 … | +rlp 1649 bytes | |
16 … | +``` | |
17 … | + | |
18 … | +Diff 65% | |
19 … | + | |
20 … | +## 20000 keys | |
21 … | +### Binary Radix Tree | |
22 … | +``` | |
23 … | +cbor 705 bytes | |
24 … | +compressed size 607 | |
25 … | +``` | |
26 … | + | |
27 … | +### Ethereum | |
28 … | +``` | |
29 … | +rlp 1772 bytes | |
30 … | +``` | |
31 … | + | |
32 … | +Diff 66% | |
33 … | + | |
34 … | +## 30000 keys | |
35 … | +### Binary Radix Tree | |
36 … | +``` | |
37 … | +cbor 731 bytes | |
38 … | +compressed 628 size | |
39 … | +``` | |
40 … | + | |
41 … | +### Ethereum | |
42 … | +``` | |
43 … | +rlp 1829 bytes | |
44 … | +``` | |
45 … | + | |
46 … | +Diff 66% | |
47 … | + | |
48 … | +## 40000 keys | |
49 … | +### Binary Radix Tree | |
50 … | +``` | |
51 … | +cbor 749 bytes | |
52 … | +compressed 643 size | |
53 … | +``` | |
54 … | + | |
55 … | +### Ethereum | |
56 … | +``` | |
57 … | +rlp 1876 bytes | |
58 … | +``` | |
59 … | + | |
60 … | +Diff 66% | |
61 … | + | |
62 … | +## 50000 keys | |
63 … | +### Binary Radix Tree | |
64 … | +``` | |
65 … | +cbor 764 bytes | |
66 … | +compressed 654 size | |
67 … | +``` | |
68 … | + | |
69 … | +### Ethereum | |
70 … | +``` | |
71 … | +rlp 1917 bytes | |
72 … | +``` | |
73 … | + | |
74 … | +Diff 66% | |
75 … | + | |
76 … | +## 60000 keys | |
77 … | +### Binary Radix Tree | |
78 … | +``` | |
79 … | +cbor 776 bytes | |
80 … | +compressed 663 size | |
81 … | +``` | |
82 … | + | |
83 … | +### Ethereum | |
84 … | +``` | |
85 … | +rlp 1956 bytes | |
86 … | +``` | |
87 … | + | |
88 … | +## 70000 keys | |
89 … | +### Binary Radix Tree | |
90 … | +``` | |
91 … | +cbor 786 bytes | |
92 … | +compressed 671 size | |
93 … | +``` | |
94 … | + | |
95 … | +### Ethereum | |
96 … | +``` | |
97 … | +rlp 1990 bytes | |
98 … | +``` | |
99 … | + | |
100 … | +Diff 66% | |
101 … | + | |
102 … | +## 80000 keys | |
103 … | +### Binary Radix Tree | |
104 … | +``` | |
105 … | +cbor 795 bytes | |
106 … | +compressed 679 size | |
107 … | +``` | |
108 … | + | |
109 … | +### Ethereum | |
110 … | +``` | |
111 … | +rlp 2021 bytes | |
112 … | +``` | |
113 … | + | |
114 … | +Diff 66% | |
115 … | + | |
116 … | +## 90000 keys | |
117 … | +### Binary Radix Tree | |
118 … | +``` | |
119 … | +cbor 803 bytes | |
120 … | +compressed 685 size | |
121 … | +``` | |
122 … | + | |
123 … | +### Ethereum | |
124 … | +``` | |
125 … | +rlp 2050 bytes | |
126 … | +``` | |
127 … | + | |
128 … | +Diff 67% | |
129 … | + | |
130 … | +## 100000 keys | |
131 … | +### Binary Radix Tree | |
132 … | +``` | |
133 … | +cbor 810 bytes | |
134 … | +compressed 691 size | |
135 … | +``` | |
136 … | + | |
137 … | +### Ethereum | |
138 … | +``` | |
139 … | +rlp 2075 bytes | |
140 … | +``` | |
141 … | + | |
142 … | +Diff 67% | |
143 … | + | |
144 … | +# multikey | |
145 … | +The following show that multikey are more compact the single key proofs . Each | |
146 … | +tree was populated with 10000 keys | |
147 … | + | |
148 … | +## Two Keys Proofs | |
149 … | +``` | |
150 … | +cbor 1088 | |
151 … | +compressed 916 | |
152 … | +``` | |
153 … | + | |
154 … | +## Three Keys Proofs | |
155 … | +``` | |
156 … | +cbor 1675 | |
157 … | +compressed 1381 | |
158 … | +``` | |
159 … | +## Four Keys Proofs | |
160 … | +``` | |
161 … | +cbor 2221 | |
162 … | +compressed 1801 | |
163 … | +``` |
Built with git-ssb-web