aboutsummaryrefslogtreecommitdiff
path: root/tests/testutils.c
diff options
context:
space:
mode:
authorAdam Litke <agl@us.ibm.com>2008-08-26 15:34:06 +0000
committerAdam Litke <agl@us.ibm.com>2008-08-26 15:34:06 +0000
commit30a7d5cb19a593a246b1da2f6dd36ff84ace9903 (patch)
tree5f26215ff5fbab8c55d1a94eeb28cd54f4952830 /tests/testutils.c
parent4a8289569ec2a0d164158ea45898cef57ebfcaa2 (diff)
downloadlibhugetlbfs-30a7d5cb19a593a246b1da2f6dd36ff84ace9903.tar.gz
tests: Make functions to read/set counters values multi-pagesize aware
Many test cases read or set the size of the hugetlb pool or are interested in other pool counters (such as the number of pages reserved). When the kernel supported only one huge page size, /proc/meminfo contained definitive information about the hugetlb pool and /proc/sys/vm/nr_hugepages was used to change the size of the pool. These locations only control the pool for the kernel's default huge page size. The configuration for other page sizes must be done via sysfs. This new complexity can be abstracted by an interface that can get and set pool counters. To maintain backwards compatibility with kernels that have only /proc interfaces, when working with the kernel default huge page size we continue to use /proc. For other sizes, use sysfs. Signed-off-by: Adam Litke <agl@us.ibm.com>
Diffstat (limited to 'tests/testutils.c')
-rw-r--r--tests/testutils.c156
1 files changed, 136 insertions, 20 deletions
diff --git a/tests/testutils.c b/tests/testutils.c
index 927e790..9aa6c3d 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -47,7 +47,7 @@ char *test_name;
void check_free_huge_pages(int nr_pages_needed)
{
- int freepages = read_meminfo("HugePages_Free:");
+ int freepages = get_pool_counter(HUGEPAGES_FREE, 0);
if (freepages < nr_pages_needed)
CONFIG("Must have at least %i free hugepages", nr_pages_needed);
}
@@ -205,8 +205,30 @@ int test_addr_huge(void *p)
return (sb.f_type == HUGETLBFS_MAGIC);
}
-/* XXX: Copied from hugeutils.c. Need to figure out how to share this */
-long read_meminfo(const char *tag)
+struct hugetlb_pool_counter_info_t hugetlb_counter_info[] = {
+ [HUGEPAGES_TOTAL] = {
+ .meminfo_key = "HugePages_Total:",
+ .sysfs_file = "nr_hugepages",
+ },
+ [HUGEPAGES_FREE] = {
+ .meminfo_key = "HugePages_Free:",
+ .sysfs_file = "free_hugepages",
+ },
+ [HUGEPAGES_RSVD] = {
+ .meminfo_key = "HugePages_Rsvd:",
+ .sysfs_file = "resv_hugepages",
+ },
+ [HUGEPAGES_SURP] = {
+ .meminfo_key = "HugePages_Surp:",
+ .sysfs_file = "surplus_hugepages",
+ },
+ [HUGEPAGES_OC] = {
+ .meminfo_key = NULL,
+ .sysfs_file = "nr_overcommit_hugepages"
+ },
+};
+
+long file_read_ulong(char *file, const char *tag)
{
int fd;
char buf[MEMINFO_SZ];
@@ -214,9 +236,9 @@ long read_meminfo(const char *tag)
char *p, *q;
long val;
- fd = open("/proc/meminfo", O_RDONLY);
+ fd = open(file, O_RDONLY);
if (fd < 0) {
- ERROR("Couldn't open /proc/meminfo: %s\n", strerror(errno));
+ ERROR("Couldn't open %s: %s\n", file, strerror(errno));
return -1;
}
@@ -224,29 +246,122 @@ long read_meminfo(const char *tag)
readerr = errno;
close(fd);
if (len < 0) {
- ERROR("Error reading /proc/meminfo: %s\n", strerror(readerr));
+ ERROR("Error reading %s: %s\n", file, strerror(errno));
return -1;
}
if (len == sizeof(buf)) {
- ERROR("/proc/meminfo is too large\n");
+ ERROR("%s is too large\n", file);
return -1;
}
buf[len] = '\0';
- p = strstr(buf, tag);
- if (!p)
- return -1; /* looks like the line we want isn't there */
+ /* Search for a tag if provided */
+ if (tag) {
+ p = strstr(buf, tag);
+ if (!p)
+ return -1; /* looks like the line we want isn't there */
+ p += strlen(tag);
+ } else
+ p = buf;
- p += strlen(tag);
val = strtol(p, &q, 0);
if (! isspace(*q)) {
- ERROR("Couldn't parse /proc/meminfo value\n");
+ ERROR("Couldn't parse %s value\n", file);
return -1;
}
return val;
}
+int file_write_ulong(char *file, unsigned long val)
+{
+ FILE *f;
+ int ret;
+
+ f = fopen(file, "w");
+ if (!f) {
+ ERROR("Couldn't open %s: %s\n", file, strerror(errno));
+ return -1;
+ }
+
+ ret = fprintf(f, "%lu", val);
+ fclose(f);
+ return ret > 0 ? 0 : -1;
+}
+
+int select_pool_counter(unsigned int counter, unsigned long pagesize_kb,
+ char *filename, char **key)
+{
+ long default_size;
+ char *meminfo_key;
+ char *sysfs_file;
+
+ if (counter >= HUGEPAGES_MAX_COUNTERS) {
+ ERROR("Invalid counter specified\n");
+ return -1;
+ }
+
+ meminfo_key = hugetlb_counter_info[counter].meminfo_key;
+ sysfs_file = hugetlb_counter_info[counter].sysfs_file;
+ if (key)
+ *key = NULL;
+
+ /*
+ * Get the meminfo page size.
+ * This could be made more efficient if utility functions were shared
+ * between libhugetlbfs and the test suite. For now we will just
+ * read /proc/meminfo.
+ */
+ default_size = file_read_ulong("/proc/meminfo", "Hugepagesize:");
+ if (default_size < 0) {
+ ERROR("Cannot determine the default page size\n");
+ return -1;
+ }
+
+ /* Convert a pagesize_kb of 0 to the libhugetlbfs default size */
+ if (pagesize_kb == 0)
+ pagesize_kb = gethugepagesize() / 1024;
+
+ /* If the user is dealing in the default page size, we can use /proc */
+ if (pagesize_kb == default_size) {
+ if (meminfo_key && key) {
+ strcpy(filename, "/proc/meminfo");
+ *key = meminfo_key;
+ } else
+ sprintf(filename, "/proc/sys/vm/%s", sysfs_file);
+ } else /* Use the sysfs interface */
+ sprintf(filename, "/sys/kernel/mm/hugepages/hugepages-%lukB/%s",
+ pagesize_kb, sysfs_file);
+ return 0;
+}
+
+long get_pool_counter(unsigned int counter, unsigned long pagesize_kb)
+{
+ char file[PATH_MAX+1];
+ char *key;
+
+ if (select_pool_counter(counter, pagesize_kb, file, &key))
+ return -1;
+
+ return file_read_ulong(file, key);
+}
+
+int set_pool_counter(unsigned int counter, unsigned long val,
+ unsigned long pagesize_kb)
+{
+ char file[PATH_MAX+1];
+
+ if (select_pool_counter(counter, pagesize_kb, file, NULL))
+ return -1;
+
+ return file_write_ulong(file, val);
+}
+
+long read_meminfo(const char *tag)
+{
+ return file_read_ulong("/proc/meminfo", tag);
+}
+
ino_t get_addr_inode(void *p)
{
char name[256];
@@ -303,10 +418,11 @@ int kernel_has_private_reservations(int fd)
void *map;
/* Read pool counters */
- t = read_meminfo("HugePages_Total:");
- f = read_meminfo("HugePages_Free:");
- r = read_meminfo("HugePages_Rsvd:");
- s = read_meminfo("HugePages_Surp:");
+ t = get_pool_counter(HUGEPAGES_TOTAL, 0);
+ f = get_pool_counter(HUGEPAGES_FREE, 0);
+ r = get_pool_counter(HUGEPAGES_RSVD, 0);
+ s = get_pool_counter(HUGEPAGES_SURP, 0);
+
if (fd < 0) {
ERROR("kernel_has_private_reservations: hugetlbfs_unlinked_fd: "
@@ -321,10 +437,10 @@ int kernel_has_private_reservations(int fd)
}
/* Recheck the counters */
- nt = read_meminfo("HugePages_Total:");
- nf = read_meminfo("HugePages_Free:");
- nr = read_meminfo("HugePages_Rsvd:");
- ns = read_meminfo("HugePages_Surp:");
+ nt = get_pool_counter(HUGEPAGES_TOTAL, 0);
+ nf = get_pool_counter(HUGEPAGES_FREE, 0);
+ nr = get_pool_counter(HUGEPAGES_RSVD, 0);
+ ns = get_pool_counter(HUGEPAGES_SURP, 0);
munmap(map, gethugepagesize());