[PATCH v4 01/14] virhostmem: Introduce virHostMemGetTHPSize()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



New virHostMemGetTHPSize() is introduced which allows caller to
obtain THP PMD (Page Middle Directory) size, which is equal to
the minimal size that THP can use, taken from kernel doc
(Documentation/admin-guide/mm/transhuge.rst):

  Some userspace (such as a test program, or an optimized memory allocation
  library) may want to know the size (in bytes) of a transparent hugepage::

    cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size

Since this size depends on the host architecture and the kernel
it won't change whilst libvirtd is running. Therefore, we can use
virOnce() and cache the value. Of course, we can be running under
kernel that has THP disabled or has no notion of THP at all. In
that case a negative value is returned to signal error.

Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx>
---
 src/libvirt_private.syms |  1 +
 src/util/virhostmem.c    | 54 ++++++++++++++++++++++++++++++++++++++++
 src/util/virhostmem.h    |  3 +++
 tests/domaincapsmock.c   |  9 +++++++
 4 files changed, 67 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 68e4b6aab8..19f0d0ddc8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2393,6 +2393,7 @@ virHostMemGetFreePages;
 virHostMemGetInfo;
 virHostMemGetParameters;
 virHostMemGetStats;
+virHostMemGetTHPSize;
 virHostMemSetParameters;
 
 
diff --git a/src/util/virhostmem.c b/src/util/virhostmem.c
index 8aa675cb4f..7de87d92ae 100644
--- a/src/util/virhostmem.c
+++ b/src/util/virhostmem.c
@@ -45,11 +45,14 @@
 #include "virstring.h"
 #include "virnuma.h"
 #include "virlog.h"
+#include "virthread.h"
 
 #define VIR_FROM_THIS VIR_FROM_NONE
 
 VIR_LOG_INIT("util.hostmem");
 
+static unsigned long long virHostTHPPMDSize; /* in kibibytes */
+static virOnceControl virHostMemGetTHPSizeOnce = VIR_ONCE_CONTROL_INITIALIZER;
 
 #ifdef __FreeBSD__
 # define BSD_MEMORY_STATS_ALL 4
@@ -918,3 +921,54 @@ virHostMemAllocPages(unsigned int npages,
 
     return ncounts;
 }
+
+#if defined(__linux__)
+# define HPAGE_PMD_SIZE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
+static void
+virHostMemGetTHPSizeSysfs(unsigned long long *size)
+{
+    if (virFileReadValueUllong(size, "%s", HPAGE_PMD_SIZE_PATH) < 0) {
+        VIR_WARN("unable to get THP PMD size: %s", g_strerror(errno));
+        return;
+    }
+
+    /* Size is now in bytes. Convert to KiB. */
+    *size >>= 10;
+}
+#endif /* defined(__linux__) */
+
+
+static void
+virHostMemGetTHPSizeOnceInit(void)
+{
+#if defined(__linux__)
+    virHostMemGetTHPSizeSysfs(&virHostTHPPMDSize);
+#else /* !defined(__linux__) */
+    VIR_WARN("Getting THP size not ported yet");
+#endif /* !defined(__linux__) */
+}
+
+
+/**
+ * virHostMemGetTHPSize:
+ * @size: returned size of THP in kibibytes
+ *
+ * Obtain Transparent Huge Page size in kibibytes. The size
+ * depends on host architecture and kernel. Because of virOnce(),
+ * do not rely on errno in case of failure.
+ *
+ * Returns: 0 on success,
+ *         -1 on failure.
+ */
+int
+virHostMemGetTHPSize(unsigned long long *size)
+{
+    if (virOnce(&virHostMemGetTHPSizeOnce, virHostMemGetTHPSizeOnceInit) < 0)
+        return -1;
+
+    if (virHostTHPPMDSize == 0)
+        return -1;
+
+    *size = virHostTHPPMDSize;
+    return 0;
+}
diff --git a/src/util/virhostmem.h b/src/util/virhostmem.h
index 1369829807..bf15c40698 100644
--- a/src/util/virhostmem.h
+++ b/src/util/virhostmem.h
@@ -53,3 +53,6 @@ int virHostMemAllocPages(unsigned int npages,
                          int startCell,
                          unsigned int cellCount,
                          bool add);
+
+int virHostMemGetTHPSize(unsigned long long *size)
+    G_GNUC_NO_INLINE;
diff --git a/tests/domaincapsmock.c b/tests/domaincapsmock.c
index b03f75199b..aa5eb68547 100644
--- a/tests/domaincapsmock.c
+++ b/tests/domaincapsmock.c
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include "virhostcpu.h"
+#include "virhostmem.h"
 
 int
 virHostCPUGetKVMMaxVCPUs(void)
@@ -29,3 +30,11 @@ virHostCPUGetMicrocodeVersion(virArch hostArch G_GNUC_UNUSED)
 {
     return 0;
 }
+
+int
+virHostMemGetTHPSize(unsigned long long *size)
+{
+    /* Pretend Transparent Huge Page size is 2MiB. */
+    *size = 2048;
+    return 0;
+}
-- 
2.31.1




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux