fadvise: perform WILLNEED readahead in a workqueue
Subsystems (4)
PATCH 1/1 fadvise: perform WILLNEED readahead in a workqueue
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front. Applications also tend to read files soon after opening them, so waiting on a slow fadvise may cause unpleasant latency when the application starts reading the file.
As a userspace hacker, I'm sometimes tempted to create a background thread in my app to run readahead(). However, I believe doing this in the kernel will make life easier for other userspace hackers.
Since fadvise makes no guarantees about when (or even if) readahead is performed, this change should not hurt existing applications.
"strace -T" timing on an uncached, one gigabyte file:
Before: fadvise64(3, 0, 0, POSIX_FADV_WILLNEED) = 0 <2.484832>
After: fadvise64(3, 0, 0, POSIX_FADV_WILLNEED) = 0 <0.000061>
---
N.B.: I'm not sure if I'm misusing any kernel APIs here. I managed to compile, boot, and run fadvise in a loop without anything blowing up. I've verified readahead gets performed via mincore().
If the workqueue approach is acceptable, I'll proceed with changing MADV_WILLNEED, too.
include/linux/mm.h | 3 +++ mm/fadvise.c | 10 ++++----- mm/readahead.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-)
include/linux/mm.h +3 -0
@@ -1473,6 +1473,9 @@ void task_dirty_inc(struct task_struct *tsk);#define VM_MAX_READAHEAD 128/* kbytes */ #define VM_MIN_READAHEAD 16/* kbytes (includes current page) */ +void wq_page_cache_readahead (struct address_space *mapping,struct file *filp, +pgoff_t offset,unsigned long nr_to_read); +int force_page_cache_readahead (struct address_space *mapping,struct file *filp,pgoff_t offset,unsigned long nr_to_read);
mm/fadvise.c +4 -6
@@ -102,12 +102,10 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)if (!nrpages) nrpages = ~0UL ; -/* -* Ignore return value because fadvise() shall return -* success even if filesystem can't retrieve a hint, -*/ -force_page_cache_readahead (mapping, f.file, start_index, - nrpages); +get_file (f.file);/* fput() is called by workqueue */ + +/* queue up the request, don't care if it fails */ +wq_page_cache_readahead (mapping, f.file, start_index, nrpages);break ;case POSIX_FADV_NOREUSE :break ;
mm/readahead.c +62 -0
74 lines not on this page · raw message
Signature · 7 lines
Eric Wong -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
How does it compare benchmark wise with a user thread or using the readahead() call ?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
How does it compare benchmark wise with a user thread or using the
readahead()call ?
Very well.
My main concern is for the speed of the initial pread()/read() call after open().
Setting EARLY_EXIT means my test program _exit()s immediately after the first pread(). In my test program (below), I wait for the background thread to become ready before open() so I would not take overhead from pthread_create() into account.
RA=1 uses a pthread + readahead()
Not setting RA uses fadvise (with my patch)
# readahead + pthread. $ EARLY_EXIT=1 RA=1 time ./first_read 1G 0.00user 0.05system 0:01.37elapsed 3%CPU (0avgtext+0avgdata 600maxresident)k 0inputs+0outputs (1major+187minor)pagefaults 0swaps
# patched fadvise $ EARLY_EXIT=1 time ./first_read 1G 0.00user 0.00system 0:00.01elapsed 0%CPU (0avgtext+0avgdata 564maxresident)k 0inputs+0outputs (1major+178minor)pagefaults 0swaps
Perhaps I screwed up my readahead() + threads path badly, but there seems to be a huge benefit in using fadvise with my patch. I'm not sure why readahead() + thread does so badly, even...
Even if I badly screwed up my use of readahead(), the benefit of my patch spares others from screwing up when using threads+readahead() :)
FULL_READ
---------
While full, fast reads are not my target use case, there's no noticeable regression here, either. Results for doing a full, fast read on the file are closer and fluctuate more between runs.
# readahead + pthread. $ FULL_READ=1 EARLY_EXIT=1 RA=1 time ./first_read 1G 0.01user 1.10system 0:09.24elapsed 12%CPU (0avgtext+0avgdata 596maxresident)k 0inputs+0outputs (1major+186minor)pagefaults 0swaps
# patched fadvise FULL_READ=1 EARLY_EXIT=1 time ./first_read 1G 0.01user 1.04system 0:09.22elapsed 11%CPU (0avgtext+0avgdata 564maxresident)k 0inputs+0outputs (1major+178minor)pagefaults 0swaps
--------------------------------- 8< ------------------------------ /* gcc -O2 -Wall -lpthread -o first_read first_read.c */ #define _GNU_SOURCE
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include <sched.h>
#include <sys/eventfd.h>
static int efd1;
static int efd2;
static void * start_ra(void *unused)
{
struct stat st;
eventfd_t val;
int fd;
/* tell parent to open() */
assert(eventfd_write(efd1, 1) == 0);
/* wait for parent to tell us fd is ready */
assert(eventfd_read(efd2, &val) == 0);
fd = (int)val;
assert(fstat(fd, &st) == 0);
assert(readahead(fd, 0, st.st_size) == 0);
return NULL;
}int main(int argc, char *argv[])
{
char buf[16384];
pthread_t thr;
int fd;
char *do_ra = getenv("RA");
if (argc != 2) {
fprintf(stderr, "Usage: strace -T %s LARGE_FILE\n", argv[0]);
return 1;
}
if (do_ra) {
eventfd_t val;
efd1 = eventfd(0, 0);
efd2 = eventfd(0, 0);
assert(efd1 >= 0 && efd2 >= 0 && "eventfd failed");
assert(pthread_create(&thr, NULL, start_ra, NULL) == 0);
/* wait for child thread to spawn */
assert(eventfd_read(efd1, &val) == 0);
}
fd = open(argv[1], O_RDONLY);
assert(fd >= 0 && "open failed");
if (do_ra) {
/* wake up the child thread, give it a chance to run */
assert(eventfd_write(efd2, fd) == 0);
sched_yield();
} else
assert(posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) == 0);
assert(pread(fd, buf, sizeof(buf), 0) == sizeof(buf));
if (getenv("FULL_READ")) {
ssize_t r;
do {
r = read(fd, buf, sizeof(buf));
} while (r > 0);
assert(r == 0 && "EOF not reached");
}
if (getenv("EXIT_EARLY"))
_exit(0);
if (do_ra) {
assert(pthread_join(thr, NULL) == 0);
assert(close(efd1) == 0);
assert(close(efd2) == 0);
}
assert(close(fd) == 0);
return 0;
}--------------------------------- 8< ------------------------------
Thanks for your interest in this!
Signature · 7 lines
Eric Wong -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 15 lines · Eric Wong
Quoted 8 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
How does it compare benchmark wise with a user thread or using the
readahead()call ?Very well.
My main concern is for the speed of the initial pread()/read() call after
open().
Quoted 7 lines
Setting
EARLY_EXITmeans my test program _exit()s immediately after the firstpread(). In my test program (below), I wait for the background thread to become ready beforeopen()so I would not take overhead frompthread_create()into account.RA=1 uses a pthread +
readahead()
Not setting RA uses fadvise (with my patch)
And if you don't use fadvise/readahead at all?
Quoted 9 lines
# readahead + pthread. $ EARLY_EXIT=1 RA=1 time ./first_read 1G 0.00user 0.05system 0:01.37elapsed 3%CPU (0avgtext+0avgdata 600maxresident)k 0inputs+0outputs (1major+187minor)pagefaults 0swaps# patched fadvise $ EARLY_EXIT=1 time ./first_read 1G 0.00user 0.00system 0:00.01elapsed 0%CPU (0avgtext+0avgdata 564maxresident)k 0inputs+0outputs (1major+178minor)pagefaults 0swaps
You're not timing how long the first pread() takes at all. You're timing the entire set of operations, including cloning a thread and for the readahead(2) call and messages to be passed back and forth through the eventfd interface to read the entire file.
Why even bother with another thread for readahead()? It implements *exactly* the same operation as fadvise(WILL_NEED) (ie. force_page_cache_readahead), so should perform identically when called in exactly the same manner...
But again, you are interesting in the latency of the first read of 16k from the file, but you are asking to readahead 1GB of data. Perhaps your shoul dbe asking for readahead of something more appropriate to what you care about - the first read....
Cheers,
Dave.
Signature · 8 lines
Dave Chinner [email protected] -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 21 lines · Dave Chinner
Quoted 20 lines · Eric Wong
Quoted 8 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
How does it compare benchmark wise with a user thread or using the
readahead()call ?Very well.
My main concern is for the speed of the initial pread()/read() call after
open().Setting
EARLY_EXITmeans my test program _exit()s immediately after the firstpread(). In my test program (below), I wait for the background thread to become ready beforeopen()so I would not take overhead frompthread_create()into account.
Quoted 4 lines
Quoted 2 lines
RA=1 uses a pthread +
readahead()
Not setting RA uses fadvise (with my patch)And if you don't use fadvise/readahead at all?
Sorry for the confusion. I believe my other reply to you summarized what I wanted to say in my commit message and also reply to Alan.
I want all the following things:
- I want the first read to be fast.
- I want to read the whole file eventually (probably slowly, as processing takes a while).
- I want to let my disk spin down for as long as possible.
This could also be a use case for an audio/video player.
Quoted 4 lines
You're not timing how long the first
pread()takes at all. You're timing the entire set of operations, including cloning a thread and for the readahead(2) call and messages to be passed back and forth through the eventfd interface to read the entire file.
You're right, I screwed up the measurement. Using clock_gettime(), there's hardly a difference between the approaches and I can't get consistent timings between them.
So no, there's no difference that matters between the approaches. But I think doing this in the kernel is easier for userspace users.
---------------------------------- 8<---------------------------- /* gcc -O2 -Wall -lpthread -lrt -o first_read first_read.c */ #define _GNU_SOURCE
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include <sched.h>
#include <sys/eventfd.h>
#include <time.h>
static int efd1;
static int efd2;
static void clock_diff(struct timespec *a, const struct timespec *b)
{
a->tv_sec -= b->tv_sec;
a->tv_nsec -= b->tv_nsec;
if (a->tv_nsec < 0) {
--a->tv_sec;
a->tv_nsec += 1000000000;
}
}static void * start_ra(void *unused)
{
struct stat st;
eventfd_t val;
int fd;
/* tell parent to open() */
assert(eventfd_write(efd1, 1) == 0);
/* wait for parent to tell us fd is ready */
assert(eventfd_read(efd2, &val) == 0);
fd = (int)val;
assert(fstat(fd, &st) == 0);
assert(readahead(fd, 0, st.st_size) == 0);
return NULL;
}int main(int argc, char *argv[])
{
char buf[16384];
pthread_t thr;
int fd;
struct timespec start;
struct timespec finish;
char *do_ra = getenv("RA");
if (argc != 2) {
fprintf(stderr, "Usage: strace -T %s LARGE_FILE\n", argv[0]);
return 1;
}
if (do_ra) {
eventfd_t val;
efd1 = eventfd(0, 0);
efd2 = eventfd(0, 0);
assert(efd1 >= 0 && efd2 >= 0 && "eventfd failed");
assert(pthread_create(&thr, NULL, start_ra, NULL) == 0);
/* wait for child thread to spawn */
assert(eventfd_read(efd1, &val) == 0);
}
fd = open(argv[1], O_RDONLY);
assert(fd >= 0 && "open failed");
assert(clock_gettime(CLOCK_MONOTONIC, &start) == 0);
if (do_ra) {
/* wake up the child thread, give it a chance to run */
assert(eventfd_write(efd2, fd) == 0);
sched_yield();
} else
assert(posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED) == 0);
assert(pread(fd, buf, sizeof(buf), 0) == sizeof(buf));
assert(clock_gettime(CLOCK_MONOTONIC, &finish) == 0);
clock_diff(&finish, &start);
fprintf(stderr, "elapsed: %lu.%09lu\n", finish.tv_sec, finish.tv_nsec);
if (getenv("FULL_READ")) {
ssize_t r;
do {
r = read(fd, buf, sizeof(buf));
} while (r > 0);
assert(r == 0 && "EOF not reached");
}
if (getenv("EXIT_EARLY"))
_exit(0);
if (do_ra) {
assert(pthread_join(thr, NULL) == 0);
assert(close(efd1) == 0);
assert(close(efd2) == 0);
}
assert(close(fd) == 0);
return 0;
}Quoted 10 lines · Eric Wong
Quoted 7 lines · Dave Chinner
Quoted 6 lines · Eric Wong
Quoted 5 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
This could also be a use case for an audio/video player.
Sure, but this can all be handled by a userspace application. If you want to avoid/batch IO to enable longer spindown times, then you have to load the file into RAM somewhere, and you don't need special kernel support for that.
Quoted 2 lines
So no, there's no difference that matters between the approaches. But I think doing this in the kernel is easier for userspace users.
The kernel provides mechanisms for applications to use. You have not mentioned anything new that requires a new kernel mechanism to acheive - you just need to have the knowledge to put the pieces together properly. People have been solving this same problem for the last 20 years without needing to tweak fadvise(). Or even having an fadvise() syscall...
Nothing about low latency IO or streaming IO is simple or easy, and changing how readahead works doesn't change that fact. All it does is change the behaviour of every other application that uses fadvise() to minimise IO latency....
Cheers,
Dave.
Signature · 8 lines
Dave Chinner [email protected] -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Dave Chinner
Quoted 8 lines · Eric Wong
Quoted 7 lines · Dave Chinner
Quoted 6 lines · Eric Wong
Quoted 5 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
Quoted 8 lines
Quoted 1 line
This could also be a use case for an audio/video player.
Sure, but this can all be handled by a userspace application. If you want to avoid/batch IO to enable longer spindown times, then you have to load the file into RAM somewhere, and you don't need special kernel support for that.
From userspace, I don't know when/if I'm caching too much and possibly
getting the userspace cache itself swapped out.
Quoted 9 lines
Quoted 2 lines
So no, there's no difference that matters between the approaches. But I think doing this in the kernel is easier for userspace users.
The kernel provides mechanisms for applications to use. You have not mentioned anything new that requires a new kernel mechanism to acheive - you just need to have the knowledge to put the pieces together properly. People have been solving this same problem for the last 20 years without needing to tweak
fadvise(). Or even having anfadvise()syscall...
fadvise() is fairly new, and AFAIK few apps use it. Perhaps if it were improved, more people would use it and not have to reinvent the wheel.
Quoted 4 lines
Nothing about low latency IO or streaming IO is simple or easy, and changing how readahead works doesn't change that fact. All it does is change the behaviour of every other application that uses
fadvise()to minimise IO latency....
I don't want to introduce regressions, either.
Perhaps if part of the FADV_WILLNEED read-ahead were handled synchronously (maybe 2M?) and humongous large readaheads (like mine) went to the background, that would be a good trade off?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 13 lines · Eric Wong
Quoted 12 lines · Dave Chinner
Quoted 10 lines · Eric Wong
Quoted 7 lines · Dave Chinner
Quoted 6 lines · Eric Wong
Quoted 5 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
This could also be a use case for an audio/video player.
Quoted 7 lines
Quoted 4 lines
Sure, but this can all be handled by a userspace application. If you want to avoid/batch IO to enable longer spindown times, then you have to load the file into RAM somewhere, and you don't need special kernel support for that.
From userspace, I don't know when/if I'm caching too much and possibly getting the userspace cache itself swapped out.
Which causes th disk to spin up. Now you start to see the complexity of what you are trying to acheive...
Quoted 10 lines
Quoted 9 lines
Quoted 2 lines
So no, there's no difference that matters between the approaches. But I think doing this in the kernel is easier for userspace users.
The kernel provides mechanisms for applications to use. You have not mentioned anything new that requires a new kernel mechanism to acheive - you just need to have the knowledge to put the pieces together properly. People have been solving this same problem for the last 20 years without needing to tweak
fadvise(). Or even having anfadvise()syscall...
Quoted 3 lines
fadvise()is fairly new, and AFAIK few apps use it. Perhaps if it were improved, more people would use it and not have to reinvent the wheel.
fadvise() is not "fairly new". It's been around for many, many years - it was there whan the linux kernel moved to git in 2005, and I haven't bothered to look any further back in history...
Quoted 10 lines
Quoted 4 lines
Nothing about low latency IO or streaming IO is simple or easy, and changing how readahead works doesn't change that fact. All it does is change the behaviour of every other application that uses
fadvise()to minimise IO latency....I don't want to introduce regressions, either.
Perhaps if part of the
FADV_WILLNEEDread-ahead were handled synchronously (maybe 2M?) and humongous large readaheads (like mine) went to the background, that would be a good trade off?
Which you can already do in userspace yourself without changing the kernel. i.e:
main thread background thread: readahead(0, 2MB) spawn background thread read(0, len) readahead(2MB,1GB);
Cheers,
Dave.
Signature · 8 lines
Dave Chinner [email protected] -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 27 lines · Dave Chinner
Quoted 10 lines · Eric Wong
Quoted 7 lines · Dave Chinner
Quoted 6 lines · Eric Wong
Quoted 5 lines · Alan Cox
Quoted 2 lines · On Sat, 15 Dec 2012 00:54:48 +0000 Eric Wong <[email protected]> wrote:
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front
This could also be a use case for an audio/video player.
Sure, but this can all be handled by a userspace application. If you want to avoid/batch IO to enable longer spindown times, then you have to load the file into RAM somewhere, and you don't need special kernel support for that.
Quoted 2 lines
So no, there's no difference that matters between the approaches. But I think doing this in the kernel is easier for userspace users.
The kernel provides mechanisms for applications to use. You have not mentioned anything new that requires a new kernel mechanism to acheive - you just need to have the knowledge to put the pieces together properly. People have been solving this same problem for the last 20 years without needing to tweak
fadvise(). Or even having anfadvise()syscall...
Quoted 4 lines
Nothing about low latency IO or streaming IO is simple or easy, and changing how readahead works doesn't change that fact. All it does is change the behaviour of every other application that uses
fadvise()to minimise IO latency....
Hi Dave,
I am wondering this patch might be a good idea to reduce the latency of fadvise() syscall itself. I do a really simple test in my desktop to measure the latency of fadvise syscall. Before applying this patch, fadvise syscall takes 32 microseconds. After applying the patch, it only takes 4 microseconds. (I was surprised that it takes a very long time!)
Actually we observe a latency after using fadvise. But I don't find a proper time to look at this problem. So I guess this patch might be useful to reduce latency.
Regards,
- Zheng
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Eric Wong
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front. Applications also tend to read files soon after opening them, so waiting on a slow fadvise may cause unpleasant latency when the application starts reading the file.
As a userspace hacker, I'm sometimes tempted to create a background thread in my app to run
readahead(). However, I believe doing this in the kernel will make life easier for other userspace hackers.
Quoted 7 lines
Since fadvise makes no guarantees about when (or even if) readahead is performed, this change should not hurt existing applications.
"strace -T" timing on an uncached, one gigabyte file:
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>
You've basically asked fadvise() to readahead the entire file if it can. That means it is likely to issue enough readahead to fill the IO queue, and that's where all the latency is coming from. If all you are trying to do is reduce the latency of the first read, then only readahead the initial range that you are going to need to read...
Also, Pushing readahead off to a workqueue potentially allows someone to DOS the system because readahead won't ever get throttled in the syscall context...
Cheers,
Dave.
Signature · 8 lines
Dave Chinner [email protected] -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 16 lines · Dave Chinner
Quoted 15 lines · Eric Wong
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front. Applications also tend to read files soon after opening them, so waiting on a slow fadvise may cause unpleasant latency when the application starts reading the file.
As a userspace hacker, I'm sometimes tempted to create a background thread in my app to run
readahead(). However, I believe doing this in the kernel will make life easier for other userspace hackers.Since fadvise makes no guarantees about when (or even if) readahead is performed, this change should not hurt existing applications.
"strace -T" timing on an uncached, one gigabyte file:
Quoted 8 lines
Quoted 2 lines
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>You've basically asked
fadvise()to readahead the entire file if it can. That means it is likely to issue enough readahead to fill the IO queue, and that's where all the latency is coming from. If all you are trying to do is reduce the latency of the first read, then only readahead the initial range that you are going to need to read...
Yes, I do want to read the whole file, eventually. So I want to put the file into the page cache ASAP and allow the disk to spin down. But I also want the first read() to be fast.
Quoted 3 lines
Also, Pushing readahead off to a workqueue potentially allows someone to DOS the system because readahead won't ever get throttled in the syscall context...
Yes, I'm a little worried about this, too. Perhaps squashing something like the following will work?
mm/readahead.c +9 -4
@@ -246,16 +246,18 @@ void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, {struct wq_ra_req *req; + nr_to_read =max_sane_readahead (nr_to_read); +if (!nr_to_read) + goto skip_ra; + req =kzalloc (sizeof (*req),GFP_ATOMIC );/* * we are fire-and-forget, not having enough memory means readahead * is not worth doing anyways */ -if (!req) { -fput (filp); -return ; - } +if (!req) + goto skip_ra;INIT_WORK (&req->work, wq_ra_req_fn); req->mapping = mapping;
@@ -264,6 +266,9 @@ void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, req->nr_to_read = nr_to_read;queue_work (readahead_wq, &req->work); + +skip_ra: +fput (filp); }/*
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 1 line · Eric Wong
Perhaps squashing something like the following will work?
Last hunk should've had a return before skip_ra:
mm/readahead.c +4 -0
@@ -264,6 +266,10 @@ void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, req->nr_to_read = nr_to_read;queue_work (readahead_wq, &req->work); + +return ; +skip_ra: +fput (filp); }/*
Signature · 7 lines
Eric Wong -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 20 lines · Eric Wong
Quoted 19 lines · Dave Chinner
Quoted 17 lines · Eric Wong
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front. Applications also tend to read files soon after opening them, so waiting on a slow fadvise may cause unpleasant latency when the application starts reading the file.
As a userspace hacker, I'm sometimes tempted to create a background thread in my app to run
readahead(). However, I believe doing this in the kernel will make life easier for other userspace hackers.Since fadvise makes no guarantees about when (or even if) readahead is performed, this change should not hurt existing applications.
"strace -T" timing on an uncached, one gigabyte file:
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>
Quoted 8 lines
Quoted 5 lines
You've basically asked
fadvise()to readahead the entire file if it can. That means it is likely to issue enough readahead to fill the IO queue, and that's where all the latency is coming from. If all you are trying to do is reduce the latency of the first read, then only readahead the initial range that you are going to need to read...Yes, I do want to read the whole file, eventually. So I want to put the file into the page cache ASAP and allow the disk to spin down.
Issuing readahead is not going to speed up the first read. Either you will spend more time issuing all the readahead, or you block waiting for the first read to complete. And the way you are issuing readahead does not guarantee the entire file is brought into the page cache....
Quoted 1 line
But I also want the first
read()to be fast.
You can't have a pony, sorry.
Quoted 12 lines
Quoted 3 lines
Also, Pushing readahead off to a workqueue potentially allows someone to DOS the system because readahead won't ever get throttled in the syscall context...
Yes, I'm a little worried about this, too. Perhaps squashing something like the following will work?
mm/readahead.c +0
-0
mm/readahead.c void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, · line 251
Quoted 6 lines
mm/readahead.c +3
-0@@ -246,16 +246,18 @@ void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, {struct wq_ra_req *req; + nr_to_read =max_sane_readahead (nr_to_read); +if (!nr_to_read) + goto skip_ra;
You do realise that anything you read ahead will be accounted as inactive pages, so nr_to_read doesn't decrease at all as you fill memory with readahead pages...
mm/readahead.c void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, · line 253
Quoted 2 lines
mm/readahead.c +1
-0+ req =kzalloc (sizeof (*req),GFP_ATOMIC );
GFP_ATOMIC? Really?
In reality, I think you are looking in the wrong place to fix your "first read" latency problem. No matter what you do, there is going to be IO latency on the first read. And readahead doesn't guarantee that the pages are brought into the page cache (ever heard of readahead thrashing?) so the way you are doing your readahead is not going to result in you being able to spin the disk down after issuing a readahead command...
You've really got two problems - minimal initial latency, and reading the file quickly and pinning it in memory until you get around to needing it. The first can't be made faster by using readahead, and the second can not be guaranteed by using readahead.
IOWs, readahead is the wrong tool for solving your problems. Minimal IO latency from the first read will come from just issuing pread() after open(), and ensuring that the file is read quickly and pinned in memory can really only be done by allocating RAM in the application to hold it until it is needed....
Cheers,
Dave.
Signature · 8 lines
Dave Chinner [email protected] -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 13 lines · Dave Chinner
Quoted 12 lines · Eric Wong
Quoted 10 lines · Dave Chinner
Quoted 3 lines · Eric Wong
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>You've basically asked
fadvise()to readahead the entire file if it can. That means it is likely to issue enough readahead to fill the IO queue, and that's where all the latency is coming from. If all you are trying to do is reduce the latency of the first read, then only readahead the initial range that you are going to need to read...
Quoted 8 lines
Quoted 2 lines
Yes, I do want to read the whole file, eventually. So I want to put the file into the page cache ASAP and allow the disk to spin down.
Issuing readahead is not going to speed up the first read. Either you will spend more time issuing all the readahead, or you block waiting for the first read to complete. And the way you are issuing readahead does not guarantee the entire file is brought into the page cache....
I'm not relying on readahead to speed up the first read.
By using fadvise/readahead, I want a _best-effort_ attempt to keep the file in cache.
Quoted 3 lines
Quoted 1 line
But I also want the first
read()to be fast.You can't have a pony, sorry.
I want the first read() to happen sooner than it would under current fadvise. If it's slightly slower that w/o fadvise, that's fine. The 1-2s slower with current fadvise is what bothers me.
Quoted 15 lines
Quoted 15 lines
Quoted 3 lines
Also, Pushing readahead off to a workqueue potentially allows someone to DOS the system because readahead won't ever get throttled in the syscall context...
Yes, I'm a little worried about this, too. Perhaps squashing something like the following will work?
mm/readahead.c +0
-0@@ -246,16 +246,18 @@ void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, {struct wq_ra_req *req;
Quoted 7 lines
mm/readahead.c void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, · line 251
Quoted 3 lines
mm/readahead.c +3
-0+ nr_to_read =max_sane_readahead (nr_to_read); +if (!nr_to_read) + goto skip_ra;You do realise that anything you read ahead will be accounted as inactive pages, so
nr_to_readdoesn't decrease at all as you fill memory with readahead pages...
Ah, ok, I'll see if I can rework it.
Quoted 3 lines
mm/readahead.c void wq_page_cache_readahead(struct address_space *mapping, struct file *filp, · line 253
Quoted 1 line
mm/readahead.c +0
-0req =kzalloc (sizeof (*req),GFP_ATOMIC );
GFP_ATOMIC? Really?
Sorry, I'm really new at this.
Quoted 7 lines
In reality, I think you are looking in the wrong place to fix your "first read" latency problem. No matter what you do, there is going to be IO latency on the first read. And readahead doesn't guarantee that the pages are brought into the page cache (ever heard of readahead thrashing?) so the way you are doing your readahead is not going to result in you being able to spin the disk down after issuing a readahead command...
Right, I want a _best-effort_ readahead (which seems to be what an advisory interface should offer).
Quoted 4 lines
You've really got two problems - minimal initial latency, and reading the file quickly and pinning it in memory until you get around to needing it. The first can't be made faster by using readahead, and the second can not be guaranteed by using readahead.
Agreed. I think I overstated the requirements.
I want "less-bad" initial latency than I was getting.
So I don't mind if open()+fadvise()+read() is a couple of milliseconds slower than just open()+read(), but I do mind if fadvise() takes 1-2 seconds.
Quoted 5 lines
IOWs, readahead is the wrong tool for solving your problems. Minimal IO latency from the first read will come from just issuing
pread()afteropen(), and ensuring that the file is read quickly and pinned in memory can really only be done by allocating RAM in the application to hold it until it is needed....
I definitely only want a best-effort method to put a file into memory. I want the kernel to decide whether or not to cache it.
Thanks for looking at this!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 28 lines · Eric Wong
Quoted 13 lines · Dave Chinner
Quoted 12 lines · Eric Wong
Quoted 10 lines · Dave Chinner
Quoted 3 lines · Eric Wong
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>You've basically asked
fadvise()to readahead the entire file if it can. That means it is likely to issue enough readahead to fill the IO queue, and that's where all the latency is coming from. If all you are trying to do is reduce the latency of the first read, then only readahead the initial range that you are going to need to read...Quoted 8 lines
Quoted 2 lines
Yes, I do want to read the whole file, eventually. So I want to put the file into the page cache ASAP and allow the disk to spin down.
Issuing readahead is not going to speed up the first read. Either you will spend more time issuing all the readahead, or you block waiting for the first read to complete. And the way you are issuing readahead does not guarantee the entire file is brought into the page cache....
I'm not relying on readahead to speed up the first read.
By using fadvise/readahead, I want a _best-effort_ attempt to keep the file in cache.
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
But I also want the first
read()to be fast.You can't have a pony, sorry.
I want the first
read()to happen sooner than it would under current fadvise.
You're not listening. You do not need the kernel to be modified to avoid the latency of issuing 1GB of readahead on a file.
You don't need to do readahead before the first read. Nor do you do need to wait for 1GB of readhead to be issued before you do the first read.
You could do readahead *concurrently* with the first read, so the first read only blocks until the readahead of the first part of the file completes. i.e. just do readahead() in a background thread and don't wait for it to complete before doing the first read.
You could even do readahead *after* the first read, when the time it takes *doesn't matter* to the processing of the incoming data...
Quoted 1 line
I want "less-bad" initial latency than I was getting.
And you can do that by changing how you issue readahead from userspace.
Cheers,
Dave.
Signature · 8 lines
Dave Chinner [email protected] -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Dave Chinner
Quoted 2 lines · Eric Wong
I want the first
read()to happen sooner than it would under current fadvise.You're not listening. You do not need the kernel to be modified to avoid the latency of issuing 1GB of readahead on a file.
Quoted 8 lines
You don't need to do readahead before the first read. Nor do you do need to wait for 1GB of readhead to be issued before you do the first read.
You could do readahead *concurrently* with the first read, so the first read only blocks until the readahead of the first part of the file completes. i.e. just do
readahead()in a background thread and don't wait for it to complete before doing the first read.
What you describe with concurrent readahead() is _exactly_ what my test program (in other email) does with the RA environment variable set.
I know I do not _need_ fadvise + background WILLNEED support in the kernel.
But I think the kernel can make life easier and allow us to avoid doing background threads or writing our own (inferior) caching in userspace.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Quoted 21 lines · Dave Chinner
Quoted 11 lines · Eric Wong
Applications streaming large files may want to reduce disk spinups and I/O latency by performing large amounts of readahead up front. Applications also tend to read files soon after opening them, so waiting on a slow fadvise may cause unpleasant latency when the application starts reading the file.
As a userspace hacker, I'm sometimes tempted to create a background thread in my app to run
readahead(). However, I believe doing this in the kernel will make life easier for other userspace hackers.Quoted 8 lines
Since fadvise makes no guarantees about when (or even if) readahead is performed, this change should not hurt existing applications.
"strace -T" timing on an uncached, one gigabyte file:
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>
Quoted 6 lines
You've basically asked
fadvise()to readahead the entire file if it can. That means it is likely to issue enough readahead to fill the IO queue, and that's where all the latency is coming from. If all you are trying to do is reduce the latency of the first read, then only readahead the initial range that you are going to need to read...
It shouldn't take 2 seconds to queue up some async reads. Are you using ext3? The blocks have to be mapped in order to queue the reads, and without ext4 extents, this means the indirect blocks have to be read and can cause fadvise to block.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
iQEcBAEBAgAGBQJRJ6CjAAoJEJrBOlT6nu759s8IAKmIyZYDk1JSRP6oJaGaGZ/r aZCBH52wTPH8DaqFGe+62L8lyIQ5hD15Y+zTuaWh+fJ7C1k/lU8F/QbKCG2D+xCB vfLF0WRx63fWLLg8xZTRU1x8X6sG+Byp+UYWNspTDrL15ChlaqqGGmwLNo4JxLa8 +AGQVt1WMU3TitD9CUMUfYFWGUQsMR0gWeJkJnjHiEZ7VoGzft2PTlnvElzIk76u 3cmwfoKHrnXzi50rPtP2gonRjMwd8VY859qOk0zlHoMDMcXklAWeIN9PEUIMx+VP fMnBm6u48cKXPYGvQrGMOdjxlt7k4LhGDZxIlvmwNHWUSaifmkJ8oBMvfbAYtUA= =G5rE
-----END PGP SIGNATURE-----
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Phillip Susi
Quoted 5 lines · Eric Wong
Quoted 4 lines
"strace -T" timing on an uncached, one gigabyte file:
Before:
fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <2.484832>
After:fadvise64(3, 0, 0, POSIX_FADV_WILLNEED)= 0 <0.000061>It shouldn't take 2 seconds to queue up some async reads. Are you using ext3? The blocks have to be mapped in order to queue the reads, and without ext4 extents, this means the indirect blocks have to be read and can cause fadvise to block.
You're right, I originally tested on ext3.
I just tested an unpatched 3.7.9 kernel with ext4 and is much faster (~250ms). I consider ~250ms acceptable for my needs. Will migrate the rest of my setup to ext4 soon, thanks for the tip!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>