From b2d1d95ef4b0812aca631d11c2b08946c73203c8 Mon Sep 17 00:00:00 2001 From: Peter Schiffer Date: Tue, 30 Apr 2013 15:09:33 +0200 Subject: Hardware: Added additional information to the Memory provider Added information: * detect NUMA layout * standard memory page size * all supported sizes of huge memory pages * current state of transparent huge pages --- mof/60_LMI_Hardware.mof | 20 +++++++ src/hardware/LMI_MemoryProvider.c | 25 +++++++++ src/hardware/dmidecode.c | 4 +- src/hardware/sysfs.c | 107 +++++++++++++++++++++++++++++++++++++- src/hardware/sysfs.h | 36 ++++++++++++- 5 files changed, 188 insertions(+), 4 deletions(-) diff --git a/mof/60_LMI_Hardware.mof b/mof/60_LMI_Hardware.mof index 63c1a74..cba6459 100644 --- a/mof/60_LMI_Hardware.mof +++ b/mof/60_LMI_Hardware.mof @@ -169,6 +169,26 @@ class LMI_ProcessorChipRealizes: CIM_Realizes [ Provider("cmpi:cmpiLMI_Memory") ] class LMI_Memory: CIM_Memory { + [ Description("Indicates whether memory has NUMA layout.") ] + boolean HasNUMA; + + [ Description("Standard memory page size in kB."), + Units("Kilobytes"), PUnit("kilobyte")] + uint32 StandardMemoryPageSize; + + [ Description("All supported huge memory page sizes in currently " + "running kernel in kB."), + Units("Kilobytes"), PUnit("kilobyte")] + uint32 SupportedHugeMemoryPageSizes[]; + + [ Description ("Current state of the transparent huge memory pages. The " + "state can be \"Unsupported\", what means that the feature is not " + "available on the system, \"Never\" when the feature is disabled, " + "\"Madvise\" when huge pages are used only in marked memory area or " + "\"Always\" when this feature is used all the time. "), + ValueMap { "0", "1", "2", "3" }, + Values { "Unsupported", "Never", "Madvise", "Always" } ] + uint16 TransparentHugeMemoryPageStatus; }; [ Provider("cmpi:cmpiLMI_PhysicalMemory") ] diff --git a/src/hardware/LMI_MemoryProvider.c b/src/hardware/LMI_MemoryProvider.c index 0d77c17..4f2ab7f 100644 --- a/src/hardware/LMI_MemoryProvider.c +++ b/src/hardware/LMI_MemoryProvider.c @@ -19,11 +19,15 @@ */ #include +#include +#include +#include #include "LMI_Memory.h" #include "LMI_Hardware.h" #include "globals.h" #include "dmidecode.h" #include "procfs.h" +#include "sysfs.h" static const CMPIBroker* _cb = NULL; @@ -59,8 +63,10 @@ static CMPIStatus LMI_MemoryEnumInstances( LMI_Memory lmi_mem; const char *ns = KNameSpace(cop), *name = "System Memory"; char *error_msg = NULL; + long page_size; unsigned long fallback_memory_size = 0; DmiMemory dmi_memory; + unsigned i, *huge_page_sizes = NULL, huge_page_sizes_nb; if (dmi_get_memory(&dmi_memory) != 0) { fallback_memory_size = meminfo_get_memory_size(); @@ -70,6 +76,9 @@ static CMPIStatus LMI_MemoryEnumInstances( } } + page_size = sysconf(_SC_PAGESIZE); + sysfs_get_sizes_of_hugepages(&huge_page_sizes, &huge_page_sizes_nb); + LMI_Memory_Init(&lmi_mem, _cb, ns); LMI_Memory_Set_SystemCreationClassName(&lmi_mem, @@ -107,10 +116,26 @@ static CMPIStatus LMI_MemoryEnumInstances( LMI_Memory_Set_NumberOfBlocks(&lmi_mem, fallback_memory_size); } + LMI_Memory_Set_HasNUMA(&lmi_mem, sysfs_has_numa()); + if (page_size > 0) { + LMI_Memory_Set_StandardMemoryPageSize(&lmi_mem, page_size / 1024); + } + if (huge_page_sizes_nb > 0) { + LMI_Memory_Init_SupportedHugeMemoryPageSizes(&lmi_mem, + huge_page_sizes_nb); + for (i = 0; i < huge_page_sizes_nb; i++) { + LMI_Memory_Set_SupportedHugeMemoryPageSizes(&lmi_mem, i, + huge_page_sizes[i]); + } + } + LMI_Memory_Set_TransparentHugeMemoryPageStatus(&lmi_mem, + sysfs_get_transparent_hugepages_status()); + KReturnInstance(cr, lmi_mem); done: dmi_free_memory(&dmi_memory); + free(huge_page_sizes); if (error_msg) { KReturn2(_cb, ERR_FAILED, error_msg); diff --git a/src/hardware/dmidecode.c b/src/hardware/dmidecode.c index f034b56..dfff7e3 100644 --- a/src/hardware/dmidecode.c +++ b/src/hardware/dmidecode.c @@ -439,7 +439,7 @@ void dmi_free_processors(DmiProcessor **cpus, unsigned *cpus_nb) free((*cpus)[i].part_number); (*cpus)[i].part_number = NULL; } - free (*cpus); + free(*cpus); } *cpus_nb = 0; @@ -686,7 +686,7 @@ void dmi_free_cpu_caches(DmiCpuCache **caches, unsigned *caches_nb) free((*caches)[i].associativity); (*caches)[i].associativity = NULL; } - free (*caches); + free(*caches); } *caches_nb = 0; diff --git a/src/hardware/sysfs.c b/src/hardware/sysfs.c index d07df71..80d360e 100644 --- a/src/hardware/sysfs.c +++ b/src/hardware/sysfs.c @@ -149,11 +149,11 @@ short sysfs_get_cpu_caches(SysfsCpuCache **caches, unsigned *caches_nb) short ret = -1; unsigned i, level; char *buf = NULL, *format_str, path[PATH_MAX]; - DIR *dir; *caches_nb = 0; /* count caches */ + DIR *dir; char *cache_dir = SYSFS_CPU_PATH "/cpu0/cache"; dir = opendir(cache_dir); if (!dir) { @@ -285,3 +285,108 @@ void sysfs_free_cpu_caches(SysfsCpuCache **caches, unsigned *caches_nb) *caches_nb = 0; *caches = NULL; } + +short sysfs_has_numa() +{ + struct stat st; + + if (stat(SYSFS_PATH "/node/node0", &st) == 0) { + return 1; + } + + return 0; +} + +short sysfs_get_sizes_of_hugepages(unsigned **sizes, unsigned *sizes_nb) +{ + short ret = -1; + DIR *dir; + + *sizes_nb = 0; + *sizes = NULL; + + /* count all sizes */ + char *sizes_dir = SYSFS_KERNEL_MM "/hugepages"; + dir = opendir(sizes_dir); + if (!dir) { + warn("Failed to read directory: \"%s\"; Error: %s", + sizes_dir, strerror(errno)); + ret = -2; + goto done; + } + while (readdir(dir)) { + (*sizes_nb)++; + } + + /* do not count . and .. */ + *sizes_nb -= 2; + + /* if no size was found */ + if (*sizes_nb < 1) { + warn("Looks like kernel doesn't support huge memory pages."); + ret = -3; + goto done; + } + + /* allocate memory for sizes */ + *sizes = (unsigned *)calloc(*sizes_nb, sizeof(unsigned)); + if (!(*sizes)) { + warn("Failed to allocate memory."); + ret = -4; + goto done; + } + + /* get sizes */ + struct dirent *d; + unsigned i = 0; + rewinddir(dir); + while ((d = readdir(dir)) && i < *sizes_nb) { + if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0) { + continue; + } + if (strlen(d->d_name) > 11) { + /* read page size from the dirname, which looks like: hugepages-2048kB */ + if (sscanf(d->d_name + 10, "%u", &(*sizes)[i]) == 1) { + i++; + } + } + } + + ret = 0; + +done: + if (dir) { + closedir(dir); + } + + if (ret != 0) { + *sizes_nb = 0; + free(*sizes); + *sizes = NULL; + } + + return ret; +} + +ThpStatus sysfs_get_transparent_hugepages_status() +{ + ThpStatus ret = thp_unsupported; + char *val = NULL; + + if (path_get_string(SYSFS_KERNEL_MM "/transparent_hugepage/enabled", &val) != 0) { + goto done; + } + + if (strstr(val, "[always]")) { + ret = thp_always; + } else if (strstr(val, "[madvise]")) { + ret = thp_madvise; + } else if (strstr(val, "[never]")) { + ret = thp_never; + } + +done: + free(val); + + return ret; +} diff --git a/src/hardware/sysfs.h b/src/hardware/sysfs.h index 028b559..297a1a7 100644 --- a/src/hardware/sysfs.h +++ b/src/hardware/sysfs.h @@ -27,9 +27,23 @@ #include #include #include +#include +#include #include "utils.h" -#define SYSFS_CPU_PATH "/sys/devices/system/cpu" +#define SYSFS_PATH "/sys/devices/system" +#define SYSFS_CPU_PATH SYSFS_PATH "/cpu" +#define SYSFS_KERNEL_MM "/sys/kernel/mm" + + +/* Transparent memory huge pages statuses. */ +typedef enum _ThpStatus { + thp_unsupported = 0, + thp_never, + thp_madvise, + thp_always +} ThpStatus; + /* Processor cache from sysfs. */ typedef struct _SysfsCpuCache { @@ -59,5 +73,25 @@ short sysfs_get_cpu_caches(SysfsCpuCache **caches, unsigned *caches_nb); */ void sysfs_free_cpu_caches(SysfsCpuCache **caches, unsigned *caches_nb); +/* + * Detects whether system has NUMA memory layout. + * @return 0 if no, 1 if yes + */ +short sysfs_has_numa(); + +/* + * Get all supported sizes of memory huge pages in kB + * @param sizes array of all supported sizes if huge pages + * @param sizes_nb number of items in array + * @return 0 if success, negative value otherwise + */ +short sysfs_get_sizes_of_hugepages(unsigned **sizes, unsigned *sizes_nb); + +/* + * Get current status of transparent memory huge pages. + * @return ThpStatus + */ +ThpStatus sysfs_get_transparent_hugepages_status(); + #endif /* SYSFS_H_ */ -- cgit