Skip to content

Commit

Permalink
feat: allow users to check cpu flags (#1631)
Browse files Browse the repository at this point in the history
allow users to check if specific cpu flags are supported by the host.

```yaml
apiVersion: troubleshoot.sh/v1beta2
kind: HostPreflight
metadata:
  name: ec-cluster-preflight
spec:
  collectors:
  - cpu: {}
  analyzers:
  - cpu:
      checkName: CPU
      outcomes:
        - pass:
            when: hasFlags cmov,cx8,fpu,fxsr,mmx
            message: CPU supports all required flags
        - fail:
            message: CPU not supported
```
  • Loading branch information
ricardomaraschini authored Oct 1, 2024
1 parent c1c4b61 commit 2efbc20
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 8 deletions.
42 changes: 34 additions & 8 deletions pkg/analyze/host_cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ import (
// ref: https://gitlab.com/x86-psABIs/x86-64-ABI
// ref: https://developers.redhat.com/blog/2021/01/05/building-red-hat-enterprise-linux-9-for-the-x86-64-v2-microarchitecture-level
var microarchs = map[string][]string{
"x86-64": {"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2"},
"x86-64-v2": {"cx16", "lahf_lm", "popcnt", "ssse3", "sse4_1", "sse4_2", "ssse3"},
"x86-64-v3": {"avx", "avx2", "bmi1", "bmi2", "f16c", "fma", "lzcnt", "movbe", "xsave"},
"x86-64-v4": {"avx512f", "avx512bw", "avx512cd", "avx512dq", "avx512vl"},
}

// x8664BaseFeatures are the features that are present in all x86-64 microarchitectures.
var x8664BaseFeatures = []string{"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2"}

type AnalyzeHostCPU struct {
hostAnalyzer *troubleshootv1beta2.CPUAnalyze
}
Expand Down Expand Up @@ -126,13 +124,36 @@ func (a *AnalyzeHostCPU) Analyze(
}

func doCompareHostCPUMicroArchitecture(microarch string, flags []string) (res bool, err error) {
specifics, ok := microarchs[microarch]
if !ok && microarch != "x86-64" {
specifics := make([]string, 0)
switch microarch {
case "x86-64-v4":
specifics = append(specifics, microarchs["x86-64-v4"]...)
fallthrough
case "x86-64-v3":
specifics = append(specifics, microarchs["x86-64-v3"]...)
fallthrough
case "x86-64-v2":
specifics = append(specifics, microarchs["x86-64-v2"]...)
fallthrough
case "x86-64":
specifics = append(specifics, microarchs["x86-64"]...)
default:
return false, errors.Errorf("troubleshoot does not yet support microarchitecture %q", microarch)
}
expectedFlags := x8664BaseFeatures
if len(specifics) > 0 {
expectedFlags = append(expectedFlags, specifics...)

for _, flag := range specifics {
if slices.Contains(flags, flag) {
continue
}
return false, nil
}
return true, nil
}

func doCompareHostCPUFlags(expected string, flags []string) (res bool, err error) {
expectedFlags := strings.Split(expected, ",")
if len(expectedFlags) == 0 {
return false, errors.New("expected flags cannot be empty")
}
for _, flag := range expectedFlags {
if slices.Contains(flags, flag) {
Expand Down Expand Up @@ -173,6 +194,11 @@ func compareHostCPUConditionalToActual(conditional string, logicalCount int, phy
return doCompareHostCPUMicroArchitecture(desired, flags)
}

// hasFlags allows users to query for specific flags on the CPU.
if strings.ToLower(comparator) == "hasflags" {
return doCompareHostCPUFlags(desired, flags)
}

if !compareLogical && !comparePhysical && !compareUnspecified {
return false, errors.New("unable to parse conditional")
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/analyze/host_cpu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,18 @@ func Test_compareHostCPUConditionalToActual(t *testing.T) {
flags: []string{"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2", "cx16", "lahf_lm", "popcnt", "ssse3", "sse4_1", "sse4_2", "ssse3"},
expected: true,
},
{
name: "has a non existent flag",
when: "hasFlags cmov,doesNotExist",
flags: []string{"cmov", "cx8", "fpu", "fxsr", "mmx", "syscall", "sse", "sse2", "cx16", "lahf_lm", "popcnt", "ssse3", "sse4_1", "sse4_2", "ssse3"},
expected: false,
},
{
name: "has flags",
when: "hasFlags a,b,c",
flags: []string{"a", "b", "c", "d", "e"},
expected: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
Expand Down

0 comments on commit 2efbc20

Please sign in to comment.