The size of the page cache is appropriate (I have measured about 200 MB with top) and caches the remote file system. I tested it in a following way:
- turned on the TV, the "cached" value in top was about 50 MB
- started to play a HD movie through CIFS, the "cached" value started to grow until free memory was available up to about 250 MB
- when the video started to lag, I pressed the rwd button, that made the lagging part played back properly because the data was in the page cache already
So the sole issue is that not enough readahead happens.
The following article describes how a FUSE module as a shim between the NFS mountpoint and the player can trigger readahead.
http://www.linuxjournal.com/article/9769
The read implementation of the FUSE module reads in what the application requested and the next 4MB of data. The extra data is just thrown away but the mere act of the FUSE module reading, the 4MB of extra data will remain in the page cache. (I have increased the buffer to 32 MB in the included code.)
The article recommends using FS-Cache but it is not needed in our case as the page cache has a satisfactory size and behaviour for file caching.
The only thing seems to be done, is to compile the nfs-fuse-readahead-shim.cpp class and the fuselagefs package to the TV's platform. (see below)
I tried it but I have stucked with building the cross-compiler toolchain on cygwin. And I have to admit not having the necessary experience for cross compilation.
I would appritiate if someone could compile and upload it or assist me how to compile.
The solution can be also included in the All Extensions Pack.
fuselagefs: http://sourceforge.net/project/showfile ... _id=225200
nfs-fuse-readahead-shim.cpp:
- Code: Select all
#include <fuselagefs/fuselagefs.hh>
using namespace Fuselage;
using namespace Fuselage::Helpers;
#include <aio.h>
#include <errno.h>
#include <string>
#include <iostream>
using namespace std;
...
class CustomFilesystem
:
public Delegatefs
{
typedef Delegatefs _Base;
off_t m_oldOffset;
off_t m_startNextAIOOffset;
enum
{
aio_buffer_sz = 32 * 1024 * 1024,
aio_consume_window = aio_buffer_sz / 2,
debug_readahread_aio = false
};
char aio_buffer[ aio_buffer_sz ];
void schedule_readahread_aio( int fd,
off_t offset, bool forceNewReadAHead )
{
if( m_startNextAIOOffset <= offset
|| forceNewReadAHead )
{
cerr << "Starting an async read request"
<< " at offset:" << offset << endl;
ssize_t retval; ssize_t nbytes;
struct aiocb arg;
bzero( &arg, sizeof (struct aiocb));
arg.aio_fildes = fd;
arg.aio_offset = offset;
arg.aio_buf = (void *) aio_buffer;
arg.aio_nbytes = aio_buffer_sz;
arg.aio_sigevent.sigev_notify = SIGEV_NONE;
retval = aio_read( &arg );
if( retval < 0 )
cerr << "error starting aio request!"
<< endl;
m_startNextAIOOffset = offset
+ aio_consume_window;
if( debug_readahread_aio )
{
while ( (retval = aio_error( &arg ) )
== EINPROGRESS )
{}
cerr << "aio_return():"
<< aio_return( &arg )
<< endl;
}
}
}
public:
CustomFilesystem()
:
_Base(),
m_startNextAIOOffset( 0 ),
m_oldOffset( -1 )
{
}
virtual int fs_read( const char *path,
char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
cerr << "fs_read() offset:" << offset
<< " sz:" << size << endl;
int fd = fi->fh;
bool forceNewReadAHead = false;
if( (offset - size) != m_oldOffset )
{
cerr << "possible seek() between read()s!"
<< endl;
forceNewReadAHead = true;
aio_cancel( fd, 0 );
}
schedule_readahread_aio( fd, offset,
forceNewReadAHead );
m_oldOffset = offset;
return _Base::fs_read( path, buf,
size, offset, fi );
}
};
Make file:
- Code: Select all
nfs-fuse-readahead-shim: nfs-fuse-readahead-shim.cpp
g++ nfs-fuse-readahead-shim.cpp \
-o nfs-fuse-readahead-shim \
-D_FILE_OFFSET_BITS=64 -lfuselagefs

DivFix++ AVI Fix
Meteorite MKV Repair