Repository: Naruno/Naruno (language: python)

Issue:
lib: Adding I/O performance analyzers



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
index 7ce7cdd9..8a150615 100644
--- a/.github/workflows/codecov.yml
+++ b/.github/workflows/codecov.yml
@@ -47,7 +47,8 @@ jobs:
     - name: Install dependencies
       run: |
         pip install -r requirements/api.txt
-        pip install -r requirements/gui.txt      
+        pip install -r requirements/gui.txt
+        pip install -r requirements/tests.txt     
         pip install pytest
         pip install coverage
     - name: Generate coverage report
diff --git a/decentra_network/lib/performance_analyzers/accounts.py b/decentra_network/lib/performance_analyzers/accounts.py
new file mode 100644
index 00000000..3c975105
--- /dev/null
+++ b/decentra_network/lib/performance_analyzers/accounts.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+import contextlib
+import hashlib
+import os
+import sys
+import time
+from cgitb import reset
+
+from speed_calculator import calculate
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
+
+from decentra_network.accounts.account import Account
+from decentra_network.accounts.get_accounts import GetAccounts
+from decentra_network.accounts.save_accounts import SaveAccounts
+from decentra_network.blockchain.block.block_main import Block
+from decentra_network.blockchain.block.blocks_hash import (GetBlockshash,
+                                                           GetBlockshash_part,
+                                                           SaveBlockshash,
+                                                           SaveBlockshash_part)
+from decentra_network.blockchain.block.get_block import GetBlock
+from decentra_network.blockchain.block.save_block import SaveBlock
+
+
+class Accounts_IO_Performance_Analyzer:
+    """
+    This class is used to analyze the performance of GetBlock
+    """
+
+    def __init__(self):
+        self.block = Block("test")
+
+        self.account = Account("test", 5000)
+
+        self.the_account_list = []
+
+        for i in range(self.block.max_tx_number):
+            self.the_account_list.append(self.account)
+
+    def analyze(self) -> float:
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        result = (
+            calculate(self.save_operation)[0],
+            calculate(self.get_operation)[0],
+            os.path.getsize("db/Accounts_Performance_Analyzer_accounts.pf") /
+            1000000,
+        )
+
+        os.remove("db/Accounts_Performance_Analyzer_accounts.pf")
+
+        return result
+
+    def save_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        SaveAccounts(
+            self.the_account_list,
+            custom_TEMP_ACCOUNTS_PATH=
+            "db/Accounts_Performance_Analyzer_accounts.pf",
+        )
+
+    def get_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        the_accounts = GetAccounts(
+            "db/Accounts_Performance_Analyzer_accounts.pf")
diff --git a/decentra_network/lib/performance_analyzers/block.py b/decentra_network/lib/performance_analyzers/block.py
new file mode 100644
index 00000000..806d917d
--- /dev/null
+++ b/decentra_network/lib/performance_analyzers/block.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+import contextlib
+import hashlib
+import os
+import sys
+import time
+from cgitb import reset
+
+from speed_calculator import calculate
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
+
+from decentra_network.accounts.account import Account
+from decentra_network.accounts.get_accounts import GetAccounts
+from decentra_network.accounts.save_accounts import SaveAccounts
+from decentra_network.blockchain.block.block_main import Block
+from decentra_network.blockchain.block.blocks_hash import (GetBlockshash,
+                                                           GetBlockshash_part,
+                                                           SaveBlockshash,
+                                                           SaveBlockshash_part)
+from decentra_network.blockchain.block.get_block import GetBlock
+from decentra_network.blockchain.block.save_block import SaveBlock
+
+
+class Block_IO_Performance_Analyzer:
+    """
+    This class is used to analyze the performance of GetBlock
+    """
+
+    def __init__(self):
+        self.block = Block("test")
+        self.block.first_time = False
+
+        self.block.hash = hashlib.sha256("test".encode()).hexdigest()
+        self.block.round_2_starting_time = time.time()
+        self.block.validated_time = time.time()
+
+    def analyze(self) -> float:
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        result = (
+            calculate(self.save_operation)[0],
+            calculate(self.get_operation)[0],
+            os.path.getsize("db/Block_Performance_Analyzer_block.pf") /
+            1000000,
+        )
+
+        os.remove("db/Block_Performance_Analyzer_block.pf")
+
+        return result
+
+    def save_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+        SaveBlock(
+            self.block,
+            custom_TEMP_BLOCK_PATH="db/Block_Performance_Analyzer_block.pf",
+        )
+
+    def get_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        GetBlock("db/Block_Performance_Analyzer_block.pf")
diff --git a/decentra_network/lib/performance_analyzers/blockshash.py b/decentra_network/lib/performance_analyzers/blockshash.py
new file mode 100644
index 00000000..77123c60
--- /dev/null
+++ b/decentra_network/lib/performance_analyzers/blockshash.py
@@ -0,0 +1,74 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+import contextlib
+import hashlib
+import os
+import sys
+import time
+from cgitb import reset
+
+from speed_calculator import calculate
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
+
+from decentra_network.accounts.account import Account
+from decentra_network.accounts.get_accounts import GetAccounts
+from decentra_network.accounts.save_accounts import SaveAccounts
+from decentra_network.blockchain.block.block_main import Block
+from decentra_network.blockchain.block.blocks_hash import (GetBlockshash,
+                                                           GetBlockshash_part,
+                                                           SaveBlockshash,
+                                                           SaveBlockshash_part)
+from decentra_network.blockchain.block.get_block import GetBlock
+from decentra_network.blockchain.block.save_block import SaveBlock
+
+
+class Blockshash_IO_Performance_Analyzer:
+    """
+    This class is used to analyze the performance of GetBlock
+    """
+
+    def __init__(self):
+        self.block = Block("test")
+        the_hash = hashlib.sha256("test".encode()).hexdigest()
+        self.blocks_hash = [the_hash for i in range(self.block.part_amount)]
+        self.blocks_hash.append(self.block.previous_hash)
+
+    def analyze(self) -> float:
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        result = (
+            calculate(self.save_operation)[0],
+            calculate(self.get_operation)[0],
+            os.path.getsize("db/Blockshash_Performance_Analyzer_blockshash.pf")
+            / 1000000,
+        )
+
+        os.remove("db/Blockshash_Performance_Analyzer_blockshash.pf")
+
+        return result
+
+    def save_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        SaveBlockshash(
+            self.blocks_hash,
+            custom_TEMP_BLOCKSHASH_PATH=
+            "db/Blockshash_Performance_Analyzer_blockshash.pf",
+        )
+
+    def get_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        GetBlockshash(custom_TEMP_BLOCKSHASH_PATH=
+                      "db/Blockshash_Performance_Analyzer_blockshash.pf")
diff --git a/decentra_network/lib/performance_analyzers/blockshash_part.py b/decentra_network/lib/performance_analyzers/blockshash_part.py
new file mode 100644
index 00000000..fb25a4c5
--- /dev/null
+++ b/decentra_network/lib/performance_analyzers/blockshash_part.py
@@ -0,0 +1,85 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+import contextlib
+import hashlib
+import os
+import sys
+import time
+from cgitb import reset
+
+from speed_calculator import calculate
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
+
+from decentra_network.accounts.account import Account
+from decentra_network.accounts.get_accounts import GetAccounts
+from decentra_network.accounts.save_accounts import SaveAccounts
+from decentra_network.blockchain.block.block_main import Block
+from decentra_network.blockchain.block.blocks_hash import (GetBlockshash,
+                                                           GetBlockshash_part,
+                                                           SaveBlockshash,
+                                                           SaveBlockshash_part)
+from decentra_network.blockchain.block.get_block import GetBlock
+from decentra_network.blockchain.block.save_block import SaveBlock
+
+
+class Blockshash_part_IO_Performance_Analyzer:
+    """
+    This class is used to analyze the performance of GetBlock
+    """
+
+    def __init__(self):
+        self.block = Block("test")
+        the_hash = hashlib.sha256("test".encode()).hexdigest()
+
+        # calculate the seconds in a day
+        seconds_in_a_day = 60 * 60 * 24
+
+        # how many blocks in a day
+        blocks_in_a_day = seconds_in_a_day / self.block.block_time
+
+        # how many blocks in a year
+        blocks_in_a_year = blocks_in_a_day * 365
+
+        self.blocks_hash = [the_hash for i in range(int(blocks_in_a_year))]
+
+    def analyze(self) -> float:
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        result = (
+            calculate(self.save_operation)[0],
+            calculate(self.get_operation)[0],
+            os.path.getsize(
+                "db/Blockshash_part_Performance_Analyzer_blockshash.pf") /
+            1000000,
+        )
+
+        os.remove("db/Blockshash_part_Performance_Analyzer_blockshash.pf")
+
+        return result
+
+    def save_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        SaveBlockshash_part(
+            self.blocks_hash,
+            custom_TEMP_BLOCKSHASH_PART_PATH=
+            "db/Blockshash_part_Performance_Analyzer_blockshash.pf",
+        )
+
+    def get_operation(self):
+        """
+        This function is used to analyze the performance of GetBlock
+        """
+
+        GetBlockshash_part(
+            custom_TEMP_BLOCKSHASH_PART_PATH=
+            "db/Blockshash_part_Performance_Analyzer_blockshash.pf")
diff --git a/decentra_network/lib/performance_analyzers/heartbeat_db.py b/decentra_network/lib/performance_analyzers/heartbeat_db.py
new file mode 100644
index 00000000..5bae2463
--- /dev/null
+++ b/decentra_network/lib/performance_analyzers/heartbeat_db.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at https://mozilla.org/MPL/2.0/.
+import contextlib
+import hashlib
+import os
+import sys
+import time
+from cgitb import reset
+
+from speed_calculator import calculate
+
+sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
+
+from decentra_network.lib.performance_analyzers.accounts import \
+    Accounts_IO_Performance_Analyzer
+from decentra_network.lib.performance_analyzers.block import \
+    Block_IO_Performance_Analyzer
+from decentra_network.lib.performance_analyzers.blockshash import \
+    Blockshash_IO_Performance_Analyzer
+from decentra_network.lib.performance_analyzers.blockshash_part import \
+    Blockshash_part_IO_Performance_Analyzer
+
+
+def heartbeat_generic_db_analyzer():
+    the_block = Block_IO_Performance_Analyzer()
+    the_accounts = Accounts_IO_Performance_Analyzer()
+    the_blockshash = Blockshash_IO_Performance_Analyzer()
+    the_blockshash_part = Blockshash_part_IO_Performance_Analyzer()
+
+    the_block_analysis = the_block.analyze()
+    the_accounts_analysis = the_accounts.analyze()
+    the_blockshash_analysis = the_blockshash.analyze()
+    the_blockshash_part_analysis = the_blockshash_part.analyze()
+
+    return (
+        the_block_analysis[0] + the_accounts_analysis[0] +
+        the_blockshash_analysis[0] + the_blockshash_part_analysis[0],
+        the_block_analysis[1] + the_accounts_analysis[1] +
+        the_blockshash_analysis[1] + the_blockshash_part_analysis[1],
+    )


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 66c9dde9..ecf7fc65 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -84,6 +84,7 @@ jobs:
         pip install pytest
         pip install -r requirements/api.txt
         pip install -r requirements/gui.txt
+        pip install -r requirements/tests.txt
     - name: Test with pytest
       run: |
         pytest tests/unit_tests
@@ -119,6 +120,7 @@ jobs:
         pip install pytest
         pip install -r requirements/api.txt
         pip install -r requirements/gui.txt
+        pip install -r requirements/tests.txt
     - name: Test with pytest
       run: |
         pytest tests/unit_tests
@@ -153,6 +155,7 @@ jobs:
         pip install pytest
         pip install -r requirements/api.txt
         pip install -r requirements/gui.txt
+        pip install -r requirements/tests.txt
     - name: Test with pytest
       run: |
         pytest tests/unit_tests
diff --git a/requirements/tests.txt b/requirements/tests.txt
index f7e41678..13605b43 100644
--- a/requirements/tests.txt
+++ b/requirements/tests.txt
@@ -1,2 +1,3 @@
 requests==2.28.0
 pytest==7.1.2
+speed_calculator==0.4.1
diff --git a/tests/unit_tests/test_consensus.py b/tests/unit_tests/test_consensus.py
index 0b323a7b..e3bc26dd 100644
--- a/tests/unit_tests/test_consensus.py
+++ b/tests/unit_tests/test_consensus.py
@@ -12,6 +12,8 @@
 import time
 import unittest
 
+from speed_calculator import calculate
+
 from decentra_network.accounts.account import Account
 from decentra_network.accounts.get_accounts import GetAccounts
 from decentra_network.accounts.save_accounts import SaveAccounts
@@ -1924,7 +1926,8 @@ def test_consensus_trigger_ongoing(self):
         block.round_2_starting_time = time.time()
         block.round_2_time = 2
         time.sleep(4)
-        result = consensus_trigger(
+        result = calculate(
+            consensus_trigger,
             block,
             CandidateBlock,
             unl_nodes,
@@ -1936,7 +1939,8 @@ def test_consensus_trigger_ongoing(self):
             custom_TEMP_BLOCKSHASH_PART_PATH=self.
             custom_TEMP_BLOCKSHASH_PART_PATH1,
         )
-        self.assertTrue(result)
+        self.assertTrue(result[1])
+        self.assertLess(result[0], 0.5)
         self.assertEqual(block.validated, True)
         self.assertEqual(block.round_2, True)
         self.assertNotEqual(old_block.validated_time, block.validated_time)
@@ -1985,7 +1989,8 @@ def test_consensus_trigger_finished(self):
         )
         time.sleep(1)
 
-        result = consensus_trigger(
+        result = calculate(
+            consensus_trigger,
             block,
             custom_TEMP_BLOCK_PATH=custom_TEMP_BLOCK_PATH,
             custom_BLOCKS_PATH=custom_BLOCKS_PATH,
@@ -1993,7 +1998,8 @@ def test_consensus_trigger_finished(self):
             custom_TEMP_BLOCKSHASH_PATH=custom_TEMP_BLOCKSHASH_PATH,
             custom_TEMP_BLOCKSHASH_PART_PATH=custom_TEMP_BLOCKSHASH_PART_PATH,
         )
-        self.assertTrue(result)
+        self.assertTrue(result[1])
+        self.assertLess(result[0], 0.5)
 
         result_2 = GetBlockstoBlockchainDB(
             sequance_number=0,
diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py
index 2541af79..5373a8b6 100644
--- a/tests/unit_tests/test_lib.py
+++ b/tests/unit_tests/test_lib.py
@@ -29,6 +29,8 @@
                                              printcentertext, question_maker,
                                              quit_menu_maker,
                                              starting_text_centered)
+from decentra_network.lib.performance_analyzers.heartbeat_db import \
+    heartbeat_generic_db_analyzer
 from decentra_network.lib.perpetualtimer import perpetualTimer
 from decentra_network.lib.safety import safety_check
 from decentra_network.lib.settings_system import (d_mode_settings,
@@ -612,12 +614,16 @@ def test_perpetualTimer(self):
         )
         time.sleep(3.5)
         self.assertTrue(os.path.exists("test_perpetual_time_test.txt"))
-        #open and read the file after the 2.5 seconds
+        # open and read the file after the 2.5 seconds
         with open("test_perpetual_time_test.txt", "r") as f:
             content = f.read()
         self.assertEqual(len(content), 33)
         the_timer.cancel()
         os.remove("test_perpetual_time_test.txt")
 
+    def test_heartbeat_generic_db_analyzer(self):
+        result = heartbeat_generic_db_analyzer()
+        self.assertLessEqual(result[0] + result[1], 10)
+
 
 unittest.main(exit=False)