Skip to content
This repository has been archived by the owner on Dec 15, 2023. It is now read-only.

Speed up deepcopy #293

Merged
merged 11 commits into from
Oct 5, 2022
Merged

Conversation

Solpatium
Copy link
Contributor

@Solpatium Solpatium commented Sep 29, 2022

Explanation

I've found that performing a deepcopy of ContractClass takes a lot of time and it seems that it is not mutated, therefore deepcopies of it is are not needed.

Results

I created a script that deploys a mintable ERC20 (mint function is not protected), invokes a function 50 times and performs a call 50 times.

Results before the change:

DEVNET DEPLOY 5.658147791999999
DEVNET INVOKE 34.687730957999996
DEVNET CALL 28.082026750000004
DEVNET TOTAL 69.16069075
LOCAL DEPLOY 6.191669750000003
LOCAL INVOKE 1.6923722920000017
LOCAL CALL 8.747897417000004
LOCAL TOTAL 16.632016457999995

Results after the change:

DEVNET DEPLOY 8.195612
DEVNET INVOKE 12.908604707999999
DEVNET CALL 1.2534642500000004
DEVNET TOTAL 22.378305209
LOCAL DEPLOY 6.125027791999997
LOCAL INVOKE 1.750453709000002
LOCAL CALL 8.408475457999998
LOCAL TOTAL 16.284028458999998
Test script (requires starknet.py and openzeppelin contracts)
import asyncio
import os
from contextlib import contextmanager

from starknet_py.contract import Contract
from starknet_py.net import AccountClient
from starknet_py.net.gateway_client import GatewayClient
from timeit import default_timer as timer

# Local network
from starknet_py.net.models import StarknetChainId

from starkware.starknet.testing.starknet import Starknet

# The path to the contract source code.
CAIRO_PATH = os.path.join(
  os.path.dirname(__file__), "cairo-contracts/src"
)
CONTRACT_FILE = os.path.join(
  CAIRO_PATH, "openzeppelin/token/erc20/presets/ERC20Mintable.cairo"
)

NONCE = 0
INVOCATIONS_COUNT = 50

@contextmanager
def measure(name):
  # Code to acquire resource, e.g.:
  start = timer()
  try:
      yield
  finally:
      end = timer()
      print(name, end - start)


# We don't want to fetch nonce before every request
class Account(AccountClient):

  def send_transaction(self, *args, **kwargs):
      global NONCE
      NONCE += 1
      return super(Account, self).send_transaction(*args, **kwargs)

  async def _get_nonce(self) -> int:
      return NONCE


async def test_remote():
  client = GatewayClient("http://localhost:5050")
  account = await Account.create_account(client, chain=StarknetChainId.TESTNET)
  account = Account(address=account.address, client=client, signer=account.signer, chain=StarknetChainId.TESTNET)

  with measure("DEVNET TOTAL"):
      with measure("DEVNET DEPLOY"):
          tx = await Contract.deploy(
              account,
              compilation_source=[CONTRACT_FILE],
              constructor_args=[1, 2, 3, 4, 5, 6],
              search_paths=[CAIRO_PATH],
          )

      contract = tx.deployed_contract
      with measure("DEVNET INVOKE"):
          for _ in range(INVOCATIONS_COUNT):
              await contract.functions["mint"].invoke(account.address, 1, max_fee=0)

      with measure("DEVNET CALL"):
          for _ in range(INVOCATIONS_COUNT):
              await contract.functions["balanceOf"].call(account.address)

      result = await contract.functions["balanceOf"].call(account.address)
      print("DEVNET RESULT", result)


async def test_local():
  # Create a new Starknet class that simulates the StarkNet
  # system.
  starknet = await Starknet.empty()

  with measure("LOCAL TOTAL"):
      with measure("LOCAL DEPLOY"):
          contract = await starknet.deploy(
              source=CONTRACT_FILE,
              cairo_path=[CAIRO_PATH],
              constructor_calldata=list(range(7))
          )

      with measure("LOCAL INVOKE"):
          for _ in range(INVOCATIONS_COUNT):
              await contract.mint(to=10, amount=(1, 0)).execute()

      with measure("LOCAL CALL"):
          for _ in range(INVOCATIONS_COUNT):
              await contract.balanceOf(10).call()

  exc_info = await contract.balanceOf(10).call()
  print("LOCAL RESULT", exc_info.result)


asyncio.run(test_remote())
asyncio.run(test_local())

Usage related changes

This should only improve performance, so it shouldn't affect users.

Related to #208 and #52.

Development related changes

Updated README to inform mac users how to pass test_postman.

Checklist:

  • Applied formatting - ./scripts/format.sh
  • No linter errors - ./scripts/lint.sh
  • Performed code self-review
  • Rebased to the last commit of the target branch (or merged it into my branch)
  • Documented the changes
  • Linked the issues which this PR resolves
  • Updated the tests NA
  • All tests are passing

@Solpatium Solpatium changed the title Feat/no state deepcopy Speed up deepcopy Oct 3, 2022
@Solpatium
Copy link
Contributor Author

Solpatium commented Oct 3, 2022

e2e tests in starknet.py on github actions run in 412.49s with this change, was 518.30s.

@mikiw
Copy link
Contributor

mikiw commented Oct 5, 2022

Hi @Solpatium! Is this PR ready for review?

@mikiw
Copy link
Contributor

mikiw commented Oct 5, 2022

@FabijanC maybe we should include a similar test as this test script in our code base as a load test to track performance for future versions?

@Solpatium
Copy link
Contributor Author

This is a temporary solution to increase performance in a safe way. After completing #298 and #297 the code added here should no longer be needed.

@Solpatium Solpatium marked this pull request as ready for review October 5, 2022 10:18
Copy link
Contributor

@ivpavici ivpavici left a comment

Choose a reason for hiding this comment

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

old_test.py is probably a leftover?

Copy link
Contributor

@mikiw mikiw left a comment

Choose a reason for hiding this comment

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

there is an empty file old_test.py, probably added by accident

@Solpatium
Copy link
Contributor Author

Sorry, removed the leftover :)

@Solpatium Solpatium requested a review from mikiw October 5, 2022 11:16
@mikiw mikiw merged commit 38c3529 into 0xSpaceShard:master Oct 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Profiling report - performance improvement investigations Performance enhancements while running tests
3 participants