1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2024-12-14 11:57:51 +00:00

Implement cpu feature source

Currently, it only detects one feature, i.e. hardware multithreading
(such as Intel hyper-threading technology). The corresponding feature
label is:
  feature.node.kubernetes.io/cpu-hardware_multithreading=true

However, this (architecture/platform dependent) feature is not detected
directly, and, the heuristics can be mislead. Detection works by
checking the thread siblings of each logical (and online) cpu in the
system. If any cpu has any thread siblings the feature label is set to
true. Thus, hardware multithreading could be effectively disabled e.g.
by putting all sibling cpus offline (even if the technology would be
enabled in hardware).
This commit is contained in:
Markus Lehtonen 2018-07-17 12:26:11 +03:00
parent 649d8a3ae1
commit da2cb07c64
4 changed files with 87 additions and 4 deletions

View file

@ -52,7 +52,7 @@ node-feature-discovery.
will override settings read from the config file.
[Default: ]
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,iommu,kernel,local,memory,network,pci,pstate,rdt,selinux,storage,system]
[Default: cpu,cpuid,iommu,kernel,local,memory,network,pci,pstate,rdt,selinux,storage,system]
--no-publish Do not publish discovered features to the
cluster-local Kubernetes API server.
--label-whitelist=<pattern> Regular expression to filter label names to
@ -75,6 +75,7 @@ for up-to-date information about the required volume mounts.
The current set of feature sources are the following:
- CPU
- [CPUID][cpuid] for x86/Arm64 CPU details
- IOMMU
- Kernel
@ -110,6 +111,7 @@ the only label value published for features is the string `"true"`._
```json
{
"feature.node.kubernetes.io/cpu-<feature-name>": "true",
"feature.node.kubernetes.io/cpuid-<feature-name>": "true",
"feature.node.kubernetes.io/iommu-<feature-name>": "true",
"feature.node.kubernetes.io/kernel-config.<option-name>": "true",
@ -133,6 +135,17 @@ given node. If features are not discovered on a consecutive run, the correspondi
label will be removed. This includes any restrictions placed on the consecutive run,
such as restricting discovered features with the --label-whitelist option._
### CPU Features
The CPU feature source differs from the CPUID feature source in that it
discovers CPU related features that are actually enabled, whereas CPUID only
reports *supported* CPU capabilities (i.e. a capability might be supported but
not enabled) as reported by the `cpuid` instruction.
| Feature name | Description |
| ----------------------- | -------------------------------------------------- |
| hardware_multithreading | Hardware multithreading, such as Intel HTT, enabled (number of locical CPUs is greater than physical CPUs)
### X86 CPUID Features (Partial List)
| Feature name | Description |

View file

@ -17,6 +17,7 @@ import (
k8sclient "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"sigs.k8s.io/node-feature-discovery/source"
"sigs.k8s.io/node-feature-discovery/source/cpu"
"sigs.k8s.io/node-feature-discovery/source/cpuid"
"sigs.k8s.io/node-feature-discovery/source/fake"
"sigs.k8s.io/node-feature-discovery/source/iommu"
@ -183,7 +184,7 @@ func argsParse(argv []string) (args Args) {
will override settings read from the config file.
[Default: ]
--sources=<sources> Comma separated list of feature sources.
[Default: cpuid,iommu,kernel,local,memory,network,pci,pstate,rdt,selinux,storage,system]
[Default: cpu,cpuid,iommu,kernel,local,memory,network,pci,pstate,rdt,selinux,storage,system]
--no-publish Do not publish discovered features to the
cluster-local Kubernetes API server.
--label-whitelist=<pattern> Regular expression to filter label names to
@ -259,6 +260,7 @@ func configureParameters(sourcesWhiteList []string, labelWhiteListStr string) (e
// Configure feature sources.
allSources := []source.FeatureSource{
cpu.Source{},
cpuid.Source{},
fake.Source{},
iommu.Source{},

View file

@ -152,7 +152,7 @@ func TestArgsParse(t *testing.T) {
So(args.sleepInterval, ShouldEqual, 60*time.Second)
So(args.noPublish, ShouldBeTrue)
So(args.oneshot, ShouldBeTrue)
So(args.sources, ShouldResemble, []string{"cpuid", "iommu", "kernel", "local", "memory", "network", "pci", "pstate", "rdt", "selinux", "storage", "system"})
So(args.sources, ShouldResemble, []string{"cpu", "cpuid", "iommu", "kernel", "local", "memory", "network", "pci", "pstate", "rdt", "selinux", "storage", "system"})
So(len(args.labelWhiteList), ShouldEqual, 0)
})
})
@ -174,7 +174,7 @@ func TestArgsParse(t *testing.T) {
Convey("args.labelWhiteList is set to appropriate value and args.sources is set to default value", func() {
So(args.noPublish, ShouldBeFalse)
So(args.sources, ShouldResemble, []string{"cpuid", "iommu", "kernel", "local", "memory", "network", "pci", "pstate", "rdt", "selinux", "storage", "system"})
So(args.sources, ShouldResemble, []string{"cpu", "cpuid", "iommu", "kernel", "local", "memory", "network", "pci", "pstate", "rdt", "selinux", "storage", "system"})
So(args.labelWhiteList, ShouldResemble, ".*rdt.*")
})
})

68
source/cpu/cpu.go Normal file
View file

@ -0,0 +1,68 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cpu
import (
"fmt"
"io/ioutil"
"path"
"sigs.k8s.io/node-feature-discovery/source"
)
// Implement FeatureSource interface
type Source struct{}
func (s Source) Name() string { return "cpu" }
func (s Source) Discover() (source.Features, error) {
features := source.Features{}
// Check if hyper-threading seems to be enabled
found, err := haveThreadSiblings()
if err != nil {
return nil, fmt.Errorf("Failed to detect hyper-threading: %v", err)
} else if found {
features["hardware_multithreading"] = true
}
return features, nil
}
// Check if any (online) CPUs have thread siblings
func haveThreadSiblings() (bool, error) {
const baseDir = "/sys/bus/cpu/devices"
files, err := ioutil.ReadDir(baseDir)
if err != nil {
return false, err
}
for _, file := range files {
// Try to read siblings from topology
siblings, err := ioutil.ReadFile(path.Join(baseDir, file.Name(), "topology/thread_siblings_list"))
if err != nil {
return false, err
}
for _, char := range siblings {
// If list separator found, we determine that there are multiple siblings
if char == ',' || char == '-' {
return true, nil
}
}
}
// No siblings were found
return false, nil
}