Commit 7a2e24ef authored by Julius Plenz's avatar Julius Plenz

Merge branch 'n-times-fadvise'

* n-times-fadvise: Update man pages to reflect "-n" option Only do multi-fadvise if previous call was successful Add explanation of -n flag / NOCACHE_NR_FADVISE env variable Implement "-n <n>" flag for repeated posix_fadvise() There was a trivial-to-solve merge conflict in nocache.c
parents 9e2f973e a30e207a
...@@ -34,6 +34,8 @@ For testing purposes, I included two small tools: ...@@ -34,6 +34,8 @@ For testing purposes, I included two small tools:
* `cachedel` calls `posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)` on * `cachedel` calls `posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)` on
the file argument. Thus, if the file is not accessed by any other the file argument. Thus, if the file is not accessed by any other
application, the pages will be eradicated from the fs cache. application, the pages will be eradicated from the fs cache.
Specifying -n <number> will repeat the syscall the given number of
times which can be useful in some circumstances (see below).
* `cachestats` has three modes: In quiet mode (`-q`), the exit status * `cachestats` has three modes: In quiet mode (`-q`), the exit status
is 0 (success) if the file is fully cached. In normal mode, is 0 (success) if the file is fully cached. In normal mode,
the number of cached vs. not-cached pages is printed. In verbose the number of cached vs. not-cached pages is printed. In verbose
...@@ -94,9 +96,17 @@ There are timing issues to consider, as well. If you consider `nocache ...@@ -94,9 +96,17 @@ There are timing issues to consider, as well. If you consider `nocache
cat <file>`, in most (all?) cases the cache will not be restored. For cat <file>`, in most (all?) cases the cache will not be restored. For
discussion and possible solutions see <http://lwn.net/Articles/480930/>. discussion and possible solutions see <http://lwn.net/Articles/480930/>.
My experience showed that in many cases you could "fix" this by doing My experience showed that in many cases you could "fix" this by doing
the `posix_fadvise` call *twice*. If you want this behaviour, compile the `posix_fadvise` call *twice*. For both tools `nocache` and
the library using `make CFLAGS=-DDOUBLEFADVISE`. `cachedel` you can specify the number using `-n`, like so:
$ nocache -n 2 cat ~/file.mp3
This actually only sets the environment variable `NOCACHE_NR_FADVISE`
to the specified value, and the shared library reads out this value.
If test number 3 in `t/basic.t` fails, then try increasing this number
until it works, e.g.:
$ env NOCACHE_NR_FADVISE=2 make test
Acknowledgements Acknowledgements
---------------- ----------------
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <error.h> #include <error.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
int exiterr(const char *s) int exiterr(const char *s)
{ {
...@@ -13,30 +14,38 @@ int exiterr(const char *s) ...@@ -13,30 +14,38 @@ int exiterr(const char *s)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int i, n = 1;
int fd; int fd;
char *fn;
struct stat st; struct stat st;
if(argc != 2) { if(argc == 4 && !strcmp("-n", argv[1])) {
fprintf(stderr, "usage: %s <file> " n = atoi(argv[2]);
"-- call fadvise(DONTNEED) on file", argv[0]); fn = argv[3];
} else if(argc != 2) {
fprintf(stderr, "usage: %s [-n <n>] <file> "
"-- call fadvise(DONTNEED) <n> times on file", argv[0]);
exit(1); exit(1);
} else {
fn = argv[1];
} }
fd = open(argv[1], O_RDONLY); fd = open(fn, O_RDONLY);
if(fd == -1) if(fd == -1)
exiterr("open"); exiterr("open");
if(fstat(fd, &st) == -1) if(fstat(fd, &st) == -1)
exiterr("fstat"); exiterr("fstat");
if(!S_ISREG(st.st_mode)) { if(!S_ISREG(st.st_mode)) {
fprintf(stderr, "%s: S_ISREG: not a regular file", argv[1]); fprintf(stderr, "%s: S_ISREG: not a regular file", fn);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if(st.st_size == 0) { if(st.st_size == 0) {
fprintf(stderr, "%s: file size is 0!\n", argv[1]); fprintf(stderr, "%s: file size is 0!\n", fn);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
for(i = 0; i < n; i++)
if(posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED) == -1) if(posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED) == -1)
exiterr("posix_fadvise"); exiterr("posix_fadvise");
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
/* Since open() and close() are re-defined in nocache.c, it's not /* Since open() and close() are re-defined in nocache.c, it's not
* possible to include <fcntl.h> there. So we do it here. */ * possible to include <fcntl.h> there. So we do it here. */
int fadv_dontneed(int fd, off_t offset, off_t len) int fadv_dontneed(int fd, off_t offset, off_t len, int n)
{ {
#ifdef DOUBLEFADVISE int i, ret;
posix_fadvise(fd, offset, len, POSIX_FADV_DONTNEED); for(i = 0, ret = 0; i < n && ret == 0; i++)
#endif ret = posix_fadvise(fd, offset, len, POSIX_FADV_DONTNEED);
return posix_fadvise(fd, offset, len, POSIX_FADV_DONTNEED); return ret;
} }
int fadv_noreuse(int fd, off_t offset, off_t len) int fadv_noreuse(int fd, off_t offset, off_t len)
......
#ifndef _FCNTL_HELPERS_H #ifndef _FCNTL_HELPERS_H
#define _FCNTL_HELPERS_H #define _FCNTL_HELPERS_H
extern int fadv_dontneed(int fd, off_t offset, off_t len); extern int fadv_dontneed(int fd, off_t offset, off_t len, int n);
extern int fadv_noreuse(int fd, off_t offset, off_t len); extern int fadv_noreuse(int fd, off_t offset, off_t len);
extern int valid_fd(int fd); extern int valid_fd(int fd);
extern void sync_if_writable(int fd); extern void sync_if_writable(int fd);
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
.SH NAME .SH NAME
cachedel \- drop pagecache for a file cachedel \- drop pagecache for a file
.SH SYNOPSIS .SH SYNOPSIS
cachedel \fBfile\fR cachedel [-n <n>] \fBfile\fR
.SH OPTIONS
.TP
\fB\-n <n>\fR "Repeat system call"
Will call posix_fadvise(POSIX_FADV_DONTNEED) \fB<n>\fR in a row.
.SH DESCRIPTION .SH DESCRIPTION
Call fadvise(DONTNEED) on file Call posix_fadvise(POSIX_FADV_DONTNEED) on file.
...@@ -2,7 +2,13 @@ ...@@ -2,7 +2,13 @@
.SH NAME .SH NAME
nocache \- don't use Linux page cache on given command nocache \- don't use Linux page cache on given command
.SH SYNOPSIS .SH SYNOPSIS
nocache \fBcommand\fR [argument...] nocache [-n <n>] \fBcommand\fR [argument...]
.SH OPTIONS
.TP
\fB\-n <n>\fR "Set number of fadvise calls"
Execute the `posix_fadvise` system call \fB<n>\fR times in a row.
Depending on your machine, this might give better results (use it if in
your tests `nocache` fails to eradicate pages from cache properly).
.SH DESCRIPTION .SH DESCRIPTION
The `nocache` tool tries to minimize the effect an application has on The `nocache` tool tries to minimize the effect an application has on
the Linux file system cache. This is done by intercepting the `open` the Linux file system cache. This is done by intercepting the `open`
......
...@@ -8,4 +8,9 @@ else ...@@ -8,4 +8,9 @@ else
export LD_PRELOAD="$libnocache" export LD_PRELOAD="$libnocache"
fi fi
if [ "$1" = "-n" ]; then
export NOCACHE_NR_FADVISE="$2"
shift 2
fi
exec "$@" exec "$@"
...@@ -63,9 +63,13 @@ static struct fadv_info *fds; ...@@ -63,9 +63,13 @@ static struct fadv_info *fds;
static size_t PAGESIZE; static size_t PAGESIZE;
static pthread_mutex_t lock; /* protects access to fds[] */ static pthread_mutex_t lock; /* protects access to fds[] */
static char *env_nr_fadvise = "NOCACHE_NR_FADVISE";
static int nr_fadvise;
static void init(void) static void init(void)
{ {
int i; int i;
char *s;
char *error; char *error;
struct rlimit rlim; struct rlimit rlim;
...@@ -93,7 +97,10 @@ static void init(void) ...@@ -93,7 +97,10 @@ static void init(void)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if((s = getenv(env_nr_fadvise)) != NULL)
nr_fadvise = atoi(s);
if(nr_fadvise <= 0)
nr_fadvise = 1;
PAGESIZE = getpagesize(); PAGESIZE = getpagesize();
for(i = 0; i < max_fds; i++) for(i = 0; i < max_fds; i++)
...@@ -308,14 +315,14 @@ static void free_unclaimed_pages(int fd) ...@@ -308,14 +315,14 @@ static void free_unclaimed_pages(int fd)
while(j < fds[i].nr_pages) { while(j < fds[i].nr_pages) {
if(fds[i].info[j] & 1) { if(fds[i].info[j] & 1) {
if(start < j) if(start < j)
fadv_dontneed(fd, start*PAGESIZE, (j - start) * PAGESIZE); fadv_dontneed(fd, start*PAGESIZE, (j - start) * PAGESIZE, nr_fadvise);
start = j + 1; start = j + 1;
} }
j++; j++;
} }
/* forget written contents that go beyond previous file size */ /* forget written contents that go beyond previous file size */
fadv_dontneed(fd, start < j ? start*PAGESIZE : fds[i].size, 0); fadv_dontneed(fd, start < j ? start*PAGESIZE : fds[i].size, 0, nr_fadvise);
free(fds[i].info); free(fds[i].info);
fds[i].fd = -1; fds[i].fd = -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment