You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

365 lines
11 KiB

lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
lite: memStoreProvider GetHeightBinarySearch method + fix ValKeys.signHeaders Updates #1021 * Implement a GetHeightBinarySearch method that looks for the height using the binary search algorithm guaranteeing worst case iteration time of O(log2(n)) whereas worst case iteration time of O(n) for the current linear search So if n we had 500 commits stored by height and sorted, to trigger the worst case scenario for each, pass in the most negative height you can find e.g. -1 Linear search: 500 iterations Binary search: 9 iterations with n=1000, qHeight = -1 Linear search: 1000 iterations Binary search: 10 iterations with n=1e6, qHeight = -1 Linear search: 1e6 iterations Binary search: 20 iterations Of course there are realistic expectations e.g. a max of commits that may be saved so linear search might be useful for very small size set because it has less preparing overhead and only ~2 types of comparisons, but nonetheless binary search shines as soon as we start to hit say 50 commits to search from as you can see below: ```shell $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6491 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 200000 12064 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 50000 32987 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 395521 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 2940724 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 6281 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 10117 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 18447 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 89029 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 265719 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.614s $ go test -v -run=^$ -bench=MemStore goos: darwin goarch: amd64 pkg: github.com/tendermint/tendermint/lite BenchmarkMemStoreProviderGetByHeightLinearSearch5-4 300000 6779 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch50-4 100000 12980 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch100-4 30000 43598 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch500-4 5000 377462 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightLinearSearch1000-4 500 3278122 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch5-4 300000 7084 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch50-4 200000 9852 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch100-4 100000 19020 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch500-4 20000 99463 ns/op 1600 B/op 15 allocs/op BenchmarkMemStoreProviderGetByHeightBinarySearch1000-4 5000 259293 ns/op 1600 B/op 15 allocs/op PASS ok github.com/tendermint/tendermint/lite 86.204s ``` which gives ```shell $ benchstat old.txt new.txt name old time/op new time/op delta MemStoreProviderGetByHeight5-4 6.63µs ± 2% 6.68µs ± 6% ~ (p=1.000 n=2+2) MemStoreProviderGetByHeight50-4 12.5µs ± 4% 10.0µs ± 1% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight100-4 38.3µs ±14% 18.7µs ± 2% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight500-4 386µs ± 2% 94µs ± 6% ~ (p=0.333 n=2+2) MemStoreProviderGetByHeight1000-4 3.11ms ± 5% 0.26ms ± 1% ~ (p=0.333 n=2+2) ``` If need be we can make a hybrid algorithm that switches between the linear and binary search depending on the number of items. This is reminiscent of Python's TimSort algorithm.
7 years ago
  1. package lite
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. liteErr "github.com/tendermint/tendermint/lite/errors"
  10. )
  11. func TestMemStoreProvidergetByHeightBinaryAndLinearSameResult(t *testing.T) {
  12. p := NewMemStoreProvider().(*memStoreProvider)
  13. // Store a bunch of commits at specific heights
  14. // and then ensure that:
  15. // * getByHeightLinearSearch
  16. // * getByHeightBinarySearch
  17. // both return the exact same result
  18. // 1. Non-existent height commits
  19. nonExistent := []int64{-1000, -1, 0, 1, 10, 11, 17, 31, 67, 1000, 1e9}
  20. ensureNonExistentCommitsAtHeight(t, "getByHeightLinearSearch", p.getByHeightLinearSearch, nonExistent)
  21. ensureNonExistentCommitsAtHeight(t, "getByHeightBinarySearch", p.getByHeightBinarySearch, nonExistent)
  22. // 2. Save some known height commits
  23. knownHeights := []int64{0, 1, 7, 9, 12, 13, 18, 44, 23, 16, 1024, 100, 199, 1e9}
  24. createAndStoreCommits(t, p, knownHeights)
  25. // 3. Now check if those heights are retrieved
  26. ensureExistentCommitsAtHeight(t, "getByHeightLinearSearch", p.getByHeightLinearSearch, knownHeights)
  27. ensureExistentCommitsAtHeight(t, "getByHeightBinarySearch", p.getByHeightBinarySearch, knownHeights)
  28. // 4. And now for the height probing to ensure that any height
  29. // requested returns a fullCommit of height <= requestedHeight.
  30. comparegetByHeightAlgorithms(t, p, 0, 0)
  31. comparegetByHeightAlgorithms(t, p, 1, 1)
  32. comparegetByHeightAlgorithms(t, p, 2, 1)
  33. comparegetByHeightAlgorithms(t, p, 5, 1)
  34. comparegetByHeightAlgorithms(t, p, 7, 7)
  35. comparegetByHeightAlgorithms(t, p, 10, 9)
  36. comparegetByHeightAlgorithms(t, p, 12, 12)
  37. comparegetByHeightAlgorithms(t, p, 14, 13)
  38. comparegetByHeightAlgorithms(t, p, 19, 18)
  39. comparegetByHeightAlgorithms(t, p, 43, 23)
  40. comparegetByHeightAlgorithms(t, p, 45, 44)
  41. comparegetByHeightAlgorithms(t, p, 1025, 1024)
  42. comparegetByHeightAlgorithms(t, p, 101, 100)
  43. comparegetByHeightAlgorithms(t, p, 1e3, 199)
  44. comparegetByHeightAlgorithms(t, p, 1e4, 1024)
  45. comparegetByHeightAlgorithms(t, p, 1e9, 1e9)
  46. comparegetByHeightAlgorithms(t, p, 1e9+1, 1e9)
  47. }
  48. func createAndStoreCommits(t *testing.T, p Provider, heights []int64) {
  49. chainID := "cache-best-height-binary-and-linear"
  50. appHash := []byte("0xdeadbeef")
  51. keys := GenValKeys(len(heights) / 2)
  52. for _, h := range heights {
  53. vals := keys.ToValidators(10, int64(len(heights)/2))
  54. fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5)
  55. err := p.StoreCommit(fc)
  56. require.NoError(t, err, "StoreCommit height=%d", h)
  57. }
  58. }
  59. func comparegetByHeightAlgorithms(t *testing.T, p *memStoreProvider, ask, expect int64) {
  60. algos := map[string]func(int64) (FullCommit, error){
  61. "getHeightByLinearSearch": p.getByHeightLinearSearch,
  62. "getHeightByBinarySearch": p.getByHeightBinarySearch,
  63. }
  64. for algo, fn := range algos {
  65. fc, err := fn(ask)
  66. // t.Logf("%s got=%v want=%d", algo, expect, fc.Height())
  67. require.Nil(t, err, "%s: %+v", algo, err)
  68. if assert.Equal(t, expect, fc.Height()) {
  69. err = p.StoreCommit(fc)
  70. require.Nil(t, err, "%s: %+v", algo, err)
  71. }
  72. }
  73. }
  74. var blankFullCommit FullCommit
  75. func ensureNonExistentCommitsAtHeight(t *testing.T, prefix string, fn func(int64) (FullCommit, error), data []int64) {
  76. for i, qh := range data {
  77. fc, err := fn(qh)
  78. assert.NotNil(t, err, "#%d: %s: height=%d should return non-nil error", i, prefix, qh)
  79. assert.Equal(t, fc, blankFullCommit, "#%d: %s: height=%d\ngot =%+v\nwant=%+v", i, prefix, qh, fc, blankFullCommit)
  80. }
  81. }
  82. func ensureExistentCommitsAtHeight(t *testing.T, prefix string, fn func(int64) (FullCommit, error), data []int64) {
  83. for i, qh := range data {
  84. fc, err := fn(qh)
  85. assert.Nil(t, err, "#%d: %s: height=%d should not return an error: %v", i, prefix, qh, err)
  86. assert.NotEqual(t, fc, blankFullCommit, "#%d: %s: height=%d got a blankCommit", i, prefix, qh)
  87. }
  88. }
  89. func BenchmarkGenCommit20(b *testing.B) {
  90. keys := GenValKeys(20)
  91. benchmarkGenCommit(b, keys)
  92. }
  93. func BenchmarkGenCommit100(b *testing.B) {
  94. keys := GenValKeys(100)
  95. benchmarkGenCommit(b, keys)
  96. }
  97. func BenchmarkGenCommitSec20(b *testing.B) {
  98. keys := GenSecpValKeys(20)
  99. benchmarkGenCommit(b, keys)
  100. }
  101. func BenchmarkGenCommitSec100(b *testing.B) {
  102. keys := GenSecpValKeys(100)
  103. benchmarkGenCommit(b, keys)
  104. }
  105. func benchmarkGenCommit(b *testing.B, keys ValKeys) {
  106. chainID := fmt.Sprintf("bench-%d", len(keys))
  107. vals := keys.ToValidators(20, 10)
  108. for i := 0; i < b.N; i++ {
  109. h := int64(1 + i)
  110. appHash := []byte(fmt.Sprintf("h=%d", h))
  111. resHash := []byte(fmt.Sprintf("res=%d", h))
  112. keys.GenCommit(chainID, h, nil, vals, appHash, []byte("params"), resHash, 0, len(keys))
  113. }
  114. }
  115. // this benchmarks generating one key
  116. func BenchmarkGenValKeys(b *testing.B) {
  117. keys := GenValKeys(20)
  118. for i := 0; i < b.N; i++ {
  119. keys = keys.Extend(1)
  120. }
  121. }
  122. // this benchmarks generating one key
  123. func BenchmarkGenSecpValKeys(b *testing.B) {
  124. keys := GenSecpValKeys(20)
  125. for i := 0; i < b.N; i++ {
  126. keys = keys.Extend(1)
  127. }
  128. }
  129. func BenchmarkToValidators20(b *testing.B) {
  130. benchmarkToValidators(b, 20)
  131. }
  132. func BenchmarkToValidators100(b *testing.B) {
  133. benchmarkToValidators(b, 100)
  134. }
  135. // this benchmarks constructing the validator set (.PubKey() * nodes)
  136. func benchmarkToValidators(b *testing.B, nodes int) {
  137. keys := GenValKeys(nodes)
  138. for i := 1; i <= b.N; i++ {
  139. keys.ToValidators(int64(2*i), int64(i))
  140. }
  141. }
  142. func BenchmarkToValidatorsSec100(b *testing.B) {
  143. benchmarkToValidatorsSec(b, 100)
  144. }
  145. // this benchmarks constructing the validator set (.PubKey() * nodes)
  146. func benchmarkToValidatorsSec(b *testing.B, nodes int) {
  147. keys := GenSecpValKeys(nodes)
  148. for i := 1; i <= b.N; i++ {
  149. keys.ToValidators(int64(2*i), int64(i))
  150. }
  151. }
  152. func BenchmarkCertifyCommit20(b *testing.B) {
  153. keys := GenValKeys(20)
  154. benchmarkCertifyCommit(b, keys)
  155. }
  156. func BenchmarkCertifyCommit100(b *testing.B) {
  157. keys := GenValKeys(100)
  158. benchmarkCertifyCommit(b, keys)
  159. }
  160. func BenchmarkCertifyCommitSec20(b *testing.B) {
  161. keys := GenSecpValKeys(20)
  162. benchmarkCertifyCommit(b, keys)
  163. }
  164. func BenchmarkCertifyCommitSec100(b *testing.B) {
  165. keys := GenSecpValKeys(100)
  166. benchmarkCertifyCommit(b, keys)
  167. }
  168. func benchmarkCertifyCommit(b *testing.B, keys ValKeys) {
  169. chainID := "bench-certify"
  170. vals := keys.ToValidators(20, 10)
  171. cert := NewStaticCertifier(chainID, vals)
  172. check := keys.GenCommit(chainID, 123, nil, vals, []byte("foo"), []byte("params"), []byte("res"), 0, len(keys))
  173. for i := 0; i < b.N; i++ {
  174. err := cert.Certify(check)
  175. if err != nil {
  176. panic(err)
  177. }
  178. }
  179. }
  180. type algo bool
  181. const (
  182. linearSearch = true
  183. binarySearch = false
  184. )
  185. // Lazy load the commits
  186. var fcs5, fcs50, fcs100, fcs500, fcs1000 []FullCommit
  187. var h5, h50, h100, h500, h1000 []int64
  188. var commitsOnce sync.Once
  189. func lazyGenerateFullCommits(b *testing.B) {
  190. b.Logf("Generating FullCommits")
  191. commitsOnce.Do(func() {
  192. fcs5, h5 = genFullCommits(nil, nil, 5)
  193. b.Logf("Generated 5 FullCommits")
  194. fcs50, h50 = genFullCommits(fcs5, h5, 50)
  195. b.Logf("Generated 50 FullCommits")
  196. fcs100, h100 = genFullCommits(fcs50, h50, 100)
  197. b.Logf("Generated 100 FullCommits")
  198. fcs500, h500 = genFullCommits(fcs100, h100, 500)
  199. b.Logf("Generated 500 FullCommits")
  200. fcs1000, h1000 = genFullCommits(fcs500, h500, 1000)
  201. b.Logf("Generated 1000 FullCommits")
  202. })
  203. }
  204. func BenchmarkMemStoreProviderGetByHeightLinearSearch5(b *testing.B) {
  205. benchmarkMemStoreProvidergetByHeight(b, fcs5, h5, linearSearch)
  206. }
  207. func BenchmarkMemStoreProviderGetByHeightLinearSearch50(b *testing.B) {
  208. benchmarkMemStoreProvidergetByHeight(b, fcs50, h50, linearSearch)
  209. }
  210. func BenchmarkMemStoreProviderGetByHeightLinearSearch100(b *testing.B) {
  211. benchmarkMemStoreProvidergetByHeight(b, fcs100, h100, linearSearch)
  212. }
  213. func BenchmarkMemStoreProviderGetByHeightLinearSearch500(b *testing.B) {
  214. benchmarkMemStoreProvidergetByHeight(b, fcs500, h500, linearSearch)
  215. }
  216. func BenchmarkMemStoreProviderGetByHeightLinearSearch1000(b *testing.B) {
  217. benchmarkMemStoreProvidergetByHeight(b, fcs1000, h1000, linearSearch)
  218. }
  219. func BenchmarkMemStoreProviderGetByHeightBinarySearch5(b *testing.B) {
  220. benchmarkMemStoreProvidergetByHeight(b, fcs5, h5, binarySearch)
  221. }
  222. func BenchmarkMemStoreProviderGetByHeightBinarySearch50(b *testing.B) {
  223. benchmarkMemStoreProvidergetByHeight(b, fcs50, h50, binarySearch)
  224. }
  225. func BenchmarkMemStoreProviderGetByHeightBinarySearch100(b *testing.B) {
  226. benchmarkMemStoreProvidergetByHeight(b, fcs100, h100, binarySearch)
  227. }
  228. func BenchmarkMemStoreProviderGetByHeightBinarySearch500(b *testing.B) {
  229. benchmarkMemStoreProvidergetByHeight(b, fcs500, h500, binarySearch)
  230. }
  231. func BenchmarkMemStoreProviderGetByHeightBinarySearch1000(b *testing.B) {
  232. benchmarkMemStoreProvidergetByHeight(b, fcs1000, h1000, binarySearch)
  233. }
  234. var rng = rand.New(rand.NewSource(10))
  235. func benchmarkMemStoreProvidergetByHeight(b *testing.B, fcs []FullCommit, fHeights []int64, algo algo) {
  236. lazyGenerateFullCommits(b)
  237. b.StopTimer()
  238. mp := NewMemStoreProvider()
  239. for i, fc := range fcs {
  240. if err := mp.StoreCommit(fc); err != nil {
  241. b.Fatalf("FullCommit #%d: err: %v", i, err)
  242. }
  243. }
  244. qHeights := make([]int64, len(fHeights))
  245. copy(qHeights, fHeights)
  246. // Append some non-existent heights to trigger the worst cases.
  247. qHeights = append(qHeights, 19, -100, -10000, 1e7, -17, 31, -1e9)
  248. memP := mp.(*memStoreProvider)
  249. searchFn := memP.getByHeightLinearSearch
  250. if algo == binarySearch { // nolint
  251. searchFn = memP.getByHeightBinarySearch
  252. }
  253. hPerm := rng.Perm(len(qHeights))
  254. b.StartTimer()
  255. b.ResetTimer()
  256. for i := 0; i < b.N; i++ {
  257. for _, j := range hPerm {
  258. h := qHeights[j]
  259. if _, err := searchFn(h); err != nil {
  260. }
  261. }
  262. }
  263. b.ReportAllocs()
  264. }
  265. func genFullCommits(prevFC []FullCommit, prevH []int64, want int) ([]FullCommit, []int64) {
  266. fcs := make([]FullCommit, len(prevFC))
  267. copy(fcs, prevFC)
  268. heights := make([]int64, len(prevH))
  269. copy(heights, prevH)
  270. appHash := []byte("benchmarks")
  271. chainID := "benchmarks-gen-full-commits"
  272. n := want
  273. keys := GenValKeys(2 + (n / 3))
  274. for i := 0; i < n; i++ {
  275. vals := keys.ToValidators(10, int64(n/2))
  276. h := int64(20 + 10*i)
  277. fcs = append(fcs, keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5))
  278. heights = append(heights, h)
  279. }
  280. return fcs, heights
  281. }
  282. func TestMemStoreProviderLatestCommitAlwaysUsesSorted(t *testing.T) {
  283. p := NewMemStoreProvider().(*memStoreProvider)
  284. // 1. With no commits yet stored, it should return ErrCommitNotFound
  285. got, err := p.LatestCommit()
  286. require.Equal(t, err.Error(), liteErr.ErrCommitNotFound().Error(), "should return ErrCommitNotFound()")
  287. require.Equal(t, got, blankFullCommit, "With no fullcommits, it should return a blank FullCommit")
  288. // 2. Generate some full commits now and we'll add them unsorted.
  289. genAndStoreCommitsOfHeight(t, p, 27, 100, 1, 12, 1000, 17, 91)
  290. fc, err := p.LatestCommit()
  291. require.Nil(t, err, "with commits saved no error expected")
  292. require.NotEqual(t, fc, blankFullCommit, "with commits saved no blank FullCommit")
  293. require.Equal(t, fc.Height(), int64(1000), "the latest commit i.e. the largest expected")
  294. }
  295. func genAndStoreCommitsOfHeight(t *testing.T, p Provider, heights ...int64) {
  296. n := len(heights)
  297. appHash := []byte("tests")
  298. chainID := "tests-gen-full-commits"
  299. keys := GenValKeys(2 + (n / 3))
  300. for i := 0; i < n; i++ {
  301. h := heights[i]
  302. vals := keys.ToValidators(10, int64(n/2))
  303. fc := keys.GenFullCommit(chainID, h, nil, vals, appHash, []byte("params"), []byte("results"), 0, 5)
  304. err := p.StoreCommit(fc)
  305. require.NoError(t, err, "StoreCommit height=%d", h)
  306. }
  307. }