2022-09-30 11:40:22 +03:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2021-09-21 20:43:43 +03:00
|
|
|
import asyncio
|
2022-05-05 18:17:38 +03:00
|
|
|
import os
|
2021-09-21 20:43:43 +03:00
|
|
|
import random
|
2022-05-05 18:17:38 +03:00
|
|
|
import sys
|
2021-09-21 20:43:43 +03:00
|
|
|
from pathlib import Path
|
2022-05-05 18:17:38 +03:00
|
|
|
from time import monotonic
|
2021-10-12 19:27:47 +03:00
|
|
|
from typing import List, Tuple
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2022-05-05 18:17:38 +03:00
|
|
|
from utils import rand_hash, rewards, setup_db
|
|
|
|
|
|
|
|
from chia.full_node.coin_store import CoinStore
|
2021-09-21 20:43:43 +03:00
|
|
|
from chia.types.blockchain_format.coin import Coin
|
2022-05-05 18:17:38 +03:00
|
|
|
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
|
|
from chia.util.db_wrapper import DBWrapper2
|
|
|
|
from chia.util.ints import uint32, uint64
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
NUM_ITERS = 200
|
|
|
|
|
2021-11-23 20:53:59 +03:00
|
|
|
# we need seeded random, to have reproducible benchmark runs
|
|
|
|
random.seed(123456789)
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2021-11-23 20:53:59 +03:00
|
|
|
|
2021-09-21 20:43:43 +03:00
|
|
|
def make_coin() -> Coin:
|
|
|
|
return Coin(rand_hash(), rand_hash(), uint64(1))
|
|
|
|
|
|
|
|
|
2021-10-12 19:27:47 +03:00
|
|
|
def make_coins(num: int) -> Tuple[List[Coin], List[bytes32]]:
|
|
|
|
additions: List[Coin] = []
|
|
|
|
hashes: List[bytes32] = []
|
|
|
|
for i in range(num):
|
|
|
|
c = make_coin()
|
|
|
|
additions.append(c)
|
2022-06-13 15:21:04 +03:00
|
|
|
hashes.append(c.name())
|
2021-10-12 19:27:47 +03:00
|
|
|
|
|
|
|
return additions, hashes
|
|
|
|
|
|
|
|
|
2023-03-06 20:50:44 +03:00
|
|
|
async def run_new_block_benchmark(version: int) -> None:
|
2021-10-18 19:33:20 +03:00
|
|
|
verbose: bool = "--verbose" in sys.argv
|
2022-03-28 21:58:00 +03:00
|
|
|
db_wrapper: DBWrapper2 = await setup_db("coin-store-benchmark.db", version)
|
2021-11-23 20:53:59 +03:00
|
|
|
|
|
|
|
# keep track of benchmark total time
|
2021-12-04 00:52:10 +03:00
|
|
|
all_test_time = 0.0
|
2021-11-23 20:53:59 +03:00
|
|
|
|
2021-09-21 20:43:43 +03:00
|
|
|
try:
|
|
|
|
coin_store = await CoinStore.create(db_wrapper)
|
|
|
|
|
2021-10-12 19:27:47 +03:00
|
|
|
all_unspent: List[bytes32] = []
|
|
|
|
all_coins: List[bytes32] = []
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
block_height = 1
|
|
|
|
timestamp = 1631794488
|
|
|
|
|
|
|
|
print("Building database ", end="")
|
|
|
|
for height in range(block_height, block_height + NUM_ITERS):
|
|
|
|
# add some new coins
|
2021-10-12 19:27:47 +03:00
|
|
|
additions, hashes = make_coins(2000)
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
# farm rewards
|
2021-12-04 00:52:10 +03:00
|
|
|
farmer_coin, pool_coin = rewards(uint32(height))
|
2021-10-12 19:27:47 +03:00
|
|
|
all_coins += hashes
|
|
|
|
all_unspent += hashes
|
|
|
|
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
# remove some coins we've added previously
|
2021-10-12 19:27:47 +03:00
|
|
|
random.shuffle(all_unspent)
|
|
|
|
removals = all_unspent[:100]
|
|
|
|
all_unspent = all_unspent[100:]
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
await coin_store.new_block(
|
2022-09-08 20:57:15 +03:00
|
|
|
uint32(height),
|
|
|
|
uint64(timestamp),
|
|
|
|
{pool_coin, farmer_coin},
|
2021-09-21 20:43:43 +03:00
|
|
|
additions,
|
|
|
|
removals,
|
|
|
|
)
|
|
|
|
|
|
|
|
# 19 seconds per block
|
|
|
|
timestamp += 19
|
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-09-21 20:43:43 +03:00
|
|
|
block_height += NUM_ITERS
|
|
|
|
|
2021-12-04 00:52:10 +03:00
|
|
|
total_time = 0.0
|
|
|
|
total_add = 0.0
|
|
|
|
total_remove = 0.0
|
2021-10-18 19:33:20 +03:00
|
|
|
print("")
|
|
|
|
if verbose:
|
|
|
|
print("Profiling mostly additions ", end="")
|
2021-09-21 20:43:43 +03:00
|
|
|
for height in range(block_height, block_height + NUM_ITERS):
|
|
|
|
# add some new coins
|
2021-10-12 19:27:47 +03:00
|
|
|
additions, hashes = make_coins(2000)
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add += 2000
|
|
|
|
|
2021-12-04 00:52:10 +03:00
|
|
|
farmer_coin, pool_coin = rewards(uint32(height))
|
2021-10-12 19:27:47 +03:00
|
|
|
all_coins += hashes
|
|
|
|
all_unspent += hashes
|
|
|
|
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add += 2
|
|
|
|
|
|
|
|
# remove some coins we've added previously
|
2021-10-12 19:27:47 +03:00
|
|
|
random.shuffle(all_unspent)
|
|
|
|
removals = all_unspent[:100]
|
|
|
|
all_unspent = all_unspent[100:]
|
2021-09-21 20:43:43 +03:00
|
|
|
total_remove += 100
|
|
|
|
|
2022-02-16 01:42:51 +03:00
|
|
|
start = monotonic()
|
2021-09-21 20:43:43 +03:00
|
|
|
await coin_store.new_block(
|
2022-09-08 20:57:15 +03:00
|
|
|
uint32(height),
|
|
|
|
uint64(timestamp),
|
|
|
|
{pool_coin, farmer_coin},
|
2021-09-21 20:43:43 +03:00
|
|
|
additions,
|
|
|
|
removals,
|
|
|
|
)
|
2022-02-16 01:42:51 +03:00
|
|
|
stop = monotonic()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
# 19 seconds per block
|
|
|
|
timestamp += 19
|
|
|
|
|
|
|
|
total_time += stop - start
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
block_height += NUM_ITERS
|
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("")
|
|
|
|
print(f"{total_time:0.4f}s, MOSTLY ADDITIONS additions: {total_add} removals: {total_remove}")
|
2021-11-23 20:53:59 +03:00
|
|
|
all_test_time += total_time
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("Profiling mostly removals ", end="")
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add = 0
|
|
|
|
total_remove = 0
|
|
|
|
total_time = 0
|
|
|
|
for height in range(block_height, block_height + NUM_ITERS):
|
|
|
|
additions = []
|
|
|
|
|
|
|
|
# add one new coins
|
|
|
|
c = make_coin()
|
|
|
|
additions.append(c)
|
|
|
|
total_add += 1
|
|
|
|
|
2021-12-04 00:52:10 +03:00
|
|
|
farmer_coin, pool_coin = rewards(uint32(height))
|
2022-06-13 15:21:04 +03:00
|
|
|
all_coins += [c.name()]
|
|
|
|
all_unspent += [c.name()]
|
2021-10-12 19:27:47 +03:00
|
|
|
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add += 2
|
|
|
|
|
|
|
|
# remove some coins we've added previously
|
2021-10-12 19:27:47 +03:00
|
|
|
random.shuffle(all_unspent)
|
|
|
|
removals = all_unspent[:700]
|
|
|
|
all_unspent = all_unspent[700:]
|
2021-09-21 20:43:43 +03:00
|
|
|
total_remove += 700
|
|
|
|
|
2022-02-16 01:42:51 +03:00
|
|
|
start = monotonic()
|
2021-09-21 20:43:43 +03:00
|
|
|
await coin_store.new_block(
|
2022-09-08 20:57:15 +03:00
|
|
|
uint32(height),
|
|
|
|
uint64(timestamp),
|
|
|
|
{pool_coin, farmer_coin},
|
2021-09-21 20:43:43 +03:00
|
|
|
additions,
|
|
|
|
removals,
|
|
|
|
)
|
|
|
|
|
2022-02-16 01:42:51 +03:00
|
|
|
stop = monotonic()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
# 19 seconds per block
|
|
|
|
timestamp += 19
|
|
|
|
|
|
|
|
total_time += stop - start
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
block_height += NUM_ITERS
|
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("")
|
|
|
|
print(f"{total_time:0.4f}s, MOSTLY REMOVALS additions: {total_add} removals: {total_remove}")
|
2021-11-23 20:53:59 +03:00
|
|
|
all_test_time += total_time
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("Profiling full block transactions", end="")
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add = 0
|
|
|
|
total_remove = 0
|
|
|
|
total_time = 0
|
|
|
|
for height in range(block_height, block_height + NUM_ITERS):
|
|
|
|
# add some new coins
|
2021-10-12 19:27:47 +03:00
|
|
|
additions, hashes = make_coins(2000)
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add += 2000
|
|
|
|
|
2021-12-04 00:52:10 +03:00
|
|
|
farmer_coin, pool_coin = rewards(uint32(height))
|
2021-10-12 19:27:47 +03:00
|
|
|
all_coins += hashes
|
|
|
|
all_unspent += hashes
|
|
|
|
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
2021-09-21 20:43:43 +03:00
|
|
|
total_add += 2
|
|
|
|
|
|
|
|
# remove some coins we've added previously
|
2021-10-12 19:27:47 +03:00
|
|
|
random.shuffle(all_unspent)
|
|
|
|
removals = all_unspent[:2000]
|
|
|
|
all_unspent = all_unspent[2000:]
|
2021-09-21 20:43:43 +03:00
|
|
|
total_remove += 2000
|
|
|
|
|
2022-02-16 01:42:51 +03:00
|
|
|
start = monotonic()
|
2021-09-21 20:43:43 +03:00
|
|
|
await coin_store.new_block(
|
2022-09-08 20:57:15 +03:00
|
|
|
uint32(height),
|
|
|
|
uint64(timestamp),
|
|
|
|
{pool_coin, farmer_coin},
|
2021-09-21 20:43:43 +03:00
|
|
|
additions,
|
|
|
|
removals,
|
|
|
|
)
|
2022-02-16 01:42:51 +03:00
|
|
|
stop = monotonic()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
# 19 seconds per block
|
|
|
|
timestamp += 19
|
|
|
|
|
|
|
|
total_time += stop - start
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2021-10-12 19:27:47 +03:00
|
|
|
block_height += NUM_ITERS
|
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("")
|
|
|
|
print(f"{total_time:0.4f}s, FULLBLOCKS additions: {total_add} removals: {total_remove}")
|
2021-11-23 20:53:59 +03:00
|
|
|
all_test_time += total_time
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("profiling get_coin_records_by_names, include_spent ", end="")
|
2021-10-12 19:27:47 +03:00
|
|
|
total_time = 0
|
|
|
|
found_coins = 0
|
|
|
|
for i in range(NUM_ITERS):
|
|
|
|
lookup = random.sample(all_coins, 200)
|
2022-02-16 01:42:51 +03:00
|
|
|
start = monotonic()
|
2021-10-12 19:27:47 +03:00
|
|
|
records = await coin_store.get_coin_records_by_names(True, lookup)
|
2022-02-16 01:42:51 +03:00
|
|
|
total_time += monotonic() - start
|
2021-10-12 19:27:47 +03:00
|
|
|
assert len(records) == 200
|
|
|
|
found_coins += len(records)
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-10-12 19:27:47 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("")
|
2021-10-12 19:27:47 +03:00
|
|
|
print(
|
2021-10-18 19:33:20 +03:00
|
|
|
f"{total_time:0.4f}s, GET RECORDS BY NAMES with spent {NUM_ITERS} "
|
2021-10-12 19:27:47 +03:00
|
|
|
f"lookups found {found_coins} coins in total"
|
|
|
|
)
|
2021-11-23 20:53:59 +03:00
|
|
|
all_test_time += total_time
|
2021-10-12 19:27:47 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("profiling get_coin_records_by_names, without spent coins ", end="")
|
2021-10-12 19:27:47 +03:00
|
|
|
total_time = 0
|
|
|
|
found_coins = 0
|
|
|
|
for i in range(NUM_ITERS):
|
|
|
|
lookup = random.sample(all_coins, 200)
|
2022-02-16 01:42:51 +03:00
|
|
|
start = monotonic()
|
2021-10-12 19:27:47 +03:00
|
|
|
records = await coin_store.get_coin_records_by_names(False, lookup)
|
2022-02-16 01:42:51 +03:00
|
|
|
total_time += monotonic() - start
|
2021-10-12 19:27:47 +03:00
|
|
|
assert len(records) <= 200
|
|
|
|
found_coins += len(records)
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-10-12 19:27:47 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("")
|
2021-10-12 19:27:47 +03:00
|
|
|
print(
|
2021-10-18 19:33:20 +03:00
|
|
|
f"{total_time:0.4f}s, GET RECORDS BY NAMES without spent {NUM_ITERS} "
|
2021-10-12 19:27:47 +03:00
|
|
|
f"lookups found {found_coins} coins in total"
|
|
|
|
)
|
2021-11-23 20:53:59 +03:00
|
|
|
all_test_time += total_time
|
2021-10-12 19:27:47 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("profiling get_coin_removed_at_height ", end="")
|
2021-10-12 19:27:47 +03:00
|
|
|
total_time = 0
|
|
|
|
found_coins = 0
|
|
|
|
for i in range(1, block_height):
|
2022-02-16 01:42:51 +03:00
|
|
|
start = monotonic()
|
2022-09-08 20:57:15 +03:00
|
|
|
records = await coin_store.get_coins_removed_at_height(uint32(i))
|
2022-02-16 01:42:51 +03:00
|
|
|
total_time += monotonic() - start
|
2021-10-12 19:27:47 +03:00
|
|
|
found_coins += len(records)
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print(".", end="")
|
|
|
|
sys.stdout.flush()
|
2021-10-12 19:27:47 +03:00
|
|
|
|
2021-10-18 19:33:20 +03:00
|
|
|
if verbose:
|
|
|
|
print("")
|
2021-10-12 19:27:47 +03:00
|
|
|
print(
|
2021-10-18 19:33:20 +03:00
|
|
|
f"{total_time:0.4f}s, GET COINS REMOVED AT HEIGHT {block_height-1} blocks, "
|
2021-10-12 19:27:47 +03:00
|
|
|
f"found {found_coins} coins in total"
|
|
|
|
)
|
2021-11-23 20:53:59 +03:00
|
|
|
all_test_time += total_time
|
|
|
|
print(f"all tests completed in {all_test_time:0.4f}s")
|
2021-10-12 19:27:47 +03:00
|
|
|
|
2021-09-21 20:43:43 +03:00
|
|
|
finally:
|
2022-03-28 21:58:00 +03:00
|
|
|
await db_wrapper.close()
|
2021-09-21 20:43:43 +03:00
|
|
|
|
2021-11-29 18:48:42 +03:00
|
|
|
db_size = os.path.getsize(Path("coin-store-benchmark.db"))
|
2021-12-06 22:22:12 +03:00
|
|
|
print(f"database size: {db_size/1000000:.3f} MB")
|
2021-11-29 18:48:42 +03:00
|
|
|
|
2021-09-21 20:43:43 +03:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2021-12-04 00:52:10 +03:00
|
|
|
print("version 1")
|
|
|
|
asyncio.run(run_new_block_benchmark(1))
|
|
|
|
print("version 2")
|
|
|
|
asyncio.run(run_new_block_benchmark(2))
|