From 6de338a2d9904ef5a67552b024491700523074a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 4 May 2012 00:13:20 +0200 Subject: readhead: temporarily lower the kernel's read_ahead_kb setting while collecting While collecting readahead data we want to know exactly what userspace accesses unblurred by the kernel's read_ahead_kb. Hence lower this during collection, and raise it afterwards. This is mostly based on ideas and code by Auke Kok. --- src/readahead/readahead-collect.c | 33 +++++++++++++--- src/readahead/readahead-common.c | 82 ++++++++++++++++++++++++++++++++++++++- src/readahead/readahead-common.h | 5 ++- src/readahead/readahead-replay.c | 2 +- 4 files changed, 114 insertions(+), 8 deletions(-) (limited to 'src/readahead') diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c index 008ede3964..70e0f66eda 100644 --- a/src/readahead/readahead-collect.c +++ b/src/readahead/readahead-collect.c @@ -233,9 +233,26 @@ static int collect(const char *root) { bool on_ssd, on_btrfs; struct statfs sfs; usec_t not_after; + uint64_t previous_block_readahead; + bool previous_block_readahead_set = false; assert(root); + if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { + log_error("Out of memory"); + r = -ENOMEM; + goto finish; + } + + /* If there's no pack file yet we lower the kernel readahead + * so that mincore() is accurate. If there is a pack file + * already we assume it is accurate enough so that kernel + * readahead is never triggered. */ + previous_block_readahead_set = + access(pack_fn, F_OK) < 0 && + block_get_readahead(root, &previous_block_readahead) >= 0 && + block_set_readahead(root, 8*1024) >= 0; + write_one_line_file("/proc/self/oom_score_adj", "1000"); if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0) @@ -458,10 +475,7 @@ done: on_btrfs = statfs(root, &sfs) >= 0 && (long) sfs.f_type == (long) BTRFS_SUPER_MAGIC; log_debug("On btrfs: %s", yes_no(on_btrfs)); - asprintf(&pack_fn, "%s/.readahead", root); - asprintf(&pack_fn_new, "%s/.readahead.new", root); - - if (!pack_fn || !pack_fn_new) { + if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) { log_error("Out of memory"); r = -ENOMEM; goto finish; @@ -551,7 +565,6 @@ finish: fclose(pack); unlink(pack_fn_new); } - free(pack_fn_new); free(pack_fn); @@ -560,6 +573,16 @@ finish: hashmap_free(files); + if (previous_block_readahead_set) { + uint64_t bytes; + + /* Restore the original kernel readahead setting if we + * changed it, and nobody has overwritten it since + * yet. */ + if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024) + block_set_readahead(root, previous_block_readahead); + } + return r; } diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c index 4e8e636975..99dbac2525 100644 --- a/src/readahead/readahead-common.c +++ b/src/readahead/readahead-common.c @@ -210,7 +210,7 @@ finish: #define BUMP_REQUEST_NR (16*1024) -int bump_request_nr(const char *p) { +int block_bump_request_nr(const char *p) { struct stat st; uint64_t u; char *ap = NULL, *line = NULL; @@ -267,3 +267,83 @@ finish: return r; } + +int block_get_readahead(const char *p, uint64_t *bytes) { + struct stat st; + char *ap = NULL, *line = NULL; + int r; + dev_t d; + uint64_t u; + + assert(p); + assert(bytes); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) + return 0; + + d = st.st_dev; + block_get_whole_disk(d, &d); + + if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { + r = -ENOMEM; + goto finish; + } + + r = read_one_line_file(ap, &line); + if (r < 0) + goto finish; + + r = safe_atou64(line, &u); + if (r < 0) + goto finish; + + *bytes = u * 1024ULL; + +finish: + free(ap); + free(line); + + return r; +} + +int block_set_readahead(const char *p, uint64_t bytes) { + struct stat st; + char *ap = NULL, *line = NULL; + int r; + dev_t d; + + assert(p); + assert(bytes); + + if (stat(p, &st) < 0) + return -errno; + + if (major(st.st_dev) == 0) + return 0; + + d = st.st_dev; + block_get_whole_disk(d, &d); + + if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) { + r = -ENOMEM; + goto finish; + } + + if (asprintf(&line, "%llu", (unsigned long long) bytes / 1024ULL) < 0) { + r = -ENOMEM; + goto finish; + } + + r = write_one_line_file(ap, line); + if (r < 0) + goto finish; + +finish: + free(ap); + free(line); + + return r; +} diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h index b4eab71b1a..9962dd527a 100644 --- a/src/readahead/readahead-common.h +++ b/src/readahead/readahead-common.h @@ -45,6 +45,9 @@ typedef struct ReadaheadShared { ReadaheadShared *shared_get(void); -int bump_request_nr(const char *p); +int block_bump_request_nr(const char *p); + +int block_get_readahead(const char *p, uint64_t *bytes); +int block_set_readahead(const char *p, uint64_t bytes); #endif diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c index f91020e805..0b7e6df946 100644 --- a/src/readahead/readahead-replay.c +++ b/src/readahead/readahead-replay.c @@ -133,7 +133,7 @@ static int replay(const char *root) { assert(root); write_one_line_file("/proc/self/oom_score_adj", "1000"); - bump_request_nr(root); + block_bump_request_nr(root); if (asprintf(&pack_fn, "%s/.readahead", root) < 0) { log_error("Out of memory"); -- cgit v1.2.3-54-g00ecf