Skip to content

Commit abbcf94

Browse files
committed
Introduce memory.hugepages feature
Signed-off-by: Marcin Franczyk <[email protected]>
1 parent 99d63d3 commit abbcf94

File tree

2 files changed

+82
-1
lines changed

2 files changed

+82
-1
lines changed

docs/usage/customization-guide.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,9 @@ The following features are available for matching:
966966
| | | **`node_count`** | int | Number of NUMA nodes |
967967
| **`memory.swap`** | attribute | | | Swap enabled on node |
968968
| | | **`enabled`** | bool | `true` if swap partition detected, `false` otherwise |
969+
| **`memory.hugepages`** | attribute | | | Discovery of huge pages size on node |
970+
| | | **`enabled`** | bool | `true` if huge pages size has been configured, otherwise `false` |
971+
| | | **`hugepages-<page-size>`** | bool | `true` if the corresponding huge page size is enabled (e.g., `hugepages-2Mi`), the attribute is absent if not enabled |
969972
| **`network.device`** | instance | | | Physical (non-virtual) network interfaces present in the system |
970973
| | | **`name`** | string | Name of the network interface |
971974
| | | **`<sysfs-attribute>`** | string | Sysfs network interface attribute, available attributes: `operstate`, `speed`, `sriov_numvfs`, `sriov_totalvfs` |

source/memory/memory.go

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ limitations under the License.
1717
package memory
1818

1919
import (
20+
"errors"
2021
"fmt"
2122
"os"
2223
"path/filepath"
24+
"regexp"
2325
"strconv"
2426
"strings"
2527

28+
"k8s.io/apimachinery/pkg/api/resource"
2629
"k8s.io/klog/v2"
2730

2831
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
@@ -40,9 +43,12 @@ const NvFeature = "nv"
4043
// NumaFeature is the name of the feature set that holds all NUMA related features.
4144
const NumaFeature = "numa"
4245

43-
// SwapFeature is the name of the feature set that holds all Swap related features
46+
// SwapFeature is the name of the feature set that holds all Swap related features.
4447
const SwapFeature = "swap"
4548

49+
// HugePages is the name of the feature set that holds information about huge pages.
50+
const HugePages = "hugepages"
51+
4652
// memorySource implements the FeatureSource and LabelSource interfaces.
4753
type memorySource struct {
4854
features *nfdv1alpha1.Features
@@ -115,6 +121,13 @@ func (s *memorySource) Discover() error {
115121
s.features.Instances[NvFeature] = nfdv1alpha1.InstanceFeatureSet{Elements: nv}
116122
}
117123

124+
// Detect Huge Pages
125+
if hp, err := detectHugePages(); err != nil {
126+
klog.ErrorS(err, "failed to detect huge pages")
127+
} else {
128+
s.features.Attributes[HugePages] = nfdv1alpha1.AttributeFeatureSet{Elements: hp}
129+
}
130+
118131
klog.V(3).InfoS("discovered features", "featureSource", s.Name(), "features", utils.DelayedDumper(s.features))
119132

120133
return nil
@@ -179,6 +192,71 @@ func detectNv() ([]nfdv1alpha1.InstanceFeature, error) {
179192
return info, nil
180193
}
181194

195+
// detectHugePages checks whether huge pages are enabled on the node
196+
// and retrieves the configured huge page sizes.
197+
func detectHugePages() (map[string]string, error) {
198+
hugePages := map[string]string{
199+
"enabled": "false",
200+
}
201+
202+
basePath := hostpath.SysfsDir.Path("kernel/mm/hugepages")
203+
subdirs, err := os.ReadDir(basePath)
204+
if err != nil {
205+
if errors.Is(err, os.ErrNotExist) {
206+
return hugePages, nil
207+
}
208+
return nil, fmt.Errorf("unable to read huge pages size: %w", err)
209+
}
210+
211+
reg := regexp.MustCompile(`hugepages-(\d+)`)
212+
for _, entry := range subdirs {
213+
if !entry.IsDir() {
214+
continue
215+
}
216+
217+
pageSize, err := getHugePageSize(basePath, entry.Name(), reg)
218+
if err != nil {
219+
klog.ErrorS(err, "skipping huge page entry", "entry", entry.Name())
220+
continue
221+
}
222+
if pageSize != "" {
223+
hugePages["enabled"] = "true"
224+
hugePages[pageSize] = "true"
225+
}
226+
}
227+
228+
return hugePages, nil
229+
}
230+
231+
func getHugePageSize(basePath, dirName string, reg *regexp.Regexp) (string, error) {
232+
matches := reg.FindStringSubmatch(dirName)
233+
if len(matches) != 2 {
234+
return "", fmt.Errorf("unexpected directory format: %s", dirName)
235+
}
236+
237+
totalPagesFile := filepath.Join(basePath, dirName, "nr_hugepages")
238+
totalPagesRaw, err := os.ReadFile(totalPagesFile)
239+
if err != nil {
240+
return "", fmt.Errorf("unable to read total number of huge pages from the file name: %s", totalPagesFile)
241+
}
242+
243+
totalPages, err := strconv.Atoi(strings.TrimSpace(string(totalPagesRaw)))
244+
if err != nil {
245+
return "", fmt.Errorf("unable to convert total pages to integer - %s: %s", totalPagesFile, totalPagesRaw)
246+
}
247+
if totalPages < 1 {
248+
return "", nil
249+
}
250+
251+
sizeFormat := matches[1] + "Ki"
252+
quantity, err := resource.ParseQuantity(sizeFormat)
253+
if err != nil {
254+
return "", fmt.Errorf("invalid size format: %s", sizeFormat)
255+
}
256+
257+
return "hugepages-" + quantity.String(), nil
258+
}
259+
182260
// ndDevAttrs is the list of sysfs files (under each nd device) that we're trying to read
183261
var ndDevAttrs = []string{"devtype", "mode"}
184262

0 commit comments

Comments
 (0)