Private
Public Access
1
0
Files
it232Abschied/benchmark/main.go
Sebastian Unterschütz 5ce097bbb7
All checks were successful
Dynamic Branch Deploy / build-and-deploy (push) Successful in 1m37s
add bench
2025-11-27 21:59:54 +01:00

184 lines
4.5 KiB
Go

package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"sync"
"sync/atomic"
"time"
)
// Konfiguration (über Flags steuerbar)
var (
targetURL string
numClients int
duration time.Duration
chunkTicks int
)
// Statistiken (Atomar für Thread-Sicherheit)
var (
totalRequests int64
totalErrors int64
totalLatency int64 // in Millisekunden
)
// Datenstrukturen für Kommunikation (Minimal)
type StartResponse struct {
SessionID string `json:"sessionId"`
}
type Input struct {
Tick int `json:"t"`
Act string `json:"act"`
}
type ValidateRequest struct {
SessionID string `json:"sessionId"`
Inputs []Input `json:"inputs"`
TotalTicks int `json:"totalTicks"`
}
func main() {
// 1. Argumente parsen
flag.StringVar(&targetURL, "url", "http://localhost:8080", "URL zum Server")
flag.IntVar(&numClients, "clients", 50, "Anzahl gleichzeitiger Spieler")
flag.DurationVar(&duration, "time", 10*time.Second, "Dauer des Tests (z.B. 10s, 1m)")
flag.IntVar(&chunkTicks, "ticks", 60, "Simulierte Ticks pro Anfrage (Last)")
flag.Parse()
fmt.Printf("🚀 Starte Benchmark auf %s\n", targetURL)
fmt.Printf("👥 Spieler (Clients): %d\n", numClients)
fmt.Printf("⏱️ Dauer: %s\n", duration)
fmt.Printf("🏋️ Last pro Request: %d Ticks Physik\n", chunkTicks)
fmt.Println("---------------------------------------------------")
// 2. Clients starten
var wg sync.WaitGroup
start := time.Now()
// Kanal um den Workern das Stop-Signal zu geben
stopChan := make(chan struct{})
// Timer für das Testende
time.AfterFunc(duration, func() {
close(stopChan)
})
for i := 0; i < numClients; i++ {
wg.Add(1)
go runClient(i, &wg, stopChan)
}
// Warten bis alle fertig sind
wg.Wait()
totalTime := time.Since(start)
// 3. Auswertung
printReport(totalTime)
}
func runClient(id int, wg *sync.WaitGroup, stopChan <-chan struct{}) {
defer wg.Done()
// A. Session Starten
sessionID, err := startSession()
if err != nil {
log.Printf("[Client %d] Start Fehler: %v", id, err)
atomic.AddInt64(&totalErrors, 1)
return
}
// B. Game Loop simulieren
client := &http.Client{Timeout: 5 * time.Second}
for {
select {
case <-stopChan:
return // Testzeit abgelaufen
default:
// Wir simulieren einen Chunk (z.B. Spieler rennt einfach geradeaus)
reqData := ValidateRequest{
SessionID: sessionID,
Inputs: []Input{}, // Keine Eingaben = Nur Rennen
TotalTicks: chunkTicks,
}
payload, _ := json.Marshal(reqData)
reqStart := time.Now()
resp, err := client.Post(targetURL+"/api/validate", "application/json", bytes.NewBuffer(payload))
latency := time.Since(reqStart).Milliseconds()
if err != nil || resp.StatusCode != 200 {
// Fehler zählen
atomic.AddInt64(&totalErrors, 1)
if resp != nil {
io.Copy(io.Discard, resp.Body) // Body leeren
resp.Body.Close()
}
} else {
// Erfolg zählen
atomic.AddInt64(&totalRequests, 1)
atomic.AddInt64(&totalLatency, latency)
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
}
// Optional: Kurz warten um "echte" 60 FPS zu simulieren?
// Für Stresstests lassen wir das weg, wir wollen sehen was MAXIMAL geht.
// time.Sleep(100 * time.Millisecond)
}
}
}
func startSession() (string, error) {
resp, err := http.Post(targetURL+"/api/start", "application/json", nil)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("status %d", resp.StatusCode)
}
var data StartResponse
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return "", err
}
return data.SessionID, nil
}
func printReport(totalTime time.Duration) {
reqs := atomic.LoadInt64(&totalRequests)
errs := atomic.LoadInt64(&totalErrors)
lat := atomic.LoadInt64(&totalLatency)
avgLat := 0.0
if reqs > 0 {
avgLat = float64(lat) / float64(reqs)
}
rps := float64(reqs) / totalTime.Seconds()
fmt.Println("\n📊 ERGEBNISSE")
fmt.Println("---------------------------------------------------")
fmt.Printf("✅ Erfolgreiche Requests: %d\n", reqs)
fmt.Printf("❌ Fehler: %d\n", errs)
fmt.Printf("⚡ Requests pro Sekunde: %.2f Req/s\n", rps)
fmt.Printf("🐢 Ø Antwortzeit: %.2f ms\n", avgLat)
fmt.Println("---------------------------------------------------")
if avgLat > 100 {
fmt.Println("⚠️ WARNUNG: Server antwortet langsam (>100ms). Spieler könnten Lags spüren.")
} else {
fmt.Println("✨ PERFEKT: Server ist schnell genug für flüssiges Spielen!")
}
}