@@ -17,12 +17,15 @@ limitations under the License.
17
17
package memory
18
18
19
19
import (
20
+ "errors"
20
21
"fmt"
21
22
"os"
22
23
"path/filepath"
23
24
"strconv"
24
25
"strings"
25
26
27
+ corev1 "k8s.io/api/core/v1"
28
+ "k8s.io/apimachinery/pkg/api/resource"
26
29
"k8s.io/klog/v2"
27
30
28
31
nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1"
@@ -40,9 +43,12 @@ const NvFeature = "nv"
40
43
// NumaFeature is the name of the feature set that holds all NUMA related features.
41
44
const NumaFeature = "numa"
42
45
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.
44
47
const SwapFeature = "swap"
45
48
49
+ // HugePages is the name of the feature set that holds information about huge pages.
50
+ const HugePages = "hugepages"
51
+
46
52
// memorySource implements the FeatureSource and LabelSource interfaces.
47
53
type memorySource struct {
48
54
features * nfdv1alpha1.Features
@@ -115,6 +121,13 @@ func (s *memorySource) Discover() error {
115
121
s .features .Instances [NvFeature ] = nfdv1alpha1.InstanceFeatureSet {Elements : nv }
116
122
}
117
123
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
+
118
131
klog .V (3 ).InfoS ("discovered features" , "featureSource" , s .Name (), "features" , utils .DelayedDumper (s .features ))
119
132
120
133
return nil
@@ -179,6 +192,57 @@ func detectNv() ([]nfdv1alpha1.InstanceFeature, error) {
179
192
return info , nil
180
193
}
181
194
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
+ for _ , entry := range subdirs {
212
+ if ! entry .IsDir () {
213
+ continue
214
+ }
215
+
216
+ totalPages , err := getHugePagesTotalCount (basePath , entry .Name ())
217
+ if err != nil {
218
+ klog .ErrorS (err , "unable to read hugepages total count" , "hugepages" , entry .Name ())
219
+ }
220
+ pageSize := strings .TrimRight (strings .TrimPrefix (entry .Name (), "hugepages-" ), "kB" )
221
+ quantity , err := resource .ParseQuantity (pageSize + "Ki" )
222
+ if err != nil {
223
+ klog .ErrorS (err , "unable to parse quantity" , "hugepages" , entry .Name (), "pageSize" , pageSize )
224
+ continue
225
+ }
226
+
227
+ hugePages [corev1 .ResourceHugePagesPrefix + quantity .String ()] = totalPages
228
+ if v , err := strconv .Atoi (totalPages ); err == nil && v > 0 {
229
+ hugePages ["enabled" ] = "true"
230
+ }
231
+ }
232
+
233
+ return hugePages , nil
234
+ }
235
+
236
+ func getHugePagesTotalCount (basePath , dirname string ) (string , error ) {
237
+ totalPagesFile := filepath .Join (basePath , dirname , "nr_hugepages" )
238
+ totalPages , err := os .ReadFile (totalPagesFile )
239
+ if err != nil {
240
+ return "" , fmt .Errorf ("unable to read total number of huge pages from the file: %s" , totalPagesFile )
241
+ }
242
+
243
+ return strings .TrimSpace (string (totalPages )), nil
244
+ }
245
+
182
246
// ndDevAttrs is the list of sysfs files (under each nd device) that we're trying to read
183
247
var ndDevAttrs = []string {"devtype" , "mode" }
184
248
0 commit comments