Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add convenient profiling #2493

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ MANIFEST-*
OPTIONS-*
CURRENT
LOCK
*.out
36 changes: 36 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,39 @@ pathfinder: juno-cached ## Run a node to sync from pathfinder feedernode. P2P us

test-fuzz: ## Run fuzzing script
./scripts/fuzz_all.sh

block-with-transaction-profile: juno-cached ## CPU profile getBlockWithTxs
./scripts/profile_juno.sh profile 60 scripts/payload/getBlockWithTxs_0.json "" getBlockWithTxs_profile_0.out ""
go tool pprof -http=:3000 getBlockWithTxs_profile_0.out

block-with-transaction-heap: juno-cached ## Heap profile getBlockWithTxs
./scripts/profile_juno.sh heap 60 scripts/payload/getBlockWithTxs_0.json "" getBlockWithTxs_heap_0.out ""
go tool pprof -http=:3001 getBlockWithTxs_heap_0.out

block-with-transaction-block: juno-cached ## Goroutine blocking profile getBlockWithTxs
./scripts/profile_juno.sh block 60 scripts/payload/getBlockWithTxs_0.json "" getBlockWithTxs_block_0.out ""
go tool pprof -http=:3002 getBlockWithTxs_block_0.out

estimate-fee-profile: juno-cached ## CPU profile estimateFee
./scripts/profile_juno.sh profile 60 scripts/payload/estimateFee.json sepolia-integration estimateFee_profile.out ./p2p-dbs/sepolia-integration_node
go tool pprof -http=:3003 estimateFee_profile.out

estimate-fee-heap: juno-cached ## Heap profile estimateFee
./scripts/profile_juno.sh heap 60 scripts/payload/estimateFee.json sepolia-integration estimateFee_heap.out ./p2p-dbs/sepolia-integration_node
go tool pprof -http=:3004 estimateFee_heap.out

estimate-fee-block: juno-cached ## Goroutine blocking profile estimateFee
./scripts/profile_juno.sh block 60 scripts/payload/estimateFee.json sepolia-integration estimateFee_block.out ./p2p-dbs/sepolia-integration_node
go tool pprof -http=:3005 estimateFee_block.out

sync-profile: juno-cached ## Goroutine blocking profile estimateFee
./scripts/profile_juno.sh profile 60 none sepolia sync-profile.out ""
go tool pprof -http=:3006 sync-profile.out

sync-heap: juno-cached ## Goroutine blocking profile estimateFee
./scripts/profile_juno.sh heap 60 none sepolia sync-heap.out ""
go tool pprof -http=:3007 sync-heap.out

sync-block: juno-cached ## Goroutine blocking profile estimateFee
./scripts/profile_juno.sh block 60 none sepolia sync-block.out ""
go tool pprof -http=:3008 sync-block.out
83 changes: 83 additions & 0 deletions scripts/payload/estimateFee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"jsonrpc": "2.0",
"id": 1,
"method": "starknet_estimateFee",
"params": {
"request": [
{
"transaction_hash": "0xf9e2327f6edb64a41f54088ca88bcf7f2331efeb0343b668a69b469986d8b8",
"version": "0x3",
"signature": [],
"nonce": "0x2",
"nonce_data_availability_mode": "L1",
"fee_data_availability_mode": "L1",
"resource_bounds": {
"L1_GAS": {
"max_amount": "0x0",
"max_price_per_unit": "0x7755370971607"
},
"L2_GAS": {
"max_amount": "0xf4240",
"max_price_per_unit": "0x1aae13a2"
},
"L1_DATA_GAS": {
"max_amount": "0x7d0",
"max_price_per_unit": "0x6070"
}
},
"tip": "0x0",
"paymaster_data": [],
"sender_address": "0x3ad02acd6e492fcccf20d22f66a7f759623ffd243f9b5c71d6e72978d7cfa5c",
"calldata": [
"0x1",
"0x57db596276973cab6285927b2c743bca4f420d6ea4748ebe5038dc83ffa8c08",
"0x14a9a610b6c242b01e01b59a4474f46f0213139737c69cab5d3e95f1cbc00f0",
"0x1",
"0xa"
],
"account_deployment_data": [],
"type": "INVOKE_FUNCTION"
},
{
"transaction_hash": "0xf9e2327f6edb64a41f54088ca88bcf7f2331efeb0343b668a69b469986d8b8",
"version": "0x3",
"signature": [],
"nonce": "0x3",
"nonce_data_availability_mode": "L1",
"fee_data_availability_mode": "L1",
"resource_bounds": {
"L1_GAS": {
"max_amount": "0x0",
"max_price_per_unit": "0x7755370971607"
},
"L2_GAS": {
"max_amount": "0xbba0",
"max_price_per_unit": "0x1aae13a2"
},
"L1_DATA_GAS": {
"max_amount": "0x7d0",
"max_price_per_unit": "0x6070"
}
},
"tip": "0x0",
"paymaster_data": [],
"sender_address": "0x3ad02acd6e492fcccf20d22f66a7f759623ffd243f9b5c71d6e72978d7cfa5c",
"calldata": [
"0x1",
"0x57db596276973cab6285927b2c743bca4f420d6ea4748ebe5038dc83ffa8c08",
"0x14a9a610b6c242b01e01b59a4474f46f0213139737c69cab5d3e95f1cbc00f0",
"0x1",
"0xa"
],
"account_deployment_data": [],
"type": "INVOKE_FUNCTION"
}
],
"block_id": {
"block_number": 65100
},
"simulation_flags": [
"SKIP_VALIDATE"
]
}
}
10 changes: 10 additions & 0 deletions scripts/payload/getBlockWithTxs_0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"jsonrpc": "2.0",
"method": "starknet_getBlockWithTxs",
"params": {
"block_id": {
"block_number": 0
}
},
"id": 1
}
123 changes: 123 additions & 0 deletions scripts/profile_juno.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/bin/bash

JUNO_PORT=6060 # Juno RPC port
PPROF_PORT=6062 # pprof profiling port

# Default values
DEFAULT_PROFILE="profile"
DEFAULT_PROFILE_DURATION=30
DEFAULT_REQUEST_FILE="scripts/payload/getBlockWithTxs_0.json"
DEFAULT_NETWORK="sepolia"
DEFAULT_OUTPUT_FILE="trace.out"
DEFAULT_DB_PATH="./p2p-dbs/feedernode"

# Read values from command-line arguments or use defaults
PROFILE=${1:-$DEFAULT_PROFILE}
PROFILE_DURATION=${2:-$DEFAULT_PROFILE_DURATION}
REQUEST_FILE=${3:-$DEFAULT_REQUEST_FILE}
NETWORK=${4:-$DEFAULT_NETWORK}
OUTPUT_FILE=${5:-$DEFAULT_OUTPUT_FILE}
DB_PATH=${6:-$DEFAULT_DB_PATH}

# Configurations
JUNO_BINARY="./build/juno"
JUNO_ARGS="--network=$NETWORK \
--log-level=debug \
--db-path=$DB_PATH \
--p2p \
--p2p-feeder-node \
--p2p-addr=/ip4/0.0.0.0/tcp/7777 \
--p2p-private-key="5f6cdc3aebcc74af494df054876100368ef6126e3a33fa65b90c765b381ffc37a0a63bbeeefab0740f24a6a38dabb513b9233254ad0020c721c23e69bc820089" \
--http \
--http-host "0.0.0.0" \
--http-port "$JUNO_PORT" \
--pprof \
--pprof-port "$PPROF_PORT" \
--disable-l1-verification"

# Ensure the request file exists if not set to "none"
if [ "$REQUEST_FILE" != "none" ] && [ ! -f "$REQUEST_FILE" ]; then
echo "Error: Request file '$REQUEST_FILE' not found."
exit 1
fi

if [ "$REQUEST_FILE" != "none" ]; then
REQUEST_PAYLOAD=$(cat "$REQUEST_FILE")
fi

echo "Using profiling duration: $PROFILE_DURATION seconds"
echo "Using request file: $REQUEST_FILE"

# 1. Start Juno in a new terminal session and log output to juno.log
echo "Starting Juno..."
tmux new-session -d -s juno_session "bash -c '$JUNO_BINARY $JUNO_ARGS > juno.log 2>&1'"

# 2. Wait for Juno to be ready
echo "Waiting for Juno to start..."
MAX_WAIT=60
WAIT_TIME=0
while ! curl --silent --fail --location 'http://localhost:6060' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc":"2.0",
"method":"juno_version",
"id":1
}'; do
if ! tmux has-session -t juno_session 2>/dev/null; then
echo "Error: Juno crashed during startup."
exit 1
fi
if [ $WAIT_TIME -ge $MAX_WAIT ]; then
echo "Juno did not start within $MAX_WAIT seconds. Exiting."
tmux kill-session -t juno_session
exit 1
fi
echo "Still waiting for Juno... ($WAIT_TIME seconds)"
sleep 2
((WAIT_TIME+=2))
done
echo "Juno is up and running."

# 3. Start CPU profiling in the background
echo "Capturing profile for $PROFILE_DURATION seconds..."
curl -o $OUTPUT_FILE "http://localhost:$PPROF_PORT/debug/pprof/$PROFILE?seconds=$PROFILE_DURATION" &

if [ "$REQUEST_FILE" != "none" ]; then
# 4. Send requests and count responses
echo "Sending requests for $PROFILE_DURATION seconds..."
END_TIME=$((SECONDS + PROFILE_DURATION))
TOTAL_REQUESTS=0
SUCCESSFUL_REQUESTS=0

while [ $SECONDS -lt $END_TIME ]; do
RESPONSE=$(curl --silent --location "http://localhost:$JUNO_PORT" \
--header "Content-Type: application/json" \
--data "$REQUEST_PAYLOAD")

((TOTAL_REQUESTS++))

# Check if response contains a result field
if echo "$RESPONSE" | jq -e '.result' > /dev/null 2>&1; then
((SUCCESSFUL_REQUESTS++))
else
echo "Error in response: $RESPONSE"
fi
done

# Print request statistics
echo "Total requests sent: $TOTAL_REQUESTS"
echo "Successful requests: $SUCCESSFUL_REQUESTS"
fi

# Wait for profiling and requests to complete
wait
echo "CPU profile saved to trace.out"

# 5. Stop Juno
echo "Stopping Juno..."
tmux kill-session -t juno_session
echo "Juno stopped."

# 6. Analyze the profile (optional)
# echo "Run 'go tool pprof trace.out' to analyze the profile."
echo "Run 'go tool pprof -http=:3000 $OUTPUT_FILE' to analyze the profile."
Loading