github.com/google/cadvisor@v0.49.1/nvm/machine_libipmctl.go (about) 1 //go:build libipmctl && cgo 2 // +build libipmctl,cgo 3 4 // Copyright 2020 Google Inc. All Rights Reserved. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 package nvm 19 20 // #cgo pkg-config: libipmctl 21 // #include <nvm_management.h> 22 import "C" 23 import ( 24 "fmt" 25 "sync" 26 27 info "github.com/google/cadvisor/info/v1" 28 29 "k8s.io/klog/v2" 30 ) 31 32 var ( 33 isNVMLibInitialized = false 34 nvmLibMutex = sync.Mutex{} 35 ) 36 37 func init() { 38 nvmLibMutex.Lock() 39 defer nvmLibMutex.Unlock() 40 cErr := C.nvm_init() 41 if cErr != C.NVM_SUCCESS { 42 // Unfortunately klog does not seem to work here. I believe it's better to 43 // output information using fmt rather then let it disappear silently. 44 fmt.Printf("libipmctl initialization failed with status %d", cErr) 45 return 46 } 47 isNVMLibInitialized = true 48 } 49 50 // getAvgPowerBudget retrieves configured power budget 51 // (in watts) for NVM devices. When libipmctl is not available 52 // zero is returned. 53 func getAvgPowerBudget() (uint, error) { 54 // Get number of devices on the platform 55 // see: https://github.com/intel/ipmctl/blob/v01.00.00.3497/src/os/nvm_api/nvm_management.h#L1478 56 count := C.uint(0) 57 err := C.nvm_get_number_of_devices(&count) 58 if err != C.NVM_SUCCESS { 59 klog.Warningf("Unable to get number of NVM devices. Status code: %d", err) 60 return uint(0), fmt.Errorf("Unable to get number of NVM devices. Status code: %d", err) 61 } 62 63 if count == 0 { 64 klog.V(4).Infof("There are no NVM devices.") 65 return uint(0), nil 66 } 67 68 // Load basic device information for all the devices 69 // to obtain UID of the first one. 70 devices := make([]C.struct_device_discovery, count) 71 err = C.nvm_get_devices(&devices[0], C.uchar(count)) 72 if err != C.NVM_SUCCESS { 73 klog.Warningf("Unable to get all NVM devices. Status code: %d", err) 74 return uint(0), fmt.Errorf("Unable to get all NVM devices. Status code: %d", err) 75 } 76 77 // Power budget is same for all the devices 78 // so we can rely on any of them. 79 device := C.struct_device_details{} 80 err = C.nvm_get_device_details(&devices[0].uid[0], &device) 81 if err != C.NVM_SUCCESS { 82 uid := C.GoString(&devices[0].uid[0]) 83 klog.Warningf("Unable to get details of NVM device %q. Status code: %d", uid, err) 84 return uint(0), fmt.Errorf("Unable to get details of NVM device %q. Status code: %d", uid, err) 85 } 86 87 return uint(device.avg_power_budget / 1000), nil 88 } 89 90 // getCapacities retrieves the total NVM capacity in bytes for memory mode and app direct mode 91 func getCapacities() (uint64, uint64, error) { 92 caps := C.struct_device_capacities{} 93 err := C.nvm_get_nvm_capacities(&caps) 94 if err != C.NVM_SUCCESS { 95 klog.Warningf("Unable to get NVM capacity. Status code: %d", err) 96 return uint64(0), uint64(0), fmt.Errorf("Unable to get NVM capacity. Status code: %d", err) 97 } 98 return uint64(caps.memory_capacity), uint64(caps.app_direct_capacity), nil 99 } 100 101 // GetInfo returns information specific for non-volatile memory modules 102 func GetInfo() (info.NVMInfo, error) { 103 nvmLibMutex.Lock() 104 defer nvmLibMutex.Unlock() 105 106 nvmInfo := info.NVMInfo{} 107 if !isNVMLibInitialized { 108 klog.V(1).Info("libipmctl has not been initialized. NVM information will not be available") 109 return nvmInfo, nil 110 } 111 112 var err error 113 nvmInfo.MemoryModeCapacity, nvmInfo.AppDirectModeCapacity, err = getCapacities() 114 if err != nil { 115 return info.NVMInfo{}, fmt.Errorf("Unable to get NVM capacities, err: %s", err) 116 } 117 118 nvmInfo.AvgPowerBudget, err = getAvgPowerBudget() 119 if err != nil { 120 return info.NVMInfo{}, fmt.Errorf("Unable to get NVM average power budget, err: %s", err) 121 } 122 return nvmInfo, nil 123 } 124 125 // Finalize un-initializes libipmctl. See https://github.com/google/cadvisor/issues/2457. 126 func Finalize() { 127 nvmLibMutex.Lock() 128 defer nvmLibMutex.Unlock() 129 130 klog.V(1).Info("Attempting to un-initialize libipmctl") 131 if !isNVMLibInitialized { 132 klog.V(1).Info("libipmctl has not been initialized; not un-initializing.") 133 return 134 } 135 136 C.nvm_uninit() 137 isNVMLibInitialized = false 138 }