hs-test: HTTP download benchmarking

HttpTpsTest now use Gomega's gmeasure package and go internal http
client. With gmeasure you can create "Experiments" which can produce
reports to show the statistical distribution of measurement.
Potentially experiments can also be cached and used to identify
regression in performance.

Type: test

Change-Id: Id049fb0344d8ebed71b15e706b053b5c2a18e0de
Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:
Matus Fabian
2024-06-06 11:24:36 +02:00
committed by Florin Coras
parent 8a424338ad
commit 2d1f0e6c73
2 changed files with 46 additions and 20 deletions

View File

@@ -5,6 +5,7 @@ import (
"errors"
"flag"
"fmt"
"github.com/onsi/gomega/gmeasure"
"io"
"log"
"os"
@@ -500,3 +501,21 @@ func (s *HstSuite) startWget(finished chan error, server_ip, port, query, netNs
}
finished <- nil
}
/*
runBenchmark creates Gomega's experiment with the passed-in name and samples the passed-in callback repeatedly (samplesNum times),
passing in suite context, experiment and your data.
You can also instruct runBenchmark to run with multiple concurrent workers.
You can record multiple named measurements (float64 or duration) within passed-in callback.
runBenchmark then produces report to show statistical distribution of measurements.
*/
func (s *HstSuite) runBenchmark(name string, samplesNum, parallelNum int, callback func(s *HstSuite, e *gmeasure.Experiment, data interface{}), data interface{}) {
experiment := gmeasure.NewExperiment(name)
experiment.Sample(func(idx int) {
defer GinkgoRecover()
callback(s, experiment, data)
}, gmeasure.SamplingConfig{N: samplesNum, NumParallel: parallelNum})
AddReportEntry(experiment.Name, experiment)
}

View File

@@ -2,6 +2,8 @@ package main
import (
"fmt"
"github.com/onsi/gomega/gmeasure"
"io"
"net/http"
"os"
"strings"
@@ -11,36 +13,41 @@ import (
)
func init() {
registerNsTests(HttpTpsTest)
registerVethTests(HttpCliTest, HttpCliConnectErrorTest)
registerNoTopoTests(NginxHttp3Test, NginxAsServerTest,
NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest, HeaderServerTest,
HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest,
HttpCliBadRequestTest, HttpStaticPathTraversalTest)
registerNoTopoSoloTests(HttpStaticPromTest)
registerNoTopoSoloTests(HttpStaticPromTest, HttpTpsTest)
}
const wwwRootPath = "/tmp/www_root"
func HttpTpsTest(s *NsSuite) {
iface := s.getInterfaceByName(clientInterface)
client_ip := iface.ip4AddressString()
port := "8080"
finished := make(chan error, 1)
clientNetns := s.getNetNamespaceByName("cln")
container := s.getContainerByName("vpp")
// configure vpp in the container
container.vppInstance.vppctl("http tps uri tcp://0.0.0.0/8080")
go func() {
defer GinkgoRecover()
s.startWget(finished, client_ip, port, "test_file_10M", clientNetns)
}()
// wait for client
err := <-finished
func httpDownloadBenchmark(s *HstSuite, experiment *gmeasure.Experiment, data interface{}) {
url, isValid := data.(string)
s.assertEqual(true, isValid)
client := newHttpClient()
req, err := http.NewRequest("GET", url, nil)
s.assertNil(err, fmt.Sprint(err))
t := time.Now()
resp, err := client.Do(req)
s.assertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
s.assertEqual(200, resp.StatusCode)
_, err = io.ReadAll(resp.Body)
duration := time.Since(t)
experiment.RecordValue("Download Speed", (float64(resp.ContentLength)/1024/1024)/duration.Seconds(), gmeasure.Units("MB/s"), gmeasure.Precision(2))
}
func HttpTpsTest(s *NoTopoSuite) {
vpp := s.getContainerByName("vpp").vppInstance
serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
url := "http://" + serverAddress + ":8080/test_file_10M"
vpp.vppctl("http tps uri tcp://0.0.0.0/8080")
s.runBenchmark("HTTP tps 10M", 10, 0, httpDownloadBenchmark, url)
}
func HttpCliTest(s *VethsSuite) {