forked from kubevirt/kubevirt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrealtime.go
122 lines (107 loc) · 4.01 KB
/
realtime.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package performance
import (
"fmt"
"strconv"
"strings"
expect "github.com/google/goexpect"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/resource"
k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "kubevirt.io/api/core/v1"
"kubevirt.io/client-go/kubecli"
virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
"kubevirt.io/kubevirt/tests"
"kubevirt.io/kubevirt/tests/console"
cd "kubevirt.io/kubevirt/tests/containerdisk"
"kubevirt.io/kubevirt/tests/framework/checks"
"kubevirt.io/kubevirt/tests/libvmi"
"kubevirt.io/kubevirt/tests/util"
)
const tuneAdminRealtimeCloudInitData = `#cloud-config
password: fedora
chpasswd: { expire: False }
bootcmd:
- sudo tuned-adm profile realtime
`
func byStartingTheVMI(vmi *v1.VirtualMachineInstance, virtClient kubecli.KubevirtClient) {
By("Starting a VirtualMachineInstance")
var err error
vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Create(vmi)
Expect(err).ToNot(HaveOccurred())
tests.WaitForSuccessfulVMIStart(vmi)
}
func withRelatimeConfiguration(memory string, realtimeMask string) libvmi.Option {
memoryRequest := resource.MustParse(memory)
return func(vmi *v1.VirtualMachineInstance) {
vmi.Spec.Domain.CPU = &v1.CPU{
Model: "host-passthrough",
DedicatedCPUPlacement: true,
Realtime: &v1.Realtime{Mask: realtimeMask},
NUMA: &v1.NUMA{GuestMappingPassthrough: &v1.NUMAGuestMappingPassthrough{}},
}
vmi.Spec.Domain.Memory = &v1.Memory{
Hugepages: &v1.Hugepages{PageSize: "2Mi"},
Guest: &memoryRequest,
}
}
}
var _ = SIGDescribe("CPU latency tests for measuring realtime VMs performance", func() {
var (
vmi *v1.VirtualMachineInstance
virtClient kubecli.KubevirtClient
err error
)
BeforeEach(func() {
skipIfNoRealtimePerformanceTests()
virtClient, err = kubecli.GetKubevirtClient()
util.PanicOnError(err)
checks.SkipTestIfNoFeatureGate(virtconfig.NUMAFeatureGate)
checks.SkipTestIfNotEnoughNodesWithCPUManagerWith2MiHugepages(1)
})
It("running cyclictest and collecting results directly from VM", func() {
const memory = "512Mi"
vmi = libvmi.New(
libvmi.WithRng(),
libvmi.WithContainerImage(cd.ContainerDiskFor(cd.ContainerDiskFedoraRealtime)),
libvmi.WithCloudInitNoCloudUserData(tuneAdminRealtimeCloudInitData, true),
libvmi.WithResourceCPU("2"),
libvmi.WithLimitCPU("2"),
libvmi.WithResourceMemory(memory),
libvmi.WithLimitMemory(memory),
withRelatimeConfiguration(memory, ""),
)
byStartingTheVMI(vmi, virtClient)
By("validating VMI is up and running")
vmi, err = virtClient.VirtualMachineInstance(util.NamespaceTestDefault).Get(vmi.Name, &k8smetav1.GetOptions{})
Expect(err).ToNot(HaveOccurred())
Expect(vmi.Status.Phase).To(Equal(v1.Running))
Expect(console.LoginToFedora(vmi)).To(Succeed())
By(fmt.Sprintf("running cyclictest for %d seconds", cyclicTestDurationInSeconds))
cmd := fmt.Sprintf("sudo cyclictest --policy fifo --priority 95 -i 100 -H 1000 -D %ds -q |grep 'Max Latencies' |awk '{print $4}'\n", cyclicTestDurationInSeconds)
res, err := console.SafeExpectBatchWithResponse(vmi, []expect.Batcher{
&expect.BSnd{S: cmd},
&expect.BExp{R: console.RetValue("[0-9]+")},
}, int(5+cyclicTestDurationInSeconds))
Expect(err).NotTo(HaveOccurred())
Expect(res).To(HaveLen(1))
sout := strings.Split(res[0].Output, "\r\n")
Expect(sout).To(HaveLen(3))
max, err := strconv.ParseInt(sout[1], 10, 64)
Expect(err).NotTo(HaveOccurred())
Expect(max).NotTo(BeNumerically(">", realtimeThreshold), fmt.Sprintf("Maximum CPU latency of %d is greater than threshold %d", max, realtimeThreshold))
})
})
type psOutput struct {
priority int64
processorID int64
}
func newPs(psLine string) psOutput {
s := strings.Split(psLine, " ")
Expect(len(s)).To(BeNumerically(">", 1))
prio, err := strconv.ParseInt(s[0], 10, 8)
Expect(err).NotTo(HaveOccurred())
procID, err := strconv.ParseInt(s[1], 10, 8)
Expect(err).NotTo(HaveOccurred())
return psOutput{priority: prio, processorID: procID}
}