Skip to content

Commit

Permalink
Seperate performance framework and clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
GawronskaSylwia authored and wojciechos committed Sep 13, 2024
1 parent f00475b commit 98503d2
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 62 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Run Tests
name: Run Tests and Benchmarks

on:
push:
Expand All @@ -7,8 +7,8 @@ on:
branches: [ main ]

jobs:
test:
name: Run p2p tests
test-and-benchmark:
name: Run p2p tests and benchmarks
runs-on: ubuntu-latest

steps:
Expand All @@ -26,8 +26,8 @@ jobs:
- name: Set TARGET_PEER_ADDRESS environment variable
run: echo "TARGET_PEER_ADDRESS=/ip4/35.237.66.77/tcp/7777/p2p/12D3KooWR8ikUDiinyE5wgdYiqsdLfJRsBDYKGii6L3oyoipVEaV" >> $GITHUB_ENV

- name: Run performance tests
run: go test -v -timeout 5m ./tests/performance
- name: Run performance benchmarks
run: go test -v -bench=. -benchtime=1x ./tests/performance
env:
TARGET_PEER_ADDRESS: ${{ env.TARGET_PEER_ADDRESS }}

Expand Down
6 changes: 0 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ var (
)

func init() {
//TargetPeerAddress = getEnv("TARGET_PEER_ADDRESS", "/ip4/35.237.66.77/tcp/7777/p2p/12D3KooWR8ikUDiinyE5wgdYiqsdLfJRsBDYKGii6L3oyoipVEaV")
TargetPeerAddress = getEnv("TARGET_PEER_ADDRESS", "/ip4/127.0.0.1/tcp/7777/p2p/12D3KooWLBUjEPyTiACzQZ3K1oqBXRqHwRFvAUHrm561pWWbJkYf")
timeoutStr := getEnv("DEFAULT_TEST_TIMEOUT", "300s")
var err error
Expand All @@ -35,8 +34,3 @@ func getEnv(key, fallback string) string {
}
return fallback
}

// P2P Private Key: 3d59fe5117449e06bd4b64e789e78b97a17ed2703d840cf81d3ab298a999904599fd7bdb269c2b86267a04b3867a78352a96f97b331d980cde7d83eb7d0eace0
// P2P Public Key: 99fd7bdb269c2b86267a04b3867a78352a96f97b331d980cde7d83eb7d0eace0
// P2P PeerID: 12D3KooWLBUjEPyTiACzQZ3K1oqBXRqHwRFvAUHrm561pWWbJkYf
// ./juno-v0.12.2-8-gb89e0786-macOS-x86_64 --network sepolia --p2p --p2p-feeder-node --p2p-addr /ip4/127.0.0.1/tcp/7777 --p2p-private-key 3d59fe5117449e06bd4b64e789e78b97a17ed2703d840cf81d3ab298a999904599fd7bdb269c2b86267a04b3867a78352a96f97b331d980cde7d83eb7d0eace0
Binary file removed target_node/juno-v0.12.2-8-gb89e0786-macOS-x86_64
Binary file not shown.
4 changes: 2 additions & 2 deletions tests/conformance/discovery_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tests
package conformance

import (
"context"
Expand All @@ -18,7 +18,7 @@ func TestDiscovery(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), config.DefaultTestTimeout)
defer cancel()

// Creating synthetic nodes for testing discovery functionality
// Creating synthetic nodes
node1, err := synthetic_node.New(ctx, t)
require.NoError(t, err)
node2, err := synthetic_node.New(ctx, t)
Expand Down
12 changes: 6 additions & 6 deletions tests/conformance/getBlock_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tests
package conformance

import (
"context"
Expand All @@ -22,11 +22,11 @@ type blockHeaderTestCase struct {

func TestSyntheticNodeMultipleBlockHeadersRequest(t *testing.T) {
testCases := []blockHeaderTestCase{
{"Basic Consecutive Blocks", 1, 5, 1},
{"Non-unit Step", 1, 5, 2},
{"Non-standard Start and Limit", 10, 3, 1},
{"Large Step", 1, 5, 10},
{"High Start Block", 100, 5, 1},
{name: "Basic Consecutive Blocks", startBlock: 1, limit: 5, step: 1},
{name: "Non-unit Step", startBlock: 1, limit: 5, step: 2},
{name: "Non-standard Start and Limit", startBlock: 10, limit: 3, step: 1},
{name: "Large Step", startBlock: 1, limit: 5, step: 10},
{name: "High Start Block", startBlock: 100, limit: 5, step: 1},
}

for _, tc := range testCases {
Expand Down
75 changes: 50 additions & 25 deletions tests/performance/framework/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,37 @@ import (
synthetic_node "starknet-p2p-tests/tools"
)

type PeerStats struct {
latencies []float64
successes int
connectTime float64
errorCounts map[string]int
}

type TestFunc func(ctx context.Context, syntheticNode *synthetic_node.SyntheticNode) (time.Duration, error)

// RunTest starts multiple peers, runs the specified test function for each peer,
// and collects performance statistics. It simulates a specified number of peers
// making requests to a target node and measures latencies and error rates.
func RunTest(b *testing.B, peerCount, requestsPerPeer int, rampUpTime, responseTimeout time.Duration, testFunc TestFunc) LatencyStats {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

var wg sync.WaitGroup
latencies := make([]float64, 0, peerCount*requestsPerPeer)
connectTimes := make([]float64, 0, peerCount)
var latenciesMutex sync.Mutex

var successfulRequests int64
totalRequests := int64(peerCount * requestsPerPeer)

errorCounts := make(map[string]int)
var errorCountsMutex sync.Mutex
var (
wg sync.WaitGroup
peerStatsList = make([]PeerStats, 0, peerCount) // slice to hold stats for each peer
latenciesMutex sync.Mutex
successfulRequests int64
totalRequests = int64(peerCount * requestsPerPeer)
)

// Helper function to collect stats from each peer
collectStats := func(stats PeerStats) {
atomic.AddInt64(&successfulRequests, int64(stats.successes))
latenciesMutex.Lock()
peerStatsList = append(peerStatsList, stats)
latenciesMutex.Unlock()
}

b.ResetTimer()
startTime := time.Now()
Expand All @@ -35,18 +50,9 @@ func RunTest(b *testing.B, peerCount, requestsPerPeer int, rampUpTime, responseT
wg.Add(1)
go func(peerIndex int) {
defer wg.Done()
peerLatencies, peerSuccesses, connectTime, peerErrors := simulatePeer(b, ctx, peerIndex, peerCount, requestsPerPeer, responseTimeout, testFunc)
atomic.AddInt64(&successfulRequests, int64(peerSuccesses))
latenciesMutex.Lock()
latencies = append(latencies, peerLatencies...)
connectTimes = append(connectTimes, connectTime)
latenciesMutex.Unlock()

errorCountsMutex.Lock()
for errType, count := range peerErrors {
errorCounts[errType] += count
}
errorCountsMutex.Unlock()
// Simulate peer and collect stats
peerStats := simulatePeer(b, ctx, peerIndex, requestsPerPeer, responseTimeout, testFunc)
collectStats(peerStats)
}(i)

time.Sleep(rampUpTime / time.Duration(peerCount))
Expand All @@ -57,10 +63,24 @@ func RunTest(b *testing.B, peerCount, requestsPerPeer int, rampUpTime, responseT

b.StopTimer()

return CalculateStats(latencies, connectTimes, successfulRequests, totalRequests, totalTime, peerCount, errorCounts)
// Gather all latencies and error counts from each peer to calculate stats
var allLatencies []float64
var allErrorCounts = make(map[string]int)
var connectTimes []float64

for _, stats := range peerStatsList {
allLatencies = append(allLatencies, stats.latencies...)
connectTimes = append(connectTimes, stats.connectTime)
for errType, count := range stats.errorCounts {
allErrorCounts[errType] += count
}
}

return CalculateStats(allLatencies, connectTimes, successfulRequests, totalRequests, totalTime, peerCount, allErrorCounts)
}

func simulatePeer(b *testing.B, ctx context.Context, peerIndex, totalPeers, requestsPerPeer int, responseTimeout time.Duration, testFunc TestFunc) ([]float64, int, float64, map[string]int) {
// simulatePeer simulates the behavior of a single peer, collects latencies, and tracks success/error counts.
func simulatePeer(b *testing.B, ctx context.Context, peerIndex, requestsPerPeer int, responseTimeout time.Duration, testFunc TestFunc) PeerStats {
syntheticNode, err := synthetic_node.New(ctx, b)
if err != nil {
b.Fatalf("Failed to create synthetic node: %v", err)
Expand Down Expand Up @@ -93,5 +113,10 @@ func simulatePeer(b *testing.B, ctx context.Context, peerIndex, totalPeers, requ
time.Sleep(time.Duration(50+peerIndex*10) * time.Millisecond)
}

return latencies, successfulRequests, connectTime, errorCounts
return PeerStats{
latencies: latencies,
successes: successfulRequests,
connectTime: connectTime,
errorCounts: errorCounts,
}
}
41 changes: 23 additions & 18 deletions tests/performance/getBlocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,39 @@ const (
rampUpTime = 30 * time.Second
)

// BenchmarkBlockHeaderRequestPerformance measures the performance of block header requests across varying peer counts,
// executing the requests in parallel to simulate concurrent load.
func BenchmarkBlockHeaderRequestPerformance(b *testing.B) {
peerCounts := []int{1, 5}
peerCounts := []int{1, 5, 10, 15, 20}
allResults := make(map[string]framework.LatencyStats)

for _, peerCount := range peerCounts {
peerCount := peerCount // Capture range variable
b.Run(fmt.Sprintf("Peers-%d", peerCount), func(b *testing.B) {
latencyStats := runPerformanceTest(b, peerCount)
latencyStats := framework.RunTest(b, peerCount, requestsPerPeer, rampUpTime, responseTimeout, requestBlockHeaders)
allResults[fmt.Sprintf("Peers-%d", peerCount)] = latencyStats
})
time.Sleep(5 * time.Second) // Cool-down period between tests
}

// Write all results to a file after all tests are complete
framework.WriteResultsToFile(b, allResults)
// Write all results to a file after all tests are complete using b.Cleanup
b.Cleanup(func() {
framework.WriteResultsToFile(b, allResults)
})
}

func runPerformanceTest(b *testing.B, peerCount int) framework.LatencyStats {
testFunc := func(ctx context.Context, syntheticNode *synthetic_node.SyntheticNode) (time.Duration, error) {
start := time.Now()
headers, err := syntheticNode.RequestBlockHeaders(ctx, expectedBlockNum, 1)
if err != nil {
return 0, err
}
if len(headers) == 0 {
return 0, fmt.Errorf("empty response")
}
return time.Since(start), nil
}
// requestBlockHeaders sends a request to fetch block headers and measures the latency.
func requestBlockHeaders(ctx context.Context, syntheticNode *synthetic_node.SyntheticNode) (time.Duration, error) {
// Apply a context timeout to prevent hanging requests
ctx, cancel := context.WithTimeout(ctx, responseTimeout)
defer cancel()

return framework.RunTest(b, peerCount, requestsPerPeer, rampUpTime, responseTimeout, testFunc)
start := time.Now()
headers, err := syntheticNode.RequestBlockHeaders(ctx, expectedBlockNum, 1)
if err != nil {
return 0, err
}
if len(headers) == 0 {
return 0, fmt.Errorf("received empty response for block number %d", expectedBlockNum)
}
return time.Since(start), nil
}

0 comments on commit 98503d2

Please sign in to comment.