Skip to content
This repository has been archived by the owner on Mar 18, 2022. It is now read-only.

Add digestObjects method #58

Merged
merged 11 commits into from
Aug 10, 2021
Merged

Add digestObjects method #58

merged 11 commits into from
Aug 10, 2021

Conversation

twoeths
Copy link
Contributor

@twoeths twoeths commented Aug 2, 2021

Motivation

Description

  • Add digestObjects method to accept 2 objects of h0 to h7 number, each number is equal to 4 bytes, that makes it equivalent to 1 Uint8Array(32)
  • The idea is to inline these properties in persistent-merkle-tree nodes so that it'll share the same Object map memory, storing these properties take roughly extra 32 bytes per node only, see Cache roots as 8 inline numbers persistent-merkle-tree#52
  • Reuse variables to improve performance (~23% as tested in the performance test)

Performance
This is from the performance test

branch digest64 digestObjects
master 72ms -
this branch 55ms 55ms

Although digestObjects is not as good as the new digest64, it's already better than the current digest64 of master
Edit: digestObjects has the same performance to the new digest64 thanks to unrolling for loops.
Later on we can pass 8 u32 numbers to wasm and do the bit shifting work there, that'd make it even better I think.

Memory saving
Created a test in ssz with 250k validators.

  • Currently heapUsed starts with 870MB, calling hashTreeRoot makes it 1.33GB (with additional 460MB for Uint8Array roots)
  • This PR starts with only 680MB and keep roughly the same amount (+5MB - 8MB) after I call hashTreeRoot. This is because h0, ... h7 already starts with 0. The produced root hex string is the same.
  • Why this branch starts with less memory than master? Maybe the initial leafs already have Uint8Array roots in master, now it change to h0 to h7.

Screen Shot 2021-08-02 at 17 00 29

@twoeths twoeths requested a review from a team August 2, 2021 10:25
src/index.js Outdated Show resolved Hide resolved
src/index.js Outdated Show resolved Hide resolved
@lgtm-com
Copy link

lgtm-com bot commented Aug 3, 2021

This pull request introduces 14 alerts when merging e4814b7 into 2d97993 - view on LGTM.com

new alerts:

  • 14 for Useless assignment to local variable

@twoeths
Copy link
Contributor Author

twoeths commented Aug 4, 2021

the benchmark shows that digestObjects is a little bit faster than digest64:

hash
    ✓ digestObjects 50023 times                                           18.86434 ops/s    53.01007 ms/op        -       1132 runs   60.0 s
    ✓ digest64 50023 times                                                17.69875 ops/s    56.50117 ms/op        -       1062 runs   60.0 s

Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach looks really promising!
A few minor comments

src/index.d.ts Outdated Show resolved Hide resolved
test/utils.js Outdated Show resolved Hide resolved
src/index.d.ts Outdated Show resolved Hide resolved
@dapplion
Copy link
Contributor

dapplion commented Aug 4, 2021

yeah! Approach looks very promising. @tuyennhv Can you adds benchmarks to convert to and from HashObjects? Either here or in ssz.

@twoeths twoeths requested a review from wemeetagain August 6, 2021 00:48
@twoeths
Copy link
Contributor Author

twoeths commented Aug 6, 2021

yeah! Approach looks very promising. @tuyennhv Can you adds benchmarks to convert to and from HashObjects? Either here or in ssz.

@dapplion benchmark tests added for byteArrayToHashObject and hashObjectToByteArray

wemeetagain
wemeetagain previously approved these changes Aug 6, 2021
Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dapplion
Copy link
Contributor

dapplion commented Aug 9, 2021

Looks great! @tuyennhv can you setup the benchmarks to run in CI? @wemeetagain Could you add credentials to this repo too? 🙏

@twoeths
Copy link
Contributor Author

twoeths commented Aug 9, 2021

Looks great! @tuyennhv can you setup the benchmarks to run in CI? @wemeetagain Could you add credentials to this repo too? 🙏

@wemeetagain the benchmark workflow is ready, got Error: No ENV S3_BUCKET now

@github-actions
Copy link

github-actions bot commented Aug 9, 2021

Performance Report

✔️ no performance regression detected

Full benchmark results
Benchmark suite Current: 07003a2 Previous: - Ratio
digestTwoHashObjects 50023 times 63.523 ms/op
digest64 50023 times 64.981 ms/op
digest 50023 times 107.75 ms/op
input length 32 2.1380 us/op
input length 64 2.8110 us/op
input length 128 3.6450 us/op
input length 256 5.1070 us/op
input length 512 8.1260 us/op
input length 1024 14.572 us/op
digest 1000000 times 1.4581 s/op
hashObjectToByteArray 50023 times 1.7017 ms/op
byteArrayToHashObject 50023 times 1.7177 ms/op

by benchmarkbot/action

@GregTheGreek
Copy link
Member

@wemeetagain do I need to add this project to the global secrets?

test/bench.js Outdated
Comment on lines 1 to 24
const Benchmark = require('benchmark');

const sha256 = require('../lib');

const suite = new Benchmark.Suite;

const randomBuffer = (length) => Buffer.from(Array.from({length}, () => Math.round(Math.random() * 255)));

suite
.add('input length 32', () => sha256.default.digest(randomBuffer(32)))
.add('input length 64', () => sha256.default.digest(randomBuffer(64)))
.add('input digest-64', () => sha256.default.digest64(randomBuffer(64)))
.add('input length 128', () => sha256.default.digest(randomBuffer(128)))
.add('input length 256', () => sha256.default.digest(randomBuffer(256)))
.add('input length 512', () => sha256.default.digest(randomBuffer(512)))
.on('cycle', function (event) {
console.log(String(event.target));
}).run();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this file stay as this provides perspective of how digest fn is scaling w.r.t. length while newer benchmark.test.js purpose seems more geared towards comparision.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@g11tech I'll port it to the new benchmark framework

@wemeetagain
Copy link
Member

@GregTheGreek I already added the secrets locally

@twoeths twoeths force-pushed the tuyen/digestObjects branch from 98c09f8 to ebef2cf Compare August 10, 2021 07:25
@twoeths twoeths requested a review from wemeetagain August 10, 2021 07:35
Copy link
Contributor

@dapplion dapplion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job! Looking forward to use this implementation in Lodestar

Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@wemeetagain wemeetagain merged commit da5d822 into master Aug 10, 2021
@wemeetagain wemeetagain deleted the tuyen/digestObjects branch August 10, 2021 13:57
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants