diff options
author | Hadi Rayan Al-Sandid <halsandi@cisco.com> | 2024-06-24 10:28:58 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-07-09 20:14:28 +0000 |
commit | e0e85134ad5c26603be9ef09474f2332609ef799 (patch) | |
tree | 80111e6c2a3987b93b938c35c43c79f8fe97df66 /extras/hs-test | |
parent | c44fa9355bb8a5f0315c49ed56bc44799e1fd84f (diff) |
hs-test: Add CPU pinning test suite
Type: test
Added suite to verify that VPP launches with provided
CPU pinning configurations. CPU configuration is
specified per-test.
Change-Id: Ic283339676d3b24636fc21156a09a192c1a8d8da
Signed-off-by: Hadi Rayan Al-Sandid <halsandi@cisco.com>
Diffstat (limited to 'extras/hs-test')
-rw-r--r-- | extras/hs-test/cpu_pinning_test.go | 30 | ||||
-rw-r--r-- | extras/hs-test/infra/container.go | 1 | ||||
-rw-r--r-- | extras/hs-test/infra/hst_suite.go | 10 | ||||
-rw-r--r-- | extras/hs-test/infra/suite_cpu_pinning.go | 101 | ||||
-rw-r--r-- | extras/hs-test/infra/vppinstance.go | 60 | ||||
-rw-r--r-- | extras/hs-test/topo-containers/singleCpuPinning.yaml | 11 |
6 files changed, 201 insertions, 12 deletions
diff --git a/extras/hs-test/cpu_pinning_test.go b/extras/hs-test/cpu_pinning_test.go new file mode 100644 index 00000000000..b8dec65937e --- /dev/null +++ b/extras/hs-test/cpu_pinning_test.go @@ -0,0 +1,30 @@ +package main + +import ( + . "fd.io/hs-test/infra" +) + +func init() { + RegisterCpuPinningSoloTests(DefaultCpuConfigurationTest, SkipCoresTest) +} + +// TODO: Add more CPU configuration tests + +func DefaultCpuConfigurationTest(s *CpuPinningSuite) { + vpp := s.GetContainerByName(SingleTopoContainerVpp).VppInstance + s.AssertNil(vpp.Start()) +} + +func SkipCoresTest(s *CpuPinningSuite) { + + skipCoresConfiguration := VppCpuConfig{ + PinMainCpu: true, + PinWorkersCorelist: true, + SkipCores: 1, + } + + vpp := s.GetContainerByName(SingleTopoContainerVpp).VppInstance + vpp.CpuConfig = skipCoresConfiguration + + s.AssertNil(vpp.Start()) +} diff --git a/extras/hs-test/infra/container.go b/extras/hs-test/infra/container.go index 1dd82809f8a..3e8ccb4550f 100644 --- a/extras/hs-test/infra/container.go +++ b/extras/hs-test/infra/container.go @@ -249,6 +249,7 @@ func (c *Container) newVppInstance(cpus []int, additionalConfigs ...Stanza) (*Vp vpp := new(VppInstance) vpp.Container = c vpp.Cpus = cpus + vpp.setDefaultCpuConfig() vpp.AdditionalConfig = append(vpp.AdditionalConfig, additionalConfigs...) c.VppInstance = vpp return vpp, nil diff --git a/extras/hs-test/infra/hst_suite.go b/extras/hs-test/infra/hst_suite.go index b2e069343a1..41c8d29f84a 100644 --- a/extras/hs-test/infra/hst_suite.go +++ b/extras/hs-test/infra/hst_suite.go @@ -247,6 +247,16 @@ func (s *HstSuite) SkipIfMultiWorker(args ...any) { } } +func (s *HstSuite) SkipIfNotEnoughAvailableCpus(containerCount int, nCpus int) bool { + MaxRequestedCpu := (GinkgoParallelProcess() * containerCount * nCpus) + + if len(s.CpuAllocator.cpus)-1 < MaxRequestedCpu { + s.Skip(fmt.Sprintf("test case cannot allocate requested cpus (%d cpus * %d containers)", nCpus, containerCount)) + } + + return true +} + func (s *HstSuite) SkipUnlessExtendedTestsBuilt() { imageName := "hs-test/nginx-http3" diff --git a/extras/hs-test/infra/suite_cpu_pinning.go b/extras/hs-test/infra/suite_cpu_pinning.go new file mode 100644 index 00000000000..629d2dac3ed --- /dev/null +++ b/extras/hs-test/infra/suite_cpu_pinning.go @@ -0,0 +1,101 @@ +package hst + +import ( + "fmt" + . "github.com/onsi/ginkgo/v2" + "reflect" + "runtime" + "strings" +) + +var cpuPinningTests = map[string][]func(s *CpuPinningSuite){} +var cpuPinningSoloTests = map[string][]func(s *CpuPinningSuite){} + +type CpuPinningSuite struct { + HstSuite +} + +func RegisterCpuPinningTests(tests ...func(s *CpuPinningSuite)) { + cpuPinningTests[getTestFilename()] = tests +} + +func RegisterCpuPinningSoloTests(tests ...func(s *CpuPinningSuite)) { + cpuPinningSoloTests[getTestFilename()] = tests +} + +func (s *CpuPinningSuite) SetupSuite() { + s.HstSuite.SetupSuite() + s.LoadNetworkTopology("tap") + s.LoadContainerTopology("singleCpuPinning") +} + +func (s *CpuPinningSuite) SetupTest() { + // Skip if we cannot allocate 3 CPUs for test container + s.SkipIfNotEnoughAvailableCpus(1, 3) + s.CpuPerVpp = 3 + s.HstSuite.SetupTest() + container := s.GetContainerByName(SingleTopoContainerVpp) + vpp, err := container.newVppInstance(container.AllocatedCpus) + s.AssertNotNil(vpp, fmt.Sprint(err)) + +} + +var _ = Describe("CpuPinningSuite", Ordered, ContinueOnFailure, func() { + var s CpuPinningSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + + }) + AfterEach(func() { + s.TearDownTest() + }) + + // https://onsi.github.io/ginkgo/#dynamically-generating-specs + for filename, tests := range cpuPinningTests { + for _, test := range tests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.Log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(SuiteTimeout)) + } + } +}) + +var _ = Describe("CpuPinningSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + var s CpuPinningSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for filename, tests := range cpuPinningSoloTests { + for _, test := range tests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.Log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(SuiteTimeout)) + } + } +}) diff --git a/extras/hs-test/infra/vppinstance.go b/extras/hs-test/infra/vppinstance.go index 48d2b783917..d4f570046c7 100644 --- a/extras/hs-test/infra/vppinstance.go +++ b/extras/hs-test/infra/vppinstance.go @@ -88,6 +88,13 @@ type VppInstance struct { Connection *core.Connection ApiStream api.Stream Cpus []int + CpuConfig VppCpuConfig +} + +type VppCpuConfig struct { + PinMainCpu bool + PinWorkersCorelist bool + SkipCores int } func (vpp *VppInstance) getSuite() *HstSuite { @@ -131,7 +138,7 @@ func (vpp *VppInstance) Start() error { defaultApiSocketFilePath, defaultLogFilePath, ) - configContent += vpp.generateCpuConfig() + configContent += vpp.generateVPPCpuConfig() for _, c := range vpp.AdditionalConfig { configContent += c.ToString() } @@ -476,26 +483,55 @@ func (vpp *VppInstance) Disconnect() { vpp.ApiStream.Close() } -func (vpp *VppInstance) generateCpuConfig() string { +func (vpp *VppInstance) setDefaultCpuConfig() { + vpp.CpuConfig.PinMainCpu = true + vpp.CpuConfig.PinWorkersCorelist = true + vpp.CpuConfig.SkipCores = 0 +} + +func (vpp *VppInstance) generateVPPCpuConfig() string { var c Stanza var s string + startCpu := 0 if len(vpp.Cpus) < 1 { return "" } - c.NewStanza("cpu"). - Append(fmt.Sprintf("main-core %d", vpp.Cpus[0])) - vpp.getSuite().Log(fmt.Sprintf("main-core %d", vpp.Cpus[0])) - workers := vpp.Cpus[1:] + + c.NewStanza("cpu") + + // If skip-cores is valid, use as start value to assign main/workers CPUs + if vpp.CpuConfig.SkipCores != 0 { + c.Append(fmt.Sprintf("skip-cores %d", vpp.CpuConfig.SkipCores)) + vpp.getSuite().Log(fmt.Sprintf("skip-cores %d", vpp.CpuConfig.SkipCores)) + } + + if len(vpp.Cpus) > vpp.CpuConfig.SkipCores { + startCpu = vpp.CpuConfig.SkipCores + } + + if vpp.CpuConfig.PinMainCpu { + c.Append(fmt.Sprintf("main-core %d", vpp.Cpus[startCpu])) + vpp.getSuite().Log(fmt.Sprintf("main-core %d", vpp.Cpus[startCpu])) + } + + workers := vpp.Cpus[startCpu+1:] if len(workers) > 0 { - for i := 0; i < len(workers); i++ { - if i != 0 { - s = s + ", " + if vpp.CpuConfig.PinWorkersCorelist { + for i := 0; i < len(workers); i++ { + if i != 0 { + s = s + ", " + } + s = s + fmt.Sprintf("%d", workers[i]) } - s = s + fmt.Sprintf("%d", workers[i]) + c.Append(fmt.Sprintf("corelist-workers %s", s)) + vpp.getSuite().Log("corelist-workers " + s) + } else { + s = fmt.Sprintf("%d", len(workers)) + c.Append(fmt.Sprintf("workers %s", s)) + vpp.getSuite().Log("workers " + s) } - c.Append(fmt.Sprintf("corelist-workers %s", s)) - vpp.getSuite().Log("corelist-workers " + s) } + return c.Close().ToString() } diff --git a/extras/hs-test/topo-containers/singleCpuPinning.yaml b/extras/hs-test/topo-containers/singleCpuPinning.yaml new file mode 100644 index 00000000000..6e673aa85bf --- /dev/null +++ b/extras/hs-test/topo-containers/singleCpuPinning.yaml @@ -0,0 +1,11 @@ +--- +volumes: + - volume: &shared-vol + host-dir: "$HST_VOLUME_DIR/shared-vol" + +containers: + - name: "vpp" + volumes: + - <<: *shared-vol + container-dir: "/tmp/vpp" + is-default-work-dir: true |