From 7a76e47601d56835650ca0e12eaf6338e3353a92 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 5 Oct 2022 09:20:29 -0400 Subject: [PATCH 01/23] adjust none end calculation --- bittensor/utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 1da54cab7e..ad796b37f6 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -285,8 +285,8 @@ def run(self): self.newBlockEvent.clear() # reset nonces to start from random point - nonce_start = self.update_interval * self.proc_num + random.randint( 0, nonce_limit ) - nonce_end = nonce_start + self.update_interval + nonce_start = self.TPB * self.update_interval * self.proc_num + random.randint( 0, nonce_limit ) + nonce_end = nonce_start + self.update_interval * self.TPB # Do a block of nonces solution, time = solve_for_nonce_block_cuda(self, nonce_start, self.update_interval, block_bytes, block_difficulty, self.limit, block_number, self.dev_id, self.TPB) From 049f05e4466902cc0d6dccc5c00051dae80a9235 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 5 Oct 2022 09:21:39 -0400 Subject: [PATCH 02/23] attempt to fix stop issue --- bittensor/utils/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index ad796b37f6..d4e30a40ab 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -518,6 +518,10 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = stopEvent.set() # stop all other processes status.stop() + # wait for rest to exit + for w in solvers: + w.join() + return solution def get_human_readable(num, suffix="H"): From 9bb48ff6f3aebd3ec9d32c26fd25a97227f9c296 Mon Sep 17 00:00:00 2001 From: camfairchild Date: Wed, 5 Oct 2022 17:12:20 -0400 Subject: [PATCH 03/23] modify stop --- bittensor/utils/__init__.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index d4e30a40ab..8482961849 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -518,8 +518,9 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = stopEvent.set() # stop all other processes status.stop() - # wait for rest to exit + # terminate and wait for sovlers to exit for w in solvers: + w.terminate() w.join() return solution @@ -701,15 +702,15 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu Block_hash: [bold white]{block_hash.encode('utf-8')}[/bold white]""" status.update(message.replace(" ", "")) - # exited while, found_solution contains the nonce or wallet is registered - if solution is not None: - stopEvent.set() # stop all other processes - status.stop() + # exited while, solution contains the nonce or wallet is registered + stopEvent.set() # stop all other processes + status.stop() - return solution + for w in solvers: # terminate and wait for all solvers + w.terminate() + w.join() - status.stop() - return None + return solution def create_pow( subtensor, wallet, cuda: bool = False, dev_id: Union[List[int], int] = 0, tpb: int = 256, num_processes: int = None, update_interval: int = None) -> Optional[Dict[str, Any]]: if cuda: From 3da133ec41e8da1ba53e76f7db903a58cf1ef65e Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Thu, 6 Oct 2022 22:43:09 -0400 Subject: [PATCH 04/23] update nonce_start by correct amount --- bittensor/utils/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 8482961849..86a62c73e7 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -275,7 +275,6 @@ def run(self): # Start at random nonce nonce_start = self.TPB * self.update_interval * self.proc_num + random.randint( 0, nonce_limit ) - nonce_end = nonce_start + self.update_interval * self.TPB while not self.stopEvent.is_set(): if self.newBlockEvent.is_set(): with self.check_block: @@ -286,7 +285,6 @@ def run(self): self.newBlockEvent.clear() # reset nonces to start from random point nonce_start = self.TPB * self.update_interval * self.proc_num + random.randint( 0, nonce_limit ) - nonce_end = nonce_start + self.update_interval * self.TPB # Do a block of nonces solution, time = solve_for_nonce_block_cuda(self, nonce_start, self.update_interval, block_bytes, block_difficulty, self.limit, block_number, self.dev_id, self.TPB) @@ -296,9 +294,8 @@ def run(self): # Send time self.time_queue.put_nowait(time) - nonce_start += self.update_interval * self.num_proc + nonce_start += self.update_interval * self.num_proc * self.TPB nonce_start = nonce_start % nonce_limit - nonce_end += self.update_interval * self.num_proc def solve_for_nonce_block_cuda(solver: CUDASolver, nonce_start: int, update_interval: int, block_bytes: bytes, difficulty: int, limit: int, block_number: int, dev_id: int, TPB: int) -> Tuple[Optional[POWSolution], int]: From 418b3a4fc0d47ccf2cdad2d50c7c01420554b431 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Fri, 7 Oct 2022 11:59:08 -0400 Subject: [PATCH 05/23] fix nonce init to only random and update --- bittensor/utils/__init__.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 86a62c73e7..78a90c00b2 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -241,11 +241,6 @@ def run(self): block_difficulty = registration_diff_unpack(self.curr_diff) self.newBlockEvent.clear() - # reset nonces to start from random point - # prevents the same nonces (for each block) from being tried by multiple processes - # also prevents the same nonces from being tried by multiple peers - nonce_start = random.randint( 0, nonce_limit ) - nonce_end = nonce_start + self.update_interval # Do a block of nonces solution, time = solve_for_nonce_block(self, nonce_start, nonce_end, block_bytes, block_difficulty, self.limit, block_number) @@ -255,8 +250,9 @@ def run(self): # Send time self.time_queue.put_nowait(time) - nonce_start += self.update_interval * self.num_proc - nonce_end += self.update_interval * self.num_proc + nonce_start = random.randint( 0, nonce_limit ) + nonce_end += self.update_interval + nonce_start = nonce_start % nonce_limit class CUDASolver(SolverBase): dev_id: int @@ -274,7 +270,7 @@ def run(self): nonce_limit = int(math.pow(2,64)) - 1 # Start at random nonce - nonce_start = self.TPB * self.update_interval * self.proc_num + random.randint( 0, nonce_limit ) + nonce_start = random.randint( 0, nonce_limit ) while not self.stopEvent.is_set(): if self.newBlockEvent.is_set(): with self.check_block: @@ -283,8 +279,6 @@ def run(self): block_difficulty = registration_diff_unpack(self.curr_diff) self.newBlockEvent.clear() - # reset nonces to start from random point - nonce_start = self.TPB * self.update_interval * self.proc_num + random.randint( 0, nonce_limit ) # Do a block of nonces solution, time = solve_for_nonce_block_cuda(self, nonce_start, self.update_interval, block_bytes, block_difficulty, self.limit, block_number, self.dev_id, self.TPB) @@ -293,8 +287,9 @@ def run(self): # Send time self.time_queue.put_nowait(time) - - nonce_start += self.update_interval * self.num_proc * self.TPB + + # increase nonce by number of nonces processed + nonce_start += self.update_interval * self.TPB nonce_start = nonce_start % nonce_limit From fed88a39bf363c8b5ccfca546d4106ad91cb0841 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Fri, 7 Oct 2022 12:06:54 -0400 Subject: [PATCH 06/23] fix update amount --- bittensor/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 78a90c00b2..de5b256013 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -251,8 +251,8 @@ def run(self): self.time_queue.put_nowait(time) nonce_start = random.randint( 0, nonce_limit ) - nonce_end += self.update_interval nonce_start = nonce_start % nonce_limit + nonce_end = nonce_start + self.update_interval class CUDASolver(SolverBase): dev_id: int From 8b0883c0f6db65513d5f834fee5cf033bbeece08 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Fri, 7 Oct 2022 12:08:08 -0400 Subject: [PATCH 07/23] add start values --- bittensor/utils/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index de5b256013..42a8cc27df 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -264,10 +264,10 @@ def __init__(self, proc_num, num_proc, update_interval, time_queue, solution_que self.TPB = TPB def run(self): - block_number: int - block_bytes: bytes - block_difficulty: int - nonce_limit = int(math.pow(2,64)) - 1 + block_number: int = 0 # dummy value + block_bytes: bytes = b'0' * 32 # dummy value + block_difficulty: int = int(math.pow(2,64)) - 1 # dummy value + nonce_limit = int(math.pow(2,64)) - 1 # U64MAX # Start at random nonce nonce_start = random.randint( 0, nonce_limit ) From d6510d5a3bec04fd54268b327561ff75184ef4cf Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Fri, 7 Oct 2022 12:12:51 -0400 Subject: [PATCH 08/23] add test --- .../bittensor_tests/utils/test_utils.py | 126 ++++++++---------- 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/tests/unit_tests/bittensor_tests/utils/test_utils.py b/tests/unit_tests/bittensor_tests/utils/test_utils.py index feb1807250..669877d62e 100644 --- a/tests/unit_tests/bittensor_tests/utils/test_utils.py +++ b/tests/unit_tests/bittensor_tests/utils/test_utils.py @@ -1,26 +1,24 @@ import binascii import hashlib -import unittest -import bittensor -import sys +import math +import multiprocessing +import os +import random import subprocess +import sys import time -import pytest -import os -import random -import torch -import multiprocessing +import unittest +from sys import platform from types import SimpleNamespace +from unittest.mock import MagicMock, patch -from sys import platform -from substrateinterface.base import Keypair +import bittensor +import pytest +import torch from _pytest.fixtures import fixture +from bittensor.utils import CUDASolver from loguru import logger - -from types import SimpleNamespace - -from unittest.mock import MagicMock, patch - +from substrateinterface.base import Keypair @fixture(scope="function") @@ -400,60 +398,54 @@ class MockException(Exception): assert call1[1]['call_function'] == 'register' call_params = call1[1]['call_params'] assert call_params['nonce'] == mock_result['nonce'] - - -def test_pow_called_for_cuda(): - class MockException(Exception): - pass - mock_compose_call = MagicMock(side_effect=MockException) - - mock_subtensor = bittensor.subtensor(_mock=True) - mock_subtensor.neuron_for_pubkey=MagicMock(is_null=True) - mock_subtensor.substrate = MagicMock( - __enter__= MagicMock(return_value=MagicMock( - compose_call=mock_compose_call - )), - __exit__ = MagicMock(return_value=None), - ) - - mock_wallet = SimpleNamespace( - hotkey=SimpleNamespace( - ss58_address='' - ), - coldkeypub=SimpleNamespace( - ss58_address='' - ) - ) - mock_result = { - "block_number": 1, - 'nonce': random.randint(0, pow(2, 32)), - 'work': b'\x00' * 64, - } +class TestCUDASolverRun(unittest.TestCase): + def test_multi_cuda_run_updates_nonce_start(self): + class MockException(Exception): + pass + + TPB: int = 512 + update_interval: int = 70_000 + nonce_limit: int = int(math.pow(2, 64)) - 1 + + mock_solver_self = MagicMock( + spec=CUDASolver, + TPB=TPB, + dev_id=0, + update_interval=update_interval, + stopEvent=MagicMock(is_set=MagicMock(return_value=False)), + newBlockEvent=MagicMock(is_set=MagicMock(return_value=False)), + time_queue=MagicMock(put_nowait=MagicMock()), + limit=10000 + ) - with patch('bittensor.utils.POWNotStale', return_value=True) as mock_pow_not_stale: - with patch('torch.cuda.is_available', return_value=True) as mock_cuda_available: - with patch('bittensor.utils.create_pow', return_value=mock_result) as mock_create_pow: - with patch('bittensor.utils.hex_bytes_to_u8_list', return_value=b''): - - # Should exit early - with pytest.raises(MockException): - mock_subtensor.register(mock_wallet, cuda=True, prompt=False) - - mock_pow_not_stale.assert_called_once() - mock_create_pow.assert_called_once() - mock_cuda_available.assert_called_once() - - call0 = mock_pow_not_stale.call_args - assert call0[0][0] == mock_subtensor - assert call0[0][1] == mock_result - - mock_compose_call.assert_called_once() - call1 = mock_compose_call.call_args - assert call1[1]['call_function'] == 'register' - call_params = call1[1]['call_params'] - assert call_params['nonce'] == mock_result['nonce'] + + with patch('bittensor.utils.solve_for_nonce_block_cuda', + side_effect=[(None, 10.0), MockException] # first call returns mocked no solution, second call raises exception + ) as mock_solve_for_nonce_block_cuda: + + # Should exit early + with pytest.raises(MockException): + CUDASolver.run(mock_solver_self) + + mock_solve_for_nonce_block_cuda.assert_called() + calls = mock_solve_for_nonce_block_cuda.call_args_list + self.assertEqual(len(calls), 2, f"solve_for_nonce_block_cuda was called {len(calls)}. Expected 2") # called only twice + + # args, kwargs + args_call_0, _ = calls[0] + initial_nonce_start: int = args_call_0[1] # second arg should be nonce_start + self.assertIsInstance(initial_nonce_start, int) + + args_call_1, _ = calls[1] + nonce_start_after_iteration: int = args_call_1[1] # second arg should be nonce_start + self.assertIsInstance(nonce_start_after_iteration, int) + + # verify nonce_start is updated after each iteration + self.assertNotEqual(nonce_start_after_iteration, initial_nonce_start, "nonce_start was not updated after iteration") + ## Should incerase by the number of nonces tried == TPB * update_interval + self.assertEqual(nonce_start_after_iteration, (initial_nonce_start + update_interval * TPB) % nonce_limit, "nonce_start was not updated by the correct amount") if __name__ == "__main__": - test_solve_for_difficulty_fast_registered_already() + unittest.main() From bf005159868aa4812347ba4d6984aef81b4a30ac Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Sun, 9 Oct 2022 17:29:53 -0400 Subject: [PATCH 09/23] try different hashrate calc --- bittensor/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 42a8cc27df..85e0232ca0 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -683,7 +683,7 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu if num_time > 0: time_avg = time_total / num_time - itrs_per_sec = TPB*update_interval*num_processes / time_avg + itrs_per_sec = TPB*update_interval / time_avg time_since = time.time() - start_time message = f"""Solving From 1d0ecd2819090a440684fb689aa70372f463bec4 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 10:16:28 -0400 Subject: [PATCH 10/23] try EWMA for hash_rate --- bittensor/utils/__init__.py | 39 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 85e0232ca0..ee707741a8 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -8,6 +8,7 @@ import time from dataclasses import dataclass from queue import Empty +from tracemalloc import start from typing import Any, Dict, List, Optional, Tuple, Union import backoff @@ -639,10 +640,18 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu for w in solvers: w.start() # start the solver processes - start_time = time.time() - time_since = 0.0 + start_time = time.time() # time that the registration started + time_last = start_time # time that the last work blocks completed + solution = None - itrs_per_sec = 0 + hash_rate = 0 # EWMA hash_rate (H/s) + + n = 5 # number of samples to keep + alpha_ = 0.70 # EWMA alpha for hash_rate + + hash_rates = [0] * n # The last n true hash_rates + weights = [alpha_ ** i for i in range(n)] # weights decay by alpha + while not wallet.is_registered(subtensor): # Wait until a solver finds a solution try: @@ -668,28 +677,34 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu # Set new block events for each solver for w in solvers: w.newBlockEvent.set() - - # Get times for each solver - time_total = 0 + num_time = 0 + # Get times for each solver for _ in solvers: try: - time_ = time_queue.get_nowait() - time_total += time_ + _ = time_queue.get_nowait() num_time += 1 except Empty: break + time_since = time.time() - start_time if num_time > 0: - time_avg = time_total / num_time - itrs_per_sec = TPB*update_interval / time_avg - time_since = time.time() - start_time + time_since_last = time.time() - time_last + # create EWMA of the hash_rate to make measure more robust + hash_rate_ = ((num_time * TPB * update_interval) / time_since_last) + hash_rates.append(hash_rate_) + hash_rates.pop(0) # remove the 0th data point + hash_rate = sum([hash_rates[i]*weights[i] for i in range(n)])/(sum(weights)) + + # update time last to now + time_last = time.time() + message = f"""Solving time spent: {time_since} Difficulty: [bold white]{millify(difficulty)}[/bold white] - Iters: [bold white]{get_human_readable(int(itrs_per_sec), 'H')}/s[/bold white] + Iters: [bold white]{get_human_readable(int(hash_rate), 'H')}/s[/bold white] Block: [bold white]{block_number}[/bold white] Block_hash: [bold white]{block_hash.encode('utf-8')}[/bold white]""" status.update(message.replace(" ", "")) From a20e992408065a21e04cfceb1edfb59f9c43bad5 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 10:17:01 -0400 Subject: [PATCH 11/23] oops bad import --- bittensor/utils/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index ee707741a8..583e7c66ec 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -8,7 +8,6 @@ import time from dataclasses import dataclass from queue import Empty -from tracemalloc import start from typing import Any, Dict, List, Optional, Tuple, Union import backoff From 241f6218ab1a6159a1babfd46990b52c3aeb6c70 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 11:44:45 -0400 Subject: [PATCH 12/23] change name to worker --- bittensor/utils/__init__.py | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 583e7c66ec..253c07cd28 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -434,11 +434,11 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = update_curr_block(curr_diff, curr_block, curr_block_num, block_number, block_bytes, difficulty, check_block) # Set new block events for each solver to start - for w in solvers: - w.newBlockEvent.set() + for worker in solvers: + worker.newBlockEvent.set() - for w in solvers: - w.start() # start the solver processes + for worker in solvers: + worker.start() # start the solver processes start_time = time.time() solution = None @@ -467,8 +467,8 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = update_curr_block(curr_diff, curr_block, curr_block_num, block_number, block_bytes, difficulty, check_block) # Set new block events for each solver - for w in solvers: - w.newBlockEvent.set() + for worker in solvers: + worker.newBlockEvent.set() # Get times for each solver time_total = 0 @@ -510,10 +510,10 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = stopEvent.set() # stop all other processes status.stop() - # terminate and wait for sovlers to exit - for w in solvers: - w.terminate() - w.join() + # terminate and wait for solvers/workers to exit + for worker in solvers: + worker.terminate() + worker.join() return solution @@ -633,11 +633,11 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu update_curr_block(block_number, block_bytes, difficulty, check_block) # Set new block events for each solver to start - for w in solvers: - w.newBlockEvent.set() + for worker in solvers: + worker.newBlockEvent.set() - for w in solvers: - w.start() # start the solver processes + for worker in solvers: + worker.start() # start the solver processes start_time = time.time() # time that the registration started time_last = start_time # time that the last work blocks completed @@ -674,9 +674,10 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu update_curr_block(block_number, block_bytes, difficulty, check_block) # Set new block events for each solver - for w in solvers: - w.newBlockEvent.set() - + + for worker in solvers: + worker.newBlockEvent.set() + num_time = 0 # Get times for each solver for _ in solvers: @@ -712,9 +713,9 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu stopEvent.set() # stop all other processes status.stop() - for w in solvers: # terminate and wait for all solvers - w.terminate() - w.join() + for worker in solvers: # terminate and wait for all solvers + worker.terminate() + worker.join() return solution From cbd632c2b023b8e88470348da17386075abfcf30 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 11:49:04 -0400 Subject: [PATCH 13/23] extract helper and modify comment --- bittensor/utils/__init__.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 253c07cd28..143087d16f 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -433,7 +433,7 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = # Set to current block update_curr_block(curr_diff, curr_block, curr_block_num, block_number, block_bytes, difficulty, check_block) - # Set new block events for each solver to start + # Set new block events for each solver to start at the initial block for worker in solvers: worker.newBlockEvent.set() @@ -510,10 +510,8 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = stopEvent.set() # stop all other processes status.stop() - # terminate and wait for solvers/workers to exit - for worker in solvers: - worker.terminate() - worker.join() + # terminate and wait for all solvers to exit + terminate_workers_and_wait_for_exit(solvers) return solution @@ -632,7 +630,7 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu # Set to current block update_curr_block(block_number, block_bytes, difficulty, check_block) - # Set new block events for each solver to start + # Set new block events for each solver to start at the initial block for worker in solvers: worker.newBlockEvent.set() @@ -713,12 +711,17 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu stopEvent.set() # stop all other processes status.stop() - for worker in solvers: # terminate and wait for all solvers - worker.terminate() - worker.join() + # terminate and wait for all solvers to exit + terminate_workers_and_wait_for_exit(solvers) return solution +def terminate_workers_and_wait_for_exit(workers: List[multiprocessing.Process]) -> None: + for worker in workers: + worker.terminate() + worker.join() + + def create_pow( subtensor, wallet, cuda: bool = False, dev_id: Union[List[int], int] = 0, tpb: int = 256, num_processes: int = None, update_interval: int = None) -> Optional[Dict[str, Any]]: if cuda: solution: POWSolution = solve_for_difficulty_fast_cuda( subtensor, wallet, dev_id=dev_id, TPB=tpb, update_interval=update_interval ) From 4f46cd95512a97480255efd02d4062bcd596a9f8 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 16:08:15 -0400 Subject: [PATCH 14/23] fix time now --- bittensor/utils/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 143087d16f..a9d8482281 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -686,17 +686,20 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu except Empty: break - time_since = time.time() - start_time - if num_time > 0: - time_since_last = time.time() - time_last + time_now = time.time() # get current time + time_since_last = time_now - time_last # get time since last work block(s) + if num_time > 0 and time_since_last > 0.0: # create EWMA of the hash_rate to make measure more robust - hash_rate_ = ((num_time * TPB * update_interval) / time_since_last) + + hash_rate_ = (num_time * TPB * update_interval) / time_since_last hash_rates.append(hash_rate_) hash_rates.pop(0) # remove the 0th data point hash_rate = sum([hash_rates[i]*weights[i] for i in range(n)])/(sum(weights)) # update time last to now - time_last = time.time() + time_last = time_now + + time_since = time_now - start_time message = f"""Solving From 4e86b5bd605cb868435bdaf274c912e195862923 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 17:24:59 -0400 Subject: [PATCH 15/23] catch Full --- bittensor/utils/__init__.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index a9d8482281..09929ac689 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -7,7 +7,7 @@ import random import time from dataclasses import dataclass -from queue import Empty +from queue import Empty, Full from typing import Any, Dict, List, Optional, Tuple, Union import backoff @@ -247,8 +247,11 @@ def run(self): if solution is not None: self.solution_queue.put(solution) - # Send time - self.time_queue.put_nowait(time) + try: + # Send time + self.time_queue.put_nowait(time) + except Full: + pass nonce_start = random.randint( 0, nonce_limit ) nonce_start = nonce_start % nonce_limit @@ -284,9 +287,12 @@ def run(self): solution, time = solve_for_nonce_block_cuda(self, nonce_start, self.update_interval, block_bytes, block_difficulty, self.limit, block_number, self.dev_id, self.TPB) if solution is not None: self.solution_queue.put(solution) - - # Send time - self.time_queue.put_nowait(time) + + try: + # Send time + self.time_queue.put_nowait(time) + except Full: + pass # increase nonce by number of nonces processed nonce_start += self.update_interval * self.TPB From 3a76a790cfc34cfcdb7020dd2055320b0ef63d41 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 18:44:52 -0400 Subject: [PATCH 16/23] use a finished queue instead of times --- bittensor/utils/__init__.py | 125 +++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 09929ac689..6a5b825cf3 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -158,8 +158,8 @@ class SolverBase(multiprocessing.Process): best_queue: multiprocessing.Queue The queue to put the best nonce the process has found during the pow solve. New nonces are added each update_interval. - time_queue: multiprocessing.Queue - The queue to put the time the process took to finish each update_interval. + finished_queue: multiprocessing.Queue + The queue to put the process number when a process finishes each update_interval. Used for calculating the average time per update_interval across all processes. solution_queue: multiprocessing.Queue The queue to put the solution the process has found during the pow solve. @@ -193,7 +193,7 @@ class SolverBase(multiprocessing.Process): num_proc: int update_interval: int best_queue: Optional[multiprocessing.Queue] - time_queue: multiprocessing.Queue + finished_queue: multiprocessing.Queue solution_queue: multiprocessing.Queue newBlockEvent: multiprocessing.Event stopEvent: multiprocessing.Event @@ -203,13 +203,13 @@ class SolverBase(multiprocessing.Process): check_block: multiprocessing.Lock limit: int - def __init__(self, proc_num, num_proc, update_interval, best_queue, time_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit): + def __init__(self, proc_num, num_proc, update_interval, best_queue, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit): multiprocessing.Process.__init__(self) self.proc_num = proc_num self.num_proc = num_proc self.update_interval = update_interval self.best_queue = best_queue - self.time_queue = time_queue + self.finished_queue = finished_queue self.solution_queue = solution_queue self.newBlockEvent = multiprocessing.Event() self.newBlockEvent.clear() @@ -243,13 +243,13 @@ def run(self): self.newBlockEvent.clear() # Do a block of nonces - solution, time = solve_for_nonce_block(self, nonce_start, nonce_end, block_bytes, block_difficulty, self.limit, block_number) + solution = solve_for_nonce_block(self, nonce_start, nonce_end, block_bytes, block_difficulty, self.limit, block_number) if solution is not None: self.solution_queue.put(solution) try: # Send time - self.time_queue.put_nowait(time) + self.finished_queue.put_nowait(self.proc_num) except Full: pass @@ -261,8 +261,8 @@ class CUDASolver(SolverBase): dev_id: int TPB: int - def __init__(self, proc_num, num_proc, update_interval, time_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit, dev_id: int, TPB: int): - super().__init__(proc_num, num_proc, update_interval, None, time_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit) + def __init__(self, proc_num, num_proc, update_interval, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit, dev_id: int, TPB: int): + super().__init__(proc_num, num_proc, update_interval, None, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit) self.dev_id = dev_id self.TPB = TPB @@ -284,13 +284,14 @@ def run(self): self.newBlockEvent.clear() # Do a block of nonces - solution, time = solve_for_nonce_block_cuda(self, nonce_start, self.update_interval, block_bytes, block_difficulty, self.limit, block_number, self.dev_id, self.TPB) + solution = solve_for_nonce_block_cuda(self, nonce_start, self.update_interval, block_bytes, block_difficulty, self.limit, block_number, self.dev_id, self.TPB) if solution is not None: self.solution_queue.put(solution) - + try: - # Send time - self.time_queue.put_nowait(time) + # Signal that a nonce_block was finished using queue + # send our proc_num + self.finished_queue.put(self.proc_num) except Full: pass @@ -299,9 +300,8 @@ def run(self): nonce_start = nonce_start % nonce_limit -def solve_for_nonce_block_cuda(solver: CUDASolver, nonce_start: int, update_interval: int, block_bytes: bytes, difficulty: int, limit: int, block_number: int, dev_id: int, TPB: int) -> Tuple[Optional[POWSolution], int]: - start = time.time() - +def solve_for_nonce_block_cuda(solver: CUDASolver, nonce_start: int, update_interval: int, block_bytes: bytes, difficulty: int, limit: int, block_number: int, dev_id: int, TPB: int) -> Optional[POWSolution]: + """Tries to solve the POW on a CUDA device for a block of nonces (nonce_start, nonce_start + update_interval * TPB""" solution, seal = solve_cuda(nonce_start, update_interval, TPB, @@ -312,21 +312,16 @@ def solve_for_nonce_block_cuda(solver: CUDASolver, nonce_start: int, update_inte dev_id) if (solution != -1): - # Check if solution is valid - # Attempt to reset CUDA device - #reset_cuda() - - #print(f"{solver.proc_num} on cuda:{solver.dev_id} found a solution: {solution}, {block_number}, {str(block_bytes)}, {str(seal)}, {difficulty}") - # Found a solution, save it. - return POWSolution(solution, block_number, difficulty, seal), time.time() - start + # Check if solution is valid (i.e. not -1) + return POWSolution(solution, block_number, difficulty, seal) - return None, time.time() - start + return None -def solve_for_nonce_block(solver: Solver, nonce_start: int, nonce_end: int, block_bytes: bytes, difficulty: int, limit: int, block_number: int) -> Tuple[Optional[POWSolution], int]: +def solve_for_nonce_block(solver: Solver, nonce_start: int, nonce_end: int, block_bytes: bytes, difficulty: int, limit: int, block_number: int) -> Optional[POWSolution]: + """Tries to solve the POW for a block of nonces (nonce_start, nonce_end)""" best_local = float('inf') best_seal_local = [0]*32 - start = time.time() for nonce in range(nonce_start, nonce_end): # Create seal. nonce_bytes = binascii.hexlify(nonce.to_bytes(8, 'little')) @@ -340,7 +335,7 @@ def solve_for_nonce_block(solver: Solver, nonce_start: int, nonce_end: int, bloc product = seal_number * difficulty if product < limit: # Found a solution, save it. - return POWSolution(nonce, block_number, difficulty, seal), time.time() - start + return POWSolution(nonce, block_number, difficulty, seal) if (product - limit) < best_local: best_local = product - limit @@ -348,7 +343,7 @@ def solve_for_nonce_block(solver: Solver, nonce_start: int, nonce_end: int, bloc # Send best solution to best queue. solver.best_queue.put((best_local, best_seal_local)) - return None, time.time() - start + return None def registration_diff_unpack(packed_diff: multiprocessing.Array) -> int: @@ -361,6 +356,9 @@ def registration_diff_pack(diff: int, packed_diff: multiprocessing.Array): packed_diff[0] = diff >> 32 packed_diff[1] = diff & 0xFFFFFFFF # low 32 bits +def calculate_hash_rate() -> int: + pass + def update_curr_block(curr_diff: multiprocessing.Array, curr_block: multiprocessing.Array, curr_block_num: multiprocessing.Value, block_number: int, block_bytes: bytes, diff: int, lock: multiprocessing.Lock): with lock: @@ -421,11 +419,11 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = stopEvent.clear() best_queue = multiprocessing.Queue() solution_queue = multiprocessing.Queue() - time_queue = multiprocessing.Queue() + finished_queue = multiprocessing.Queue() check_block = multiprocessing.Lock() # Start consumers - solvers = [ Solver(i, num_processes, update_interval, best_queue, time_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit) + solvers = [ Solver(i, num_processes, update_interval, best_queue, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit) for i in range(num_processes) ] # Get first block @@ -449,7 +447,15 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = start_time = time.time() solution = None best_seal = None - itrs_per_sec = 0 + + hash_rate = 0 # EWMA hash_rate (H/s) + + n = 5 # number of samples to keep + alpha_ = 0.70 # EWMA alpha for hash_rate + + hash_rates = [0] * n # The last n true hash_rates + weights = [alpha_ ** i for i in range(n)] # weights decay by alpha + while not wallet.is_registered(subtensor): # Wait until a solver finds a solution try: @@ -475,22 +481,32 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = # Set new block events for each solver for worker in solvers: worker.newBlockEvent.set() - - # Get times for each solver - time_total = 0 + + # find hash_rate num_time = 0 - - for _ in solvers: + for _ in range(len(solvers)*2): try: - time_total += time_queue.get_nowait() + proc_num = finished_queue.get(timeout=0.1) num_time += 1 + except Empty: - break + # no more times + continue + + time_now = time.time() # get current time + time_since_last = time_now - time_last # get time since last work block(s) + if num_time > 0 and time_since_last > 0.0: + # create EWMA of the hash_rate to make measure more robust + + hash_rate_ = (num_time * update_interval) / time_since_last + hash_rates.append(hash_rate_) + hash_rates.pop(0) # remove the 0th data point + hash_rate = sum([hash_rates[i]*weights[i] for i in range(n)])/(sum(weights)) + + # update time last to now + time_last = time_now - # Calculate average time per solver for the update_interval - if num_time > 0: - time_avg = time_total / num_time - itrs_per_sec = update_interval*num_processes / time_avg + time_since = time_now - start_time # get best solution from each solver using the best_queue for _ in solvers: @@ -504,9 +520,9 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = break message = f"""Solving - time spent: {time.time() - start_time} + time spent: {time_since} Difficulty: [bold white]{millify(difficulty)}[/bold white] - Iters: [bold white]{get_human_readable(int(itrs_per_sec), 'H')}/s[/bold white] + Iters: [bold white]{get_human_readable(int(hash_rate), 'H')}/s[/bold white] Block: [bold white]{block_number}[/bold white] Block_hash: [bold white]{block_hash.encode('utf-8')}[/bold white] Best: [bold white]{binascii.hexlify(bytes(best_seal) if best_seal else bytes(0))}[/bold white]""" @@ -565,7 +581,7 @@ def __exit__(self, *args): multiprocessing.set_start_method(self._old_start_method, force=True) -def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'bittensor.Wallet', update_interval: int = 50_000, TPB: int = 512, dev_id: Union[List[int], int] = 0, use_kernel_launch_optimization: bool = False ) -> Optional[POWSolution]: +def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'bittensor.Wallet', update_interval: int = 50_000, TPB: int = 512, dev_id: Union[List[int], int] = 0 ) -> Optional[POWSolution]: """ Solves the registration fast using CUDA Args: @@ -616,15 +632,17 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu stopEvent = multiprocessing.Event() stopEvent.clear() solution_queue = multiprocessing.Queue() - time_queue = multiprocessing.Queue() + finished_queue = multiprocessing.Queue() check_block = multiprocessing.Lock() - # Start consumers + # Start workers + ## Create a worker per CUDA device num_processes = len(dev_id) - ## Create one consumer per GPU - solvers = [ CUDASolver(i, num_processes, update_interval, time_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit, dev_id[i], TPB) + + solvers = [ CUDASolver(i, num_processes, update_interval, finished_queue, solution_queue, stopEvent, curr_block, curr_block_num, curr_diff, check_block, limit, dev_id[i], TPB) for i in range(num_processes) ] + # Get first block block_number = subtensor.get_current_block() difficulty = subtensor.difficulty @@ -684,13 +702,14 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu num_time = 0 # Get times for each solver - for _ in solvers: + for _ in range(len(solvers)*2): try: - _ = time_queue.get_nowait() + proc_num = finished_queue.get(timeout=0.1) num_time += 1 - + except Empty: - break + # no more times + continue time_now = time.time() # get current time time_since_last = time_now - time_last # get time since last work block(s) From 9ba253fafa8f2f76ae0b71e38c95624e8d646da0 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Tue, 11 Oct 2022 18:48:16 -0400 Subject: [PATCH 17/23] move constants to function params --- bittensor/utils/__init__.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 6a5b825cf3..4fde6c6e88 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -374,7 +374,7 @@ def get_cpu_count(): # OSX does not have sched_getaffinity return os.cpu_count() -def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = None, update_interval: Optional[int] = None ) -> Optional[POWSolution]: +def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = None, update_interval: Optional[int] = None, n_samples: int = 5, alpha_: float = 0.70 ) -> Optional[POWSolution]: """ Solves the POW for registration using multiprocessing. Args: @@ -386,6 +386,12 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = Number of processes to use. update_interval: int Number of nonces to solve before updating block information. + n_samples: int + The number of samples of the hash_rate to keep for the EWMA + alpha_: float + The alpha for the EWMA for the hash_rate calculation + + Note: The hash rate is calculated as an exponentially weighted moving average in order to make the measure more robust. Note: - We can also modify the update interval to do smaller blocks of work, while still updating the block information after a different number of nonces, @@ -450,9 +456,6 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = hash_rate = 0 # EWMA hash_rate (H/s) - n = 5 # number of samples to keep - alpha_ = 0.70 # EWMA alpha for hash_rate - hash_rates = [0] * n # The last n true hash_rates weights = [alpha_ ** i for i in range(n)] # weights decay by alpha @@ -581,7 +584,7 @@ def __exit__(self, *args): multiprocessing.set_start_method(self._old_start_method, force=True) -def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'bittensor.Wallet', update_interval: int = 50_000, TPB: int = 512, dev_id: Union[List[int], int] = 0 ) -> Optional[POWSolution]: +def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'bittensor.Wallet', update_interval: int = 50_000, TPB: int = 512, dev_id: Union[List[int], int] = 0, n: int = 5, alpha_: float = 0.70 ) -> Optional[POWSolution]: """ Solves the registration fast using CUDA Args: @@ -595,6 +598,12 @@ def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'b The number of threads per block. CUDA param that should match the GPU capability dev_id: Union[List[int], int] The CUDA device IDs to execute the registration on, either a single device or a list of devices + n_samples: int + The number of samples of the hash_rate to keep for the EWMA + alpha_: float + The alpha for the EWMA for the hash_rate calculation + + Note: The hash rate is calculated as an exponentially weighted moving average in order to make the measure more robust. """ if isinstance(dev_id, int): dev_id = [dev_id] @@ -667,9 +676,6 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu solution = None hash_rate = 0 # EWMA hash_rate (H/s) - n = 5 # number of samples to keep - alpha_ = 0.70 # EWMA alpha for hash_rate - hash_rates = [0] * n # The last n true hash_rates weights = [alpha_ ** i for i in range(n)] # weights decay by alpha From c983aab39ba16aecd41b98ba30a9f0600b630e9c Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 12 Oct 2022 11:07:04 -0400 Subject: [PATCH 18/23] fix name of n --- bittensor/utils/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 4fde6c6e88..e7d1ea0abe 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -456,8 +456,8 @@ def solve_for_difficulty_fast( subtensor, wallet, num_processes: Optional[int] = hash_rate = 0 # EWMA hash_rate (H/s) - hash_rates = [0] * n # The last n true hash_rates - weights = [alpha_ ** i for i in range(n)] # weights decay by alpha + hash_rates = [0] * n_samples # The last n true hash_rates + weights = [alpha_ ** i for i in range(n_samples)] # weights decay by alpha while not wallet.is_registered(subtensor): # Wait until a solver finds a solution @@ -584,7 +584,7 @@ def __exit__(self, *args): multiprocessing.set_start_method(self._old_start_method, force=True) -def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'bittensor.Wallet', update_interval: int = 50_000, TPB: int = 512, dev_id: Union[List[int], int] = 0, n: int = 5, alpha_: float = 0.70 ) -> Optional[POWSolution]: +def solve_for_difficulty_fast_cuda( subtensor: 'bittensor.Subtensor', wallet: 'bittensor.Wallet', update_interval: int = 50_000, TPB: int = 512, dev_id: Union[List[int], int] = 0, n_samples: int = 5, alpha_: float = 0.70 ) -> Optional[POWSolution]: """ Solves the registration fast using CUDA Args: @@ -676,8 +676,8 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu solution = None hash_rate = 0 # EWMA hash_rate (H/s) - hash_rates = [0] * n # The last n true hash_rates - weights = [alpha_ ** i for i in range(n)] # weights decay by alpha + hash_rates = [0] * n_samples # The last n true hash_rates + weights = [alpha_ ** i for i in range(n_samples)] # weights decay by alpha while not wallet.is_registered(subtensor): # Wait until a solver finds a solution From 945b76624020f3a2b553110c29db955215e867d4 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 12 Oct 2022 11:46:09 -0400 Subject: [PATCH 19/23] fix verbose log --- bittensor/utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 1e390ba2ba..7ae9425f5e 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -406,8 +406,8 @@ def get_status_message(cls, stats: RegistrationStatistics, verbose: bool = False time spent: {timedelta(seconds=stats.time_spent)}""" + \ (f""" time spent total: {stats.time_spent_total:.2f} s - time spent average: {timedelta(seconds=stats.time_average)} - """ if verbose else "") + f""" + time spent average: {timedelta(seconds=stats.time_average)}""" if verbose else "") + \ + f""" Difficulty: [bold white]{millify(stats.difficulty)}[/bold white] Iters: [bold white]{get_human_readable(int(stats.hash_rate), 'H')}/s[/bold white] Block: [bold white]{stats.block_number}[/bold white] From bf9794332222e1e312a358a04c31070b0741f22c Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 12 Oct 2022 11:47:12 -0400 Subject: [PATCH 20/23] allow --output_in_place --- bittensor/_subtensor/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/_subtensor/__init__.py b/bittensor/_subtensor/__init__.py index eab11fd1cc..11565fdbd6 100644 --- a/bittensor/_subtensor/__init__.py +++ b/bittensor/_subtensor/__init__.py @@ -192,7 +192,7 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): # registration args. Used for register and re-register and anything that calls register. parser.add_argument('--' + prefix_str + 'subtensor.register.num_processes', '-n', dest=prefix_str + 'subtensor.register.num_processes', help="Number of processors to use for registration", type=int, default=bittensor.defaults.subtensor.register.num_processes) parser.add_argument('--' + prefix_str + 'subtensor.register.update_interval', '--' + prefix_str + 'subtensor.register.cuda.update_interval', '--' + prefix_str + 'cuda.update_interval', '-u', help="The number of nonces to process before checking for next block during registration", type=int, default=bittensor.defaults.subtensor.register.update_interval) - parser.add_argument('--' + prefix_str + 'subtensor.register.output_in_place', help="Whether to ouput the registration statistics in-place. Set flag to enable.", action='store_true', required=False, default=bittensor.defaults.subtensor.register.output_in_place) + parser.add_argument('--' + prefix_str + 'subtensor.register.output_in_place', '--' + prefix_str + 'output_in_place', help="Whether to ouput the registration statistics in-place. Set flag to enable.", action='store_true', required=False, default=bittensor.defaults.subtensor.register.output_in_place) parser.add_argument('--' + prefix_str + 'subtensor.register.verbose', help="Whether to ouput the registration statistics verbosely.", action='store_true', required=False, default=bittensor.defaults.subtensor.register.verbose) ## Registration args for CUDA registration. From da5d1b1c10d5b435b38aa088fcbb898c2aa1fbac Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 12 Oct 2022 11:49:59 -0400 Subject: [PATCH 21/23] fix n --- bittensor/utils/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/utils/__init__.py b/bittensor/utils/__init__.py index 7ae9425f5e..9526ad41fc 100644 --- a/bittensor/utils/__init__.py +++ b/bittensor/utils/__init__.py @@ -796,7 +796,7 @@ def update_curr_block(block_number: int, block_bytes: bytes, diff: int, lock: mu hash_rate_ = (num_time * TPB * update_interval) / time_since_last hash_rates.append(hash_rate_) hash_rates.pop(0) # remove the 0th data point - curr_stats.hash_rate = sum([hash_rates[i]*weights[i] for i in range(n)])/(sum(weights)) + curr_stats.hash_rate = sum([hash_rates[i]*weights[i] for i in range(n_samples)])/(sum(weights)) # update time last to now time_last = time_now From 304adbb2b42d6318ff6fb42b2a11d58053b77ef0 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 12 Oct 2022 11:51:13 -0400 Subject: [PATCH 22/23] change to --no_ouput_in_place --- bittensor/_subtensor/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bittensor/_subtensor/__init__.py b/bittensor/_subtensor/__init__.py index 11565fdbd6..cd60b673ac 100644 --- a/bittensor/_subtensor/__init__.py +++ b/bittensor/_subtensor/__init__.py @@ -192,7 +192,7 @@ def add_args(cls, parser: argparse.ArgumentParser, prefix: str = None ): # registration args. Used for register and re-register and anything that calls register. parser.add_argument('--' + prefix_str + 'subtensor.register.num_processes', '-n', dest=prefix_str + 'subtensor.register.num_processes', help="Number of processors to use for registration", type=int, default=bittensor.defaults.subtensor.register.num_processes) parser.add_argument('--' + prefix_str + 'subtensor.register.update_interval', '--' + prefix_str + 'subtensor.register.cuda.update_interval', '--' + prefix_str + 'cuda.update_interval', '-u', help="The number of nonces to process before checking for next block during registration", type=int, default=bittensor.defaults.subtensor.register.update_interval) - parser.add_argument('--' + prefix_str + 'subtensor.register.output_in_place', '--' + prefix_str + 'output_in_place', help="Whether to ouput the registration statistics in-place. Set flag to enable.", action='store_true', required=False, default=bittensor.defaults.subtensor.register.output_in_place) + parser.add_argument('--' + prefix_str + 'subtensor.register.no_output_in_place', '--' + prefix_str + 'no_output_in_place', dest="subtensor.register.output_in_place", help="Whether to not ouput the registration statistics in-place. Set flag to disable output in-place.", action='store_false', required=False, default=bittensor.defaults.subtensor.register.output_in_place) parser.add_argument('--' + prefix_str + 'subtensor.register.verbose', help="Whether to ouput the registration statistics verbosely.", action='store_true', required=False, default=bittensor.defaults.subtensor.register.verbose) ## Registration args for CUDA registration. From 147e853b99f937fe3bceeee93c9dc1219b303928 Mon Sep 17 00:00:00 2001 From: Cameron Fairchild Date: Wed, 12 Oct 2022 11:56:53 -0400 Subject: [PATCH 23/23] fix test --- tests/unit_tests/bittensor_tests/utils/test_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/bittensor_tests/utils/test_utils.py b/tests/unit_tests/bittensor_tests/utils/test_utils.py index 669877d62e..030cdbfb83 100644 --- a/tests/unit_tests/bittensor_tests/utils/test_utils.py +++ b/tests/unit_tests/bittensor_tests/utils/test_utils.py @@ -415,13 +415,14 @@ class MockException(Exception): update_interval=update_interval, stopEvent=MagicMock(is_set=MagicMock(return_value=False)), newBlockEvent=MagicMock(is_set=MagicMock(return_value=False)), - time_queue=MagicMock(put_nowait=MagicMock()), - limit=10000 + finished_queue=MagicMock(put=MagicMock()), + limit=10000, + proc_num=0, ) with patch('bittensor.utils.solve_for_nonce_block_cuda', - side_effect=[(None, 10.0), MockException] # first call returns mocked no solution, second call raises exception + side_effect=[None, MockException] # first call returns mocked no solution, second call raises exception ) as mock_solve_for_nonce_block_cuda: # Should exit early