summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile22
-rwxr-xr-xnureadahead-collect36
-rwxr-xr-xnureadahead-init30
-rw-r--r--nureadahead-preload.c38
5 files changed, 127 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..718456e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/nureadahead-preload
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..121272a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,22 @@
+CFLAGS ?= -O2 -s
+CFLAGS += -Wall -Wextra
+
+prefix = /usr/local
+sbindir = $(prefix)/sbin
+
+all: nureadahead-preload
+
+nureadahead-preload: nureadahead-preload.c
+ $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
+
+clean:
+ rm -f nureadahead-preload
+
+install: all
+ install -Dm755 nureadahead-collect $(DESTDIR)$(sbindir)
+ install -Dm755 nureadahead-collect-auto $(DESTDIR)$(sbindir)
+ install -Dm755 nureadahead-init $(DESTDIR)$(sbindir)
+ install -Dm755 nureadahead-merge $(DESTDIR)$(sbindir)
+ install -Dm755 nureadahead-preload $(DESTDIR)$(sbindir)
+
+.PHONY: all clean install
diff --git a/nureadahead-collect b/nureadahead-collect
new file mode 100755
index 0000000..9cf17fe
--- /dev/null
+++ b/nureadahead-collect
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: nureadahead-collect DEVICE TIMEOUT > file" >&2
+}
+
+case "$1" in
+ -*) usage; exit 1
+esac
+
+case "$#" in
+ 2) device=$1 timeout=$2;;
+ *) usage; exit 1
+esac
+
+awk_prog2='
+$1 <= end && $2 > end {
+ end = $2
+}
+$1 > end && NR != 1 {
+ print start " " end
+}
+$1 > end {
+ start = $1
+ end = $2
+}
+END {
+ print start " " end
+}
+'
+
+blktrace -a read -d "$1" -w "$timeout" -o - \
+ | blkparse -f "%a %d %e %n %S\n" -i - \
+ | awk '$1 == "C" && $2 ~ /R/ && $2 !~ /A/ && $3 == 0 { print $5 " " $5 + $4 - 1 }' \
+ | sort -n -k1,1 -k2,2 \
+ | awk "$awk_prog2"
diff --git a/nureadahead-init b/nureadahead-init
new file mode 100755
index 0000000..f8b315b
--- /dev/null
+++ b/nureadahead-init
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: nureadahead-init [FILE [TIMEOUT [INIT [ARGS...]]]]" >&2
+}
+
+case "$1" in
+ -*) usage; exit 1
+esac
+
+case "$#" in
+ 0) file=/.nureadahead timeout=120 init=init;;
+ 1) file=$1 timeout=120 init=init; shift 1;;
+ 2) file=$1 timeout=$2 init=init; shift 2;;
+ *) file=$1 timeout=$2 init=$3; shift 3;;
+esac
+
+export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+device=$(awk '$2 == "/" { d=$1 } END { print d }' < /proc/self/mounts)
+if [ -n "$device" ]; then
+ if [ -e "$file" ]; then
+ nureadahead-preload "$device" < "$file" &
+ else
+ echo "nureadahead-init: no file, skipping preload" >&2
+ fi
+ nureadahead-collect "$device" "$timeout" > "$file" &
+else
+ echo "nureadahead-init: cannot find root device, skipping preload + collect" >&2
+fi
+exec "$init" "$@"
diff --git a/nureadahead-preload.c b/nureadahead-preload.c
new file mode 100644
index 0000000..7d10df8
--- /dev/null
+++ b/nureadahead-preload.c
@@ -0,0 +1,38 @@
+#define _POSIX_C_SOURCE 200112L
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void usage() {
+ fputs("usage: nureadahead-preload DEVICE < file\n", stderr);
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 2 || argv[1][0] == '-' || argv[1][0] == '\0') {
+ usage();
+ exit(1);
+ }
+
+ int fd = open(argv[1], O_RDONLY);
+ if (fd == -1) {
+ perror("nureadahead-preload");
+ exit(1);
+ }
+
+ while (1) {
+ unsigned long long start, end;
+ switch (scanf("%llu %llu\n", &start, &end)) {
+ case 2:
+ if (posix_fadvise(fd, start * 512, (end - start + 1) * 512, POSIX_FADV_WILLNEED) == -1) {
+ perror("nureadahead-preload: readahead");
+ exit(1);
+ }
+ break;
+ case EOF:
+ exit(0);
+ default:
+ fputs("nureadahead-preload: invalid input\n", stderr);
+ }
+ }
+}