diff --git a/tools/debug/blocker/main.go b/tools/debug/blocker/main.go new file mode 100644 index 0000000000..013a654b77 --- /dev/null +++ b/tools/debug/blocker/main.go @@ -0,0 +1,129 @@ +// Copyright (C) 2019-2024 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +// blocker benchmarks blocks fetching performance via rest or ws +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "net/http" + "os" + "strconv" + "sync/atomic" + "time" +) + +var address = flag.String("addr", "", "Server rest address (host:port)") +var token = flag.String("token", "", "Server token for rest endpoint (optional)") +var wsAddress = flag.String("wsaddr", "", "Server ws address (host:port)") +var block = flag.Int("block", 1, "Block number to download/fetch") +var rest = flag.Bool("rest", false, "Use rest endpoint") + +func fatal(msg string, args ...any) { + fmt.Println(msg, args) + os.Exit(1) +} + +func main() { + + flag.Parse() + if *address == "" { + fatal("-addr=address required") + } + if !*rest && *wsAddress == "" { + fatal("-wsaddr=address required") + } + + var url string + var maxReq int64 + if *rest { + url = fmt.Sprintf("http://%s/v2/blocks/%d", *address, *block) + maxReq = 133 + } else { + var httpClient = http.Client{} + var resp, err = httpClient.Get(fmt.Sprintf("http://%s/genesis", *address)) + if err != nil { + fatal("get genesis error:", err) + } + data, err := io.ReadAll(resp.Body) + if err != nil { + fatal("read genesis error:", err) + } + var genesis map[string]interface{} + err = json.Unmarshal(data, &genesis) + if err != nil { + fatal("unmarshal genesis error:", err) + } + var network = genesis["network"].(string) + var id = genesis["id"].(string) + url = fmt.Sprintf("%s/v1/%s-%s/block/%s", *wsAddress, network, id, strconv.FormatUint(uint64(*block), 36)) + maxReq = 100 + } + + httpClient := http.Client{Transport: &http.Transport{MaxIdleConnsPerHost: int(maxReq)}} + var limit atomic.Int64 + var count atomic.Int64 + fmt.Printf("using url: %s\n", url) + start := time.Now() + go func() { + t := time.NewTicker(5 * time.Second) + curStart := time.Now() + curCount := count.Load() + for { + <-t.C + dt := time.Since(curStart) + num := count.Load() - curCount + curStart = time.Now() + curCount = count.Load() + fmt.Printf("elapsed: %s, req/s: %f\n", time.Since(start), float64(num)/dt.Seconds()) + } + }() + + for { + if limit.Load() < maxReq { + count.Add(1) + val := limit.Add(1) + go func(idx int64) { + defer limit.Add(-1) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + fatal("new req error:", err) + } + if *rest { + req.Header.Set("X-Algo-API-Token", *token) + } + + resp, err := httpClient.Do(req) + if err != nil { + fatal("do error:", idx, err) + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + fmt.Println("status:", idx, resp.Status) + os.Exit(1) + } else { + buf, _ := io.ReadAll(resp.Body) + if len(buf) == 0 { + fmt.Println("status:", idx, resp.Status, len(buf)) + } + } + }(val) + } + } +} diff --git a/tools/debug/pender/main.go b/tools/debug/pender/main.go new file mode 100644 index 0000000000..e70cc78c4e --- /dev/null +++ b/tools/debug/pender/main.go @@ -0,0 +1,99 @@ +// Copyright (C) 2019-2024 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +// pender benchmarks pending transactions REST API performance +package main + +import ( + "flag" + "fmt" + "io" + "net/http" + "os" + "sync/atomic" + "time" + + "github.com/algorand/go-algorand/crypto" + "github.com/algorand/go-algorand/data/transactions" +) + +var address = flag.String("addr", "", "Server rest address (host:port)") +var token = flag.String("token", "", "Server token for rest endpoint (optional)") + +func fatal(msg string, args ...any) { + fmt.Println(msg, args) + os.Exit(1) +} + +func main() { + + flag.Parse() + if *address == "" { + fatal("-addr=address required") + } + + var url string + var maxReq int64 + txID := transactions.Txid{} + crypto.RandBytes(txID[:]) + strID := "UCPICZH6FWMZVPJH7X4IV6M2WZZQCRX7ETIQK742BQMCDP5TVNEQ" + url = fmt.Sprintf("http://%s/v2/transactions/pending/%s", *address, strID) + maxReq = 100 + + httpClient := http.Client{Transport: &http.Transport{MaxIdleConnsPerHost: int(maxReq)}} + var limit atomic.Int64 + var count atomic.Int64 + fmt.Printf("using url: %s\n", url) + start := time.Now() + go func() { + t := time.NewTicker(5 * time.Second) + curStart := time.Now() + curCount := count.Load() + for { + <-t.C + dt := time.Since(curStart) + num := count.Load() - curCount + curStart = time.Now() + curCount = count.Load() + fmt.Printf("elapsed: %s, req/s: %f\n", time.Since(start), float64(num)/dt.Seconds()) + } + }() + + for { + if limit.Load() < maxReq { + count.Add(1) + val := limit.Add(1) + go func(idx int64) { + defer limit.Add(-1) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + fatal("new req error:", err) + } + req.Header.Set("X-Algo-API-Token", *token) + + resp, err := httpClient.Do(req) + if err != nil { + fatal("do error:", idx, err) + } + defer resp.Body.Close() + buf, _ := io.ReadAll(resp.Body) + if len(buf) == 0 { + fmt.Println("status:", idx, resp.Status, len(buf)) + } + }(val) + } + } +}