lkml.org 
[lkml]   [2023]   [Nov]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RESEND PATCH v7 06/10] selftests/mm: Factor out thp settings management
    Date
    The khugepaged test has a useful framework for save/restore/pop/push of
    all thp settings via the sysfs interface. This will be useful to
    explicitly control small-sized THP settings in other tests, so let's
    move it out of khugepaged and into its own thp_settings.[c|h] utility.

    Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
    ---
    tools/testing/selftests/mm/Makefile | 4 +-
    tools/testing/selftests/mm/khugepaged.c | 346 ++--------------------
    tools/testing/selftests/mm/thp_settings.c | 296 ++++++++++++++++++
    tools/testing/selftests/mm/thp_settings.h | 71 +++++
    4 files changed, 391 insertions(+), 326 deletions(-)
    create mode 100644 tools/testing/selftests/mm/thp_settings.c
    create mode 100644 tools/testing/selftests/mm/thp_settings.h

    diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
    index 78dfec8bc676..a3eb20c186e7 100644
    --- a/tools/testing/selftests/mm/Makefile
    +++ b/tools/testing/selftests/mm/Makefile
    @@ -117,8 +117,8 @@ TEST_FILES += va_high_addr_switch.sh

    include ../lib.mk

    -$(TEST_GEN_PROGS): vm_util.c
    -$(TEST_GEN_FILES): vm_util.c
    +$(TEST_GEN_PROGS): vm_util.c thp_settings.c
    +$(TEST_GEN_FILES): vm_util.c thp_settings.c

    $(OUTPUT)/uffd-stress: uffd-common.c
    $(OUTPUT)/uffd-unit-tests: uffd-common.c
    diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c
    index fc47a1c4944c..b15e7fd70176 100644
    --- a/tools/testing/selftests/mm/khugepaged.c
    +++ b/tools/testing/selftests/mm/khugepaged.c
    @@ -22,13 +22,13 @@
    #include "linux/magic.h"

    #include "vm_util.h"
    +#include "thp_settings.h"

    #define BASE_ADDR ((void *)(1UL << 30))
    static unsigned long hpage_pmd_size;
    static unsigned long page_size;
    static int hpage_pmd_nr;

    -#define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/"
    #define PID_SMAPS "/proc/self/smaps"
    #define TEST_FILE "collapse_test_file"

    @@ -71,78 +71,7 @@ struct file_info {
    };

    static struct file_info finfo;
    -
    -enum thp_enabled {
    - THP_ALWAYS,
    - THP_MADVISE,
    - THP_NEVER,
    -};
    -
    -static const char *thp_enabled_strings[] = {
    - "always",
    - "madvise",
    - "never",
    - NULL
    -};
    -
    -enum thp_defrag {
    - THP_DEFRAG_ALWAYS,
    - THP_DEFRAG_DEFER,
    - THP_DEFRAG_DEFER_MADVISE,
    - THP_DEFRAG_MADVISE,
    - THP_DEFRAG_NEVER,
    -};
    -
    -static const char *thp_defrag_strings[] = {
    - "always",
    - "defer",
    - "defer+madvise",
    - "madvise",
    - "never",
    - NULL
    -};
    -
    -enum shmem_enabled {
    - SHMEM_ALWAYS,
    - SHMEM_WITHIN_SIZE,
    - SHMEM_ADVISE,
    - SHMEM_NEVER,
    - SHMEM_DENY,
    - SHMEM_FORCE,
    -};
    -
    -static const char *shmem_enabled_strings[] = {
    - "always",
    - "within_size",
    - "advise",
    - "never",
    - "deny",
    - "force",
    - NULL
    -};
    -
    -struct khugepaged_settings {
    - bool defrag;
    - unsigned int alloc_sleep_millisecs;
    - unsigned int scan_sleep_millisecs;
    - unsigned int max_ptes_none;
    - unsigned int max_ptes_swap;
    - unsigned int max_ptes_shared;
    - unsigned long pages_to_scan;
    -};
    -
    -struct settings {
    - enum thp_enabled thp_enabled;
    - enum thp_defrag thp_defrag;
    - enum shmem_enabled shmem_enabled;
    - bool use_zero_page;
    - struct khugepaged_settings khugepaged;
    - unsigned long read_ahead_kb;
    -};
    -
    -static struct settings saved_settings;
    static bool skip_settings_restore;
    -
    static int exit_status;

    static void success(const char *msg)
    @@ -161,226 +90,13 @@ static void skip(const char *msg)
    printf(" \e[33m%s\e[0m\n", msg);
    }

    -static int read_file(const char *path, char *buf, size_t buflen)
    -{
    - int fd;
    - ssize_t numread;
    -
    - fd = open(path, O_RDONLY);
    - if (fd == -1)
    - return 0;
    -
    - numread = read(fd, buf, buflen - 1);
    - if (numread < 1) {
    - close(fd);
    - return 0;
    - }
    -
    - buf[numread] = '\0';
    - close(fd);
    -
    - return (unsigned int) numread;
    -}
    -
    -static int write_file(const char *path, const char *buf, size_t buflen)
    -{
    - int fd;
    - ssize_t numwritten;
    -
    - fd = open(path, O_WRONLY);
    - if (fd == -1) {
    - printf("open(%s)\n", path);
    - exit(EXIT_FAILURE);
    - return 0;
    - }
    -
    - numwritten = write(fd, buf, buflen - 1);
    - close(fd);
    - if (numwritten < 1) {
    - printf("write(%s)\n", buf);
    - exit(EXIT_FAILURE);
    - return 0;
    - }
    -
    - return (unsigned int) numwritten;
    -}
    -
    -static int read_string(const char *name, const char *strings[])
    -{
    - char path[PATH_MAX];
    - char buf[256];
    - char *c;
    - int ret;
    -
    - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    - if (ret >= PATH_MAX) {
    - printf("%s: Pathname is too long\n", __func__);
    - exit(EXIT_FAILURE);
    - }
    -
    - if (!read_file(path, buf, sizeof(buf))) {
    - perror(path);
    - exit(EXIT_FAILURE);
    - }
    -
    - c = strchr(buf, '[');
    - if (!c) {
    - printf("%s: Parse failure\n", __func__);
    - exit(EXIT_FAILURE);
    - }
    -
    - c++;
    - memmove(buf, c, sizeof(buf) - (c - buf));
    -
    - c = strchr(buf, ']');
    - if (!c) {
    - printf("%s: Parse failure\n", __func__);
    - exit(EXIT_FAILURE);
    - }
    - *c = '\0';
    -
    - ret = 0;
    - while (strings[ret]) {
    - if (!strcmp(strings[ret], buf))
    - return ret;
    - ret++;
    - }
    -
    - printf("Failed to parse %s\n", name);
    - exit(EXIT_FAILURE);
    -}
    -
    -static void write_string(const char *name, const char *val)
    -{
    - char path[PATH_MAX];
    - int ret;
    -
    - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    - if (ret >= PATH_MAX) {
    - printf("%s: Pathname is too long\n", __func__);
    - exit(EXIT_FAILURE);
    - }
    -
    - if (!write_file(path, val, strlen(val) + 1)) {
    - perror(path);
    - exit(EXIT_FAILURE);
    - }
    -}
    -
    -static const unsigned long _read_num(const char *path)
    -{
    - char buf[21];
    -
    - if (read_file(path, buf, sizeof(buf)) < 0) {
    - perror("read_file(read_num)");
    - exit(EXIT_FAILURE);
    - }
    -
    - return strtoul(buf, NULL, 10);
    -}
    -
    -static const unsigned long read_num(const char *name)
    -{
    - char path[PATH_MAX];
    - int ret;
    -
    - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    - if (ret >= PATH_MAX) {
    - printf("%s: Pathname is too long\n", __func__);
    - exit(EXIT_FAILURE);
    - }
    - return _read_num(path);
    -}
    -
    -static void _write_num(const char *path, unsigned long num)
    -{
    - char buf[21];
    -
    - sprintf(buf, "%ld", num);
    - if (!write_file(path, buf, strlen(buf) + 1)) {
    - perror(path);
    - exit(EXIT_FAILURE);
    - }
    -}
    -
    -static void write_num(const char *name, unsigned long num)
    -{
    - char path[PATH_MAX];
    - int ret;
    -
    - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    - if (ret >= PATH_MAX) {
    - printf("%s: Pathname is too long\n", __func__);
    - exit(EXIT_FAILURE);
    - }
    - _write_num(path, num);
    -}
    -
    -static void write_settings(struct settings *settings)
    -{
    - struct khugepaged_settings *khugepaged = &settings->khugepaged;
    -
    - write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
    - write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
    - write_string("shmem_enabled",
    - shmem_enabled_strings[settings->shmem_enabled]);
    - write_num("use_zero_page", settings->use_zero_page);
    -
    - write_num("khugepaged/defrag", khugepaged->defrag);
    - write_num("khugepaged/alloc_sleep_millisecs",
    - khugepaged->alloc_sleep_millisecs);
    - write_num("khugepaged/scan_sleep_millisecs",
    - khugepaged->scan_sleep_millisecs);
    - write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
    - write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
    - write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
    - write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
    -
    - if (file_ops && finfo.type == VMA_FILE)
    - _write_num(finfo.dev_queue_read_ahead_path,
    - settings->read_ahead_kb);
    -}
    -
    -#define MAX_SETTINGS_DEPTH 4
    -static struct settings settings_stack[MAX_SETTINGS_DEPTH];
    -static int settings_index;
    -
    -static struct settings *current_settings(void)
    -{
    - if (!settings_index) {
    - printf("Fail: No settings set");
    - exit(EXIT_FAILURE);
    - }
    - return settings_stack + settings_index - 1;
    -}
    -
    -static void push_settings(struct settings *settings)
    -{
    - if (settings_index >= MAX_SETTINGS_DEPTH) {
    - printf("Fail: Settings stack exceeded");
    - exit(EXIT_FAILURE);
    - }
    - settings_stack[settings_index++] = *settings;
    - write_settings(current_settings());
    -}
    -
    -static void pop_settings(void)
    -{
    - if (settings_index <= 0) {
    - printf("Fail: Settings stack empty");
    - exit(EXIT_FAILURE);
    - }
    - --settings_index;
    - write_settings(current_settings());
    -}
    -
    static void restore_settings_atexit(void)
    {
    if (skip_settings_restore)
    return;

    printf("Restore THP and khugepaged settings...");
    - write_settings(&saved_settings);
    + thp_restore_settings();
    success("OK");

    skip_settings_restore = true;
    @@ -395,27 +111,9 @@ static void restore_settings(int sig)
    static void save_settings(void)
    {
    printf("Save THP and khugepaged settings...");
    - saved_settings = (struct settings) {
    - .thp_enabled = read_string("enabled", thp_enabled_strings),
    - .thp_defrag = read_string("defrag", thp_defrag_strings),
    - .shmem_enabled =
    - read_string("shmem_enabled", shmem_enabled_strings),
    - .use_zero_page = read_num("use_zero_page"),
    - };
    - saved_settings.khugepaged = (struct khugepaged_settings) {
    - .defrag = read_num("khugepaged/defrag"),
    - .alloc_sleep_millisecs =
    - read_num("khugepaged/alloc_sleep_millisecs"),
    - .scan_sleep_millisecs =
    - read_num("khugepaged/scan_sleep_millisecs"),
    - .max_ptes_none = read_num("khugepaged/max_ptes_none"),
    - .max_ptes_swap = read_num("khugepaged/max_ptes_swap"),
    - .max_ptes_shared = read_num("khugepaged/max_ptes_shared"),
    - .pages_to_scan = read_num("khugepaged/pages_to_scan"),
    - };
    if (file_ops && finfo.type == VMA_FILE)
    - saved_settings.read_ahead_kb =
    - _read_num(finfo.dev_queue_read_ahead_path);
    + thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path);
    + thp_save_settings();

    success("OK");

    @@ -798,7 +496,7 @@ static void __madvise_collapse(const char *msg, char *p, int nr_hpages,
    struct mem_ops *ops, bool expect)
    {
    int ret;
    - struct settings settings = *current_settings();
    + struct thp_settings settings = *thp_current_settings();

    printf("%s...", msg);

    @@ -808,7 +506,7 @@ static void __madvise_collapse(const char *msg, char *p, int nr_hpages,
    */
    settings.thp_enabled = THP_NEVER;
    settings.shmem_enabled = SHMEM_NEVER;
    - push_settings(&settings);
    + thp_push_settings(&settings);

    /* Clear VM_NOHUGEPAGE */
    madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE);
    @@ -820,7 +518,7 @@ static void __madvise_collapse(const char *msg, char *p, int nr_hpages,
    else
    success("OK");

    - pop_settings();
    + thp_pop_settings();
    }

    static void madvise_collapse(const char *msg, char *p, int nr_hpages,
    @@ -850,13 +548,13 @@ static bool wait_for_scan(const char *msg, char *p, int nr_hpages,
    madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE);

    /* Wait until the second full_scan completed */
    - full_scans = read_num("khugepaged/full_scans") + 2;
    + full_scans = thp_read_num("khugepaged/full_scans") + 2;

    printf("%s...", msg);
    while (timeout--) {
    if (ops->check_huge(p, nr_hpages))
    break;
    - if (read_num("khugepaged/full_scans") >= full_scans)
    + if (thp_read_num("khugepaged/full_scans") >= full_scans)
    break;
    printf(".");
    usleep(TICK);
    @@ -911,11 +609,11 @@ static bool is_tmpfs(struct mem_ops *ops)

    static void alloc_at_fault(void)
    {
    - struct settings settings = *current_settings();
    + struct thp_settings settings = *thp_current_settings();
    char *p;

    settings.thp_enabled = THP_ALWAYS;
    - push_settings(&settings);
    + thp_push_settings(&settings);

    p = alloc_mapping(1);
    *p = 1;
    @@ -925,7 +623,7 @@ static void alloc_at_fault(void)
    else
    fail("Fail");

    - pop_settings();
    + thp_pop_settings();

    madvise(p, page_size, MADV_DONTNEED);
    printf("Split huge PMD on MADV_DONTNEED...");
    @@ -973,11 +671,11 @@ static void collapse_single_pte_entry(struct collapse_context *c, struct mem_ops
    static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *ops)
    {
    int max_ptes_none = hpage_pmd_nr / 2;
    - struct settings settings = *current_settings();
    + struct thp_settings settings = *thp_current_settings();
    void *p;

    settings.khugepaged.max_ptes_none = max_ptes_none;
    - push_settings(&settings);
    + thp_push_settings(&settings);

    p = ops->setup_area(1);

    @@ -1002,7 +700,7 @@ static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *o
    }
    skip:
    ops->cleanup_area(p, hpage_pmd_size);
    - pop_settings();
    + thp_pop_settings();
    }

    static void collapse_swapin_single_pte(struct collapse_context *c, struct mem_ops *ops)
    @@ -1033,7 +731,7 @@ static void collapse_swapin_single_pte(struct collapse_context *c, struct mem_op

    static void collapse_max_ptes_swap(struct collapse_context *c, struct mem_ops *ops)
    {
    - int max_ptes_swap = read_num("khugepaged/max_ptes_swap");
    + int max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap");
    void *p;

    p = ops->setup_area(1);
    @@ -1250,11 +948,11 @@ static void collapse_fork_compound(struct collapse_context *c, struct mem_ops *o
    fail("Fail");
    ops->fault(p, 0, page_size);

    - write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1);
    + thp_write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1);
    c->collapse("Collapse PTE table full of compound pages in child",
    p, 1, ops, true);
    - write_num("khugepaged/max_ptes_shared",
    - current_settings()->khugepaged.max_ptes_shared);
    + thp_write_num("khugepaged/max_ptes_shared",
    + thp_current_settings()->khugepaged.max_ptes_shared);

    validate_memory(p, 0, hpage_pmd_size);
    ops->cleanup_area(p, hpage_pmd_size);
    @@ -1275,7 +973,7 @@ static void collapse_fork_compound(struct collapse_context *c, struct mem_ops *o

    static void collapse_max_ptes_shared(struct collapse_context *c, struct mem_ops *ops)
    {
    - int max_ptes_shared = read_num("khugepaged/max_ptes_shared");
    + int max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared");
    int wstatus;
    void *p;

    @@ -1443,7 +1141,7 @@ static void parse_test_type(int argc, const char **argv)

    int main(int argc, const char **argv)
    {
    - struct settings default_settings = {
    + struct thp_settings default_settings = {
    .thp_enabled = THP_MADVISE,
    .thp_defrag = THP_DEFRAG_ALWAYS,
    .shmem_enabled = SHMEM_ADVISE,
    @@ -1484,7 +1182,7 @@ int main(int argc, const char **argv)
    default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8;

    save_settings();
    - push_settings(&default_settings);
    + thp_push_settings(&default_settings);

    alloc_at_fault();

    diff --git a/tools/testing/selftests/mm/thp_settings.c b/tools/testing/selftests/mm/thp_settings.c
    new file mode 100644
    index 000000000000..5e8ec792cac7
    --- /dev/null
    +++ b/tools/testing/selftests/mm/thp_settings.c
    @@ -0,0 +1,296 @@
    +// SPDX-License-Identifier: GPL-2.0
    +#include <fcntl.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "thp_settings.h"
    +
    +#define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/"
    +#define MAX_SETTINGS_DEPTH 4
    +static struct thp_settings settings_stack[MAX_SETTINGS_DEPTH];
    +static int settings_index;
    +static struct thp_settings saved_settings;
    +static char dev_queue_read_ahead_path[PATH_MAX];
    +
    +static const char * const thp_enabled_strings[] = {
    + "always",
    + "madvise",
    + "never",
    + NULL
    +};
    +
    +static const char * const thp_defrag_strings[] = {
    + "always",
    + "defer",
    + "defer+madvise",
    + "madvise",
    + "never",
    + NULL
    +};
    +
    +static const char * const shmem_enabled_strings[] = {
    + "always",
    + "within_size",
    + "advise",
    + "never",
    + "deny",
    + "force",
    + NULL
    +};
    +
    +int read_file(const char *path, char *buf, size_t buflen)
    +{
    + int fd;
    + ssize_t numread;
    +
    + fd = open(path, O_RDONLY);
    + if (fd == -1)
    + return 0;
    +
    + numread = read(fd, buf, buflen - 1);
    + if (numread < 1) {
    + close(fd);
    + return 0;
    + }
    +
    + buf[numread] = '\0';
    + close(fd);
    +
    + return (unsigned int) numread;
    +}
    +
    +int write_file(const char *path, const char *buf, size_t buflen)
    +{
    + int fd;
    + ssize_t numwritten;
    +
    + fd = open(path, O_WRONLY);
    + if (fd == -1) {
    + printf("open(%s)\n", path);
    + exit(EXIT_FAILURE);
    + return 0;
    + }
    +
    + numwritten = write(fd, buf, buflen - 1);
    + close(fd);
    + if (numwritten < 1) {
    + printf("write(%s)\n", buf);
    + exit(EXIT_FAILURE);
    + return 0;
    + }
    +
    + return (unsigned int) numwritten;
    +}
    +
    +const unsigned long read_num(const char *path)
    +{
    + char buf[21];
    +
    + if (read_file(path, buf, sizeof(buf)) < 0) {
    + perror("read_file()");
    + exit(EXIT_FAILURE);
    + }
    +
    + return strtoul(buf, NULL, 10);
    +}
    +
    +void write_num(const char *path, unsigned long num)
    +{
    + char buf[21];
    +
    + sprintf(buf, "%ld", num);
    + if (!write_file(path, buf, strlen(buf) + 1)) {
    + perror(path);
    + exit(EXIT_FAILURE);
    + }
    +}
    +
    +int thp_read_string(const char *name, const char * const strings[])
    +{
    + char path[PATH_MAX];
    + char buf[256];
    + char *c;
    + int ret;
    +
    + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    + if (ret >= PATH_MAX) {
    + printf("%s: Pathname is too long\n", __func__);
    + exit(EXIT_FAILURE);
    + }
    +
    + if (!read_file(path, buf, sizeof(buf))) {
    + perror(path);
    + exit(EXIT_FAILURE);
    + }
    +
    + c = strchr(buf, '[');
    + if (!c) {
    + printf("%s: Parse failure\n", __func__);
    + exit(EXIT_FAILURE);
    + }
    +
    + c++;
    + memmove(buf, c, sizeof(buf) - (c - buf));
    +
    + c = strchr(buf, ']');
    + if (!c) {
    + printf("%s: Parse failure\n", __func__);
    + exit(EXIT_FAILURE);
    + }
    + *c = '\0';
    +
    + ret = 0;
    + while (strings[ret]) {
    + if (!strcmp(strings[ret], buf))
    + return ret;
    + ret++;
    + }
    +
    + printf("Failed to parse %s\n", name);
    + exit(EXIT_FAILURE);
    +}
    +
    +void thp_write_string(const char *name, const char *val)
    +{
    + char path[PATH_MAX];
    + int ret;
    +
    + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    + if (ret >= PATH_MAX) {
    + printf("%s: Pathname is too long\n", __func__);
    + exit(EXIT_FAILURE);
    + }
    +
    + if (!write_file(path, val, strlen(val) + 1)) {
    + perror(path);
    + exit(EXIT_FAILURE);
    + }
    +}
    +
    +const unsigned long thp_read_num(const char *name)
    +{
    + char path[PATH_MAX];
    + int ret;
    +
    + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    + if (ret >= PATH_MAX) {
    + printf("%s: Pathname is too long\n", __func__);
    + exit(EXIT_FAILURE);
    + }
    + return read_num(path);
    +}
    +
    +void thp_write_num(const char *name, unsigned long num)
    +{
    + char path[PATH_MAX];
    + int ret;
    +
    + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
    + if (ret >= PATH_MAX) {
    + printf("%s: Pathname is too long\n", __func__);
    + exit(EXIT_FAILURE);
    + }
    + write_num(path, num);
    +}
    +
    +void thp_read_settings(struct thp_settings *settings)
    +{
    + *settings = (struct thp_settings) {
    + .thp_enabled = thp_read_string("enabled", thp_enabled_strings),
    + .thp_defrag = thp_read_string("defrag", thp_defrag_strings),
    + .shmem_enabled =
    + thp_read_string("shmem_enabled", shmem_enabled_strings),
    + .use_zero_page = thp_read_num("use_zero_page"),
    + };
    + settings->khugepaged = (struct khugepaged_settings) {
    + .defrag = thp_read_num("khugepaged/defrag"),
    + .alloc_sleep_millisecs =
    + thp_read_num("khugepaged/alloc_sleep_millisecs"),
    + .scan_sleep_millisecs =
    + thp_read_num("khugepaged/scan_sleep_millisecs"),
    + .max_ptes_none = thp_read_num("khugepaged/max_ptes_none"),
    + .max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"),
    + .max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared"),
    + .pages_to_scan = thp_read_num("khugepaged/pages_to_scan"),
    + };
    + if (dev_queue_read_ahead_path[0])
    + settings->read_ahead_kb = read_num(dev_queue_read_ahead_path);
    +}
    +
    +void thp_write_settings(struct thp_settings *settings)
    +{
    + struct khugepaged_settings *khugepaged = &settings->khugepaged;
    +
    + thp_write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
    + thp_write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
    + thp_write_string("shmem_enabled",
    + shmem_enabled_strings[settings->shmem_enabled]);
    + thp_write_num("use_zero_page", settings->use_zero_page);
    +
    + thp_write_num("khugepaged/defrag", khugepaged->defrag);
    + thp_write_num("khugepaged/alloc_sleep_millisecs",
    + khugepaged->alloc_sleep_millisecs);
    + thp_write_num("khugepaged/scan_sleep_millisecs",
    + khugepaged->scan_sleep_millisecs);
    + thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
    + thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
    + thp_write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
    + thp_write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
    +
    + if (dev_queue_read_ahead_path[0])
    + write_num(dev_queue_read_ahead_path, settings->read_ahead_kb);
    +}
    +
    +struct thp_settings *thp_current_settings(void)
    +{
    + if (!settings_index) {
    + printf("Fail: No settings set");
    + exit(EXIT_FAILURE);
    + }
    + return settings_stack + settings_index - 1;
    +}
    +
    +void thp_push_settings(struct thp_settings *settings)
    +{
    + if (settings_index >= MAX_SETTINGS_DEPTH) {
    + printf("Fail: Settings stack exceeded");
    + exit(EXIT_FAILURE);
    + }
    + settings_stack[settings_index++] = *settings;
    + thp_write_settings(thp_current_settings());
    +}
    +
    +void thp_pop_settings(void)
    +{
    + if (settings_index <= 0) {
    + printf("Fail: Settings stack empty");
    + exit(EXIT_FAILURE);
    + }
    + --settings_index;
    + thp_write_settings(thp_current_settings());
    +}
    +
    +void thp_restore_settings(void)
    +{
    + thp_write_settings(&saved_settings);
    +}
    +
    +void thp_save_settings(void)
    +{
    + thp_read_settings(&saved_settings);
    +}
    +
    +void thp_set_read_ahead_path(char *path)
    +{
    + if (!path) {
    + dev_queue_read_ahead_path[0] = '\0';
    + return;
    + }
    +
    + strncpy(dev_queue_read_ahead_path, path,
    + sizeof(dev_queue_read_ahead_path));
    + dev_queue_read_ahead_path[sizeof(dev_queue_read_ahead_path) - 1] = '\0';
    +}
    diff --git a/tools/testing/selftests/mm/thp_settings.h b/tools/testing/selftests/mm/thp_settings.h
    new file mode 100644
    index 000000000000..ff3d98c30617
    --- /dev/null
    +++ b/tools/testing/selftests/mm/thp_settings.h
    @@ -0,0 +1,71 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +#ifndef __THP_SETTINGS_H__
    +#define __THP_SETTINGS_H__
    +
    +#include <stdbool.h>
    +#include <stddef.h>
    +#include <stdint.h>
    +
    +enum thp_enabled {
    + THP_ALWAYS,
    + THP_MADVISE,
    + THP_NEVER,
    +};
    +
    +enum thp_defrag {
    + THP_DEFRAG_ALWAYS,
    + THP_DEFRAG_DEFER,
    + THP_DEFRAG_DEFER_MADVISE,
    + THP_DEFRAG_MADVISE,
    + THP_DEFRAG_NEVER,
    +};
    +
    +enum shmem_enabled {
    + SHMEM_ALWAYS,
    + SHMEM_WITHIN_SIZE,
    + SHMEM_ADVISE,
    + SHMEM_NEVER,
    + SHMEM_DENY,
    + SHMEM_FORCE,
    +};
    +
    +struct khugepaged_settings {
    + bool defrag;
    + unsigned int alloc_sleep_millisecs;
    + unsigned int scan_sleep_millisecs;
    + unsigned int max_ptes_none;
    + unsigned int max_ptes_swap;
    + unsigned int max_ptes_shared;
    + unsigned long pages_to_scan;
    +};
    +
    +struct thp_settings {
    + enum thp_enabled thp_enabled;
    + enum thp_defrag thp_defrag;
    + enum shmem_enabled shmem_enabled;
    + bool use_zero_page;
    + struct khugepaged_settings khugepaged;
    + unsigned long read_ahead_kb;
    +};
    +
    +int read_file(const char *path, char *buf, size_t buflen);
    +int write_file(const char *path, const char *buf, size_t buflen);
    +const unsigned long read_num(const char *path);
    +void write_num(const char *path, unsigned long num);
    +
    +int thp_read_string(const char *name, const char * const strings[]);
    +void thp_write_string(const char *name, const char *val);
    +const unsigned long thp_read_num(const char *name);
    +void thp_write_num(const char *name, unsigned long num);
    +
    +void thp_write_settings(struct thp_settings *settings);
    +void thp_read_settings(struct thp_settings *settings);
    +struct thp_settings *thp_current_settings(void);
    +void thp_push_settings(struct thp_settings *settings);
    +void thp_pop_settings(void);
    +void thp_restore_settings(void);
    +void thp_save_settings(void);
    +
    +void thp_set_read_ahead_path(char *path);
    +
    +#endif /* __THP_SETTINGS_H__ */
    --
    2.25.1
    \
     
     \ /
      Last update: 2023-11-22 17:31    [W:4.251 / U:0.272 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site