pub const MaximumNumaSockets: usize = RTE_MAX_NUMA_NODES;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Serialize, Deserialize)]
pub struct NumaSocketId(u8);
impl AnyNumaSocketId for NumaSocketId
{
#[inline(always)]
fn isAny(&self) -> bool
{
false
}
#[inline(always)]
fn as_c_int(&self) -> c_int
{
self.0 as c_int
}
#[inline(always)]
fn as_c_uint(&self) -> c_uint
{
self.0 as u32
}
#[inline(always)]
fn as_int32_t(&self) -> int32_t
{
self.0 as int32_t
}
}
#[inline(always)]
fn typeOfMemoryX(typeOfMemory: Option<ConstCStr>) -> *const c_char
{
if typeOfMemory.is_none()
{
null()
}
else
{
typeOfMemory.unwrap().as_ptr()
}
}
impl NumaSocketId
{
pub const SocketZeroAlwaysExists: NumaSocketId = NumaSocketId(0);
pub const Any: Option<NumaSocketId> = None;
#[inline(always)]
pub fn numaNodesData(sysPath: &Path) -> Result<Option<NumaNodesData>, ListParseError>
{
let nodesPath = Self::nodesSysPath(sysPath);
if !nodesPath.is_dir()
{
return Ok(None);
}
fn parse(nodesPath: &Path, item: &str) -> Result<NumaSocketsActive, ListParseError>
{
let mut nodesItemPath = PathBuf::from(nodesPath);
nodesItemPath.push(item);
NumaSocketsActive::parseFromFilePath(&nodesItemPath)
}
let nodesPath = &nodesPath;
Ok
(
Some
(
NumaNodesData
{
hasCpu: parse(nodesPath, "has_cpu")?,
hasMemory: parse(nodesPath, "has_memory")?,
hasNormalMemory: parse(nodesPath, "has_normal_memory")?,
online: parse(nodesPath, "online")?,
possible: parse(nodesPath, "possible")?,
}
)
)
}
pub fn numaStatistics(&self, sysPath: &Path) -> io::Result<NumaNodeStatistics>
{
self.statisticListParse(sysPath, "numastat")
}
pub fn virtualMemoryPageUsageStatistics(&self, sysPath: &Path) -> io::Result<NumaNodeStatistics>
{
self.statisticListParse(sysPath, "vmstat")
}
pub fn meminfo(&self, sysPath: &Path) -> Result<MemoryStatistics, MemoryStatisticsParseError>
{
let folderPath = self.nodeSysPath(sysPath);
MemoryStatistics::parse(&folderPath, &format!("Node {} ", self.0))
}
pub fn cpuList(&self, sysPath: &Path) -> Result<LogicalCoresActive, ListParseError>
{
let filePath = self.itemPath(sysPath, "cpulist");
LogicalCoresActive::parseFromFilePath(&filePath)
}
pub fn distance(&self, sysPath: &Path) -> io::Result<u8>
{
let filePath = self.itemPath(sysPath, "distance");
readValueFromFile(&filePath)
}
pub fn numberOfHugePages(&self, sysPath: &Path, hugePageSize: HugePageSize) -> io::Result<u64>
{
let filePath = self.numberOfHugePagesFilePath(sysPath, hugePageSize);
readValueFromFile(&filePath)
}
pub fn numberOfFreeHugePages(&self, sysPath: &Path, hugePageSize: HugePageSize) -> io::Result<u64>
{
let filePath = self.hugepagesPath(sysPath, hugePageSize, "free_hugepages");
readValueFromFile(&filePath)
}
pub fn numberOfSurplusHugePages(&self, sysPath: &Path, hugePageSize: HugePageSize) -> io::Result<u64>
{
let filePath = self.hugepagesPath(sysPath, hugePageSize, "surplus_hugepages");
readValueFromFile(&filePath)
}
pub fn tryToCompact(&self, sysPath: &Path) -> io::Result<()>
{
assertEffectiveUserIsRoot(&format!("Compact NUMA node '{}'", self.0));
let path = self.itemPath(sysPath, "compact");
writeValueToFile(&path, 1)
}
pub fn tryToEvictPages(&self, sysPath: &Path) -> io::Result<()>
{
assertEffectiveUserIsRoot(&format!("Evict pages on NUMA node '{}'", self.0));
let path = self.itemPath(sysPath, "scan_unevictable_pages");
writeValueToFile(&path, 1)
}
pub fn tryToClearAllHugePagesReserved(&self, sysPath: &Path, hugePageSize: HugePageSize) -> io::Result<()>
{
assertEffectiveUserIsRoot(&format!("Clear all huge pages of size '{:?}' reserved on NUMA node '{}'", hugePageSize, self.0));
self.tryToReserveHugePages(sysPath, hugePageSize, 0)
}
pub fn tryToReserveHugePages(&self, sysPath: &Path, hugePageSize: HugePageSize, count: u64) -> io::Result<()>
{
assertEffectiveUserIsRoot(&format!("Reserve '{}' huge pages of size '{:?}' reserved on NUMA node '{}'", count, hugePageSize, self.0));
let filePath = self.numberOfHugePagesFilePath(sysPath, hugePageSize);
writeValueToFile(&filePath, count)
}
fn statisticListParse(&self, sysPath: &Path, statisticsFileName: &str) -> io::Result<NumaNodeStatistics>
{
let path = self.itemPath(sysPath, statisticsFileName);
let openFile = File::open(path)?;
let mut reader = BufReader::with_capacity(4096, openFile);
let mut numaNodeStatistics = NumaNodeStatistics::with_capacity(6);
let mut lineCount = 0;
let mut line = String::with_capacity(64);
while reader.read_line(&mut line)? > 0
{
{
let mut split = line.splitn(2, ' ');
let numaNodeStatisticName = NumaNodeStatisticName::parse(split.next().unwrap());
let statisticValue = match split.next()
{
None => return Err(io::Error::new(ErrorKind::InvalidData, format!("Zero based line '{}' does not have a value second column", lineCount))),
Some(value) =>
{
match value.parse::<u64>()
{
Err(parseError) => return Err(io::Error::new(ErrorKind::InvalidData, parseError)),
Ok(value) => value,
}
}
};
if let Some(previous) = numaNodeStatistics.insert(numaNodeStatisticName, statisticValue)
{
return Err(io::Error::new(ErrorKind::InvalidData, format!("Zero based line '{}' has a duplicate statistic (was '{}')", lineCount, previous)))
}
}
line.clear();
lineCount += 1;
}
Ok(numaNodeStatistics)
}
fn numberOfHugePagesFilePath(&self, sysPath: &Path, hugePageSize: HugePageSize) -> PathBuf
{
self.hugepagesPath(sysPath, hugePageSize, "nr_hugepages")
}
#[inline(always)]
fn nodesSysPath(sysPath: &Path) -> PathBuf
{
let mut nodesSysPath = PathBuf::from(sysPath);
nodesSysPath.push("devices/system/node");
nodesSysPath
}
#[inline(always)]
fn nodesItemSysPath(sysPath: &Path, item: &str) -> PathBuf
{
let mut nodesItemSysPath = Self::nodesSysPath(sysPath);
nodesItemSysPath.push(item);
nodesItemSysPath
}
#[inline(always)]
fn nodeSysPath(&self, sysPath: &Path) -> PathBuf
{
Self::nodesItemSysPath(sysPath, &format!("node{}", self.0))
}
#[inline(always)]
fn itemPath(&self, sysPath: &Path, item: &str) -> PathBuf
{
let mut path = self.nodeSysPath(sysPath);
path.push(item);
path
}
#[inline(always)]
fn hugepagesPath(&self, sysPath: &Path, hugePageSize: HugePageSize, item: &str) -> PathBuf
{
self.itemPath(sysPath, &format!("hugepages/hugepages-{}kB/{}", hugePageSize.size(), item.to_owned()))
}
#[inline(always)]
pub fn findInstalledNumberOfNumaSockets() -> usize
{
let mut currentMaximum = NumaSocketId::SocketZeroAlwaysExists;
for logicalCoreIdentifier in 0..(MaximumLogicalCores as u32)
{
if let Some(numaSocketId) = LogicalCore(logicalCoreIdentifier).optionalNumaSocketId()
{
if numaSocketId > currentMaximum
{
currentMaximum = numaSocketId;
}
}
}
(currentMaximum.0 + 1) as usize
}
#[inline(always)]
pub fn choose<'a, V>(&'a self, from: &'a [V; MaximumNumaSockets]) -> &V
{
&from[self.0 as usize]
}
#[inline(always)]
pub fn getSocketStatistics(&self) -> rte_malloc_socket_stats
{
let mut statistics = unsafe { uninitialized() };
let result = unsafe { ::dpdk_sys::rte_malloc_get_socket_stats(self.as_c_int(), &mut statistics) };
if likely(result == 0)
{
statistics
}
else
{
forget(statistics);
panic!("rte_malloc_get_socket_stats() returned '{}'", result);
}
}
#[inline(always)]
pub fn dumpAllocationStatisticsToStandardError(typeOfMemory: Option<ConstCStr>)
{
unsafe { ::dpdk_sys::rte_malloc_dump_stats(stderr as *mut FILE, typeOfMemoryX(typeOfMemory)) }
}
#[inline(always)]
pub fn forCurrentLogicalCore() -> Option<NumaSocketId>
{
Self::fromU32(unsafe { ::dpdk_sys::rte_socket_id() })
}
#[inline(always)]
pub fn fromI32(value: i32) -> Option<NumaSocketId>
{
if unlikely(value == SOCKET_ID_ANY)
{
None
}
else
{
Self::fromU32(value as u32)
}
}
#[inline(always)]
pub fn fromU32(value: u32) -> Option<NumaSocketId>
{
debug_assert!(value <= MaximumNumaSockets as u32, "value '{}' is equal to or exceeds MaximumNumaSockets, '{}'", value, MaximumNumaSockets);
Some(NumaSocketId(value as u8))
}
#[inline(always)]
pub fn as_u8(&self) -> u8
{
self.0
}
#[inline(always)]
pub fn as_usize(&self) -> usize
{
self.0 as usize
}
}