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.
This commit is contained in:
Lennart Poettering 2012-05-04 00:13:20 +02:00
parent 37099707e2
commit 6de338a2d9
4 changed files with 114 additions and 8 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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");