diff mbox

[API-NEXT,07/13] linux-generic: system_info: adding huge page dir

Message ID 1471621724-8485-8-git-send-email-christophe.milard@linaro.org
State Superseded
Headers show

Commit Message

Christophe Milard Aug. 19, 2016, 3:48 p.m. UTC
The Huge page information is separated and a function to get the
huge page mount directory is added. This function is called at init
so the information is available later on.

Signed-off-by: Christophe Milard <christophe.milard@linaro.org>

---
 platform/linux-generic/include/odp_internal.h |   7 +-
 platform/linux-generic/odp_system_info.c      | 181 +++++++++++++++++++++++++-
 2 files changed, 184 insertions(+), 4 deletions(-)

-- 
2.7.4
diff mbox

Patch

diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h
index fd770b5..2b21777 100644
--- a/platform/linux-generic/include/odp_internal.h
+++ b/platform/linux-generic/include/odp_internal.h
@@ -30,7 +30,6 @@  extern __thread int __odp_errno;
 
 typedef struct {
 	uint64_t cpu_hz_max[MAX_CPU_NUMBER];
-	uint64_t default_huge_page_size;
 	uint64_t page_size;
 	int      cache_line_size;
 	int      cpu_count;
@@ -38,11 +37,17 @@  typedef struct {
 	char     model_str[MAX_CPU_NUMBER][128];
 } system_info_t;
 
+typedef struct {
+	uint64_t default_huge_page_size;
+	char     *default_huge_page_dir;
+} hugepage_info_t;
+
 struct odp_global_data_s {
 	pid_t main_pid;
 	odp_log_func_t log_fn;
 	odp_abort_func_t abort_fn;
 	system_info_t system_info;
+	hugepage_info_t hugepage_info;
 	odp_cpumask_t control_cpus;
 	odp_cpumask_t worker_cpus;
 	int num_cpus_installed;
diff --git a/platform/linux-generic/odp_system_info.c b/platform/linux-generic/odp_system_info.c
index bbe5358..18c61db 100644
--- a/platform/linux-generic/odp_system_info.c
+++ b/platform/linux-generic/odp_system_info.c
@@ -4,6 +4,13 @@ 
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ */
+
 #include <odp_posix_extensions.h>
 
 #include <odp/api/system_info.h>
@@ -11,11 +18,13 @@ 
 #include <odp_debug_internal.h>
 #include <odp/api/align.h>
 #include <odp/api/cpu.h>
+#include <errno.h>
 #include <pthread.h>
 #include <sched.h>
 #include <string.h>
 #include <stdio.h>
 #include <inttypes.h>
+#include <ctype.h>
 
 /* sysconf */
 #include <unistd.h>
@@ -97,6 +106,158 @@  static uint64_t default_huge_page_size(void)
 }
 
 /*
+ * split string into tokens. largely "inspired" by dpdk:
+ * lib/librte_eal/common/eal_common_string_fns.c: rte_strsplit
+ */
+static int strsplit(char *string, int stringlen,
+		    char **tokens, int maxtokens, char delim)
+{
+	int i, tok = 0;
+	int tokstart = 1; /* first token is right at start of string */
+
+	if (string == NULL || tokens == NULL)
+		return -1;
+
+	for (i = 0; i < stringlen; i++) {
+		if (string[i] == '\0' || tok >= maxtokens)
+			break;
+		if (tokstart) {
+			tokstart = 0;
+			tokens[tok++] = &string[i];
+		}
+		if (string[i] == delim) {
+			string[i] = '\0';
+			tokstart = 1;
+		}
+	}
+	return tok;
+}
+
+/*
+ * Converts a numeric string to the equivalent uint64_t value.
+ * As well as straight number conversion, also recognises the suffixes
+ * k, m and g for kilobytes, megabytes and gigabytes respectively.
+ *
+ * If a negative number is passed in  i.e. a string with the first non-black
+ * character being "-", zero is returned. Zero is also returned in the case of
+ * an error with the strtoull call in the function.
+ * largely "inspired" by dpdk:
+ * lib/librte_eal/common/include/rte_common.h: rte_str_to_size
+ *
+ * param str
+ *     String containing number to convert.
+ * return
+ *     Number.
+ */
+static inline uint64_t str_to_size(const char *str)
+{
+	char *endptr;
+	unsigned long long size;
+
+	while (isspace((int)*str))
+		str++;
+	if (*str == '-')
+		return 0;
+
+	errno = 0;
+	size = strtoull(str, &endptr, 0);
+	if (errno)
+		return 0;
+
+	if (*endptr == ' ')
+		endptr++; /* allow 1 space gap */
+
+	switch (*endptr) {
+	case 'G':
+	case 'g':
+		size *= 1024; /* fall-through */
+	case 'M':
+	case 'm':
+		size *= 1024; /* fall-through */
+	case 'K':
+	case 'k':
+		size *= 1024; /* fall-through */
+	default:
+		break;
+	}
+	return size;
+}
+
+/*
+ * returns a malloced string containing the name of the directory for
+ * huge pages of a given size (0 for default)
+ * largely "inspired" by dpdk:
+ * lib/librte_eal/linuxapp/eal/eal_hugepage_info.c: get_hugepage_dir
+ *
+ * Analysis of /proc/mounts
+ */
+static char *get_hugepage_dir(uint64_t hugepage_sz)
+{
+	enum proc_mount_fieldnames {
+		DEVICE = 0,
+		MOUNTPT,
+		FSTYPE,
+		OPTIONS,
+		_FIELDNAME_MAX
+	};
+	static uint64_t default_size;
+	const char proc_mounts[] = "/proc/mounts";
+	const char hugetlbfs_str[] = "hugetlbfs";
+	const size_t htlbfs_str_len = sizeof(hugetlbfs_str) - 1;
+	const char pagesize_opt[] = "pagesize=";
+	const size_t pagesize_opt_len = sizeof(pagesize_opt) - 1;
+	const char split_tok = ' ';
+	char *tokens[_FIELDNAME_MAX];
+	char buf[BUFSIZ];
+	char *retval = NULL;
+	const char *pagesz_str;
+	uint64_t pagesz;
+	FILE *fd = fopen(proc_mounts, "r");
+
+	if (fd == NULL)
+		return NULL;
+
+	if (default_size == 0)
+		default_size = default_huge_page_size();
+
+	if (hugepage_sz == 0)
+		hugepage_sz = default_size;
+
+	while (fgets(buf, sizeof(buf), fd)) {
+		if (strsplit(buf, sizeof(buf), tokens,
+			     _FIELDNAME_MAX, split_tok) != _FIELDNAME_MAX) {
+			ODP_ERR("Error parsing %s\n", proc_mounts);
+			break; /* return NULL */
+		}
+
+		/* is this hugetlbfs? */
+		if (!strncmp(tokens[FSTYPE], hugetlbfs_str, htlbfs_str_len)) {
+			pagesz_str = strstr(tokens[OPTIONS], pagesize_opt);
+
+			/* No explicit size, default page size is compared */
+			if (pagesz_str == NULL) {
+				if (hugepage_sz == default_size) {
+					retval = strdup(tokens[MOUNTPT]);
+					break;
+				}
+			}
+			/* there is an explicit page size, so check it */
+			else {
+				pagesz =
+				     str_to_size(&pagesz_str[pagesize_opt_len]);
+				if (pagesz == hugepage_sz) {
+					retval = strdup(tokens[MOUNTPT]);
+					break;
+				}
+			}
+		} /* end if strncmp hugetlbfs */
+	} /* end while fgets */
+
+	fclose(fd);
+	return retval;
+}
+
+/*
  * Analysis of /sys/devices/system/cpu/ files
  */
 static int systemcpu(system_info_t *sysinfo)
@@ -125,11 +286,21 @@  static int systemcpu(system_info_t *sysinfo)
 		return -1;
 	}
 
-	sysinfo->default_huge_page_size = default_huge_page_size();
-
 	return 0;
 }
 
+/*
+ * Huge page information
+ */
+static int system_hp(hugepage_info_t *hugeinfo)
+{
+	hugeinfo->default_huge_page_size = default_huge_page_size();
+
+	/* default_huge_page_dir may be NULL if no huge page support */
+	hugeinfo->default_huge_page_dir = get_hugepage_dir(0);
+
+	return 0;
+}
 
 /*
  * System info initialisation
@@ -157,6 +328,8 @@  int odp_system_info_init(void)
 		return -1;
 	}
 
+	system_hp(&odp_global_data.hugepage_info);
+
 	return 0;
 }
 
@@ -165,6 +338,8 @@  int odp_system_info_init(void)
  */
 int odp_system_info_term(void)
 {
+	free(odp_global_data.hugepage_info.default_huge_page_dir);
+
 	return 0;
 }
 
@@ -200,7 +375,7 @@  uint64_t odp_cpu_hz_max_id(int id)
 
 uint64_t odp_sys_huge_page_size(void)
 {
-	return odp_global_data.system_info.default_huge_page_size;
+	return odp_global_data.hugepage_info.default_huge_page_size;
 }
 
 uint64_t odp_sys_page_size(void)