[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-optimize
Subject: preloading of binaries
From: Lubos Lunak <l.lunak () suse ! cz>
Date: 2004-03-08 13:19:08
Message-ID: 200403081419.09984.l.lunak () suse ! cz
[Download RAW message or body]
Hello,
I'd need some people to test the the following hack. In startkde, before KDE
is loaded, a small utility mmap()'s basic large libraries used by KDE and
walks over them, causing them to be all loaded into memory, and they'll stay
cached (I think OO.o uses a similar hack). As the mmap() is done with
MADV_WILLNEED, this should cause sequential reads of large chunks from the
disk[1], instead of small random access reads which kernel uses otherwise as
the parts of the binaries are paged in[2].
How to test it:
- Edit preload.cpp, adjust prefixes, and adjust sizes of libraries. The sizes
are the value in the column 'File off' next to the '.bss' segment as reported
by 'objdump --headers' on the binary. If you strip the libraries, you can
simply use the size.
- Add calling preload to startkde, before any KDE binary is used (i.e. right
after the 'startkde: Starting up...' echo.
- Use your wristwatch ;) [3].
For me the times are 18,1s without preload with cold cache, 16,4s with
preload and 11,1s when already cached (logout and startkde again). Not much,
but probably worth it. Now I'd need some data from more people, especially if
somebody has somewhat slower HDD or has 2.6 kernel. I tried also with DMA
turned off, which reduced my 35+MiB/s HDD's performance just to about 2MiB/s,
and there was no real difference, and in fact when I preloaded too much, it
even had negative effect on the performance.
I tried the same also in kdeinit when it dlopens modules, but I couldn't see
any noticeable difference, as those binaries are <1MiB in size, so that
probably doesn't make much sense. See kinit.patch if you want to try
yourself.
[1] In case you build and use Qt from the same directory like I do, I suggest
applying the attached qt.patch. As already said here by somebody, ld is far
from creating the library as one large sequential area of disk.
[2] I'd be interested if somebody could test what the difference with 2.6
kernel is, as I heard rumours somewhere (here?) that 2.6 will do a better job
at loading binaries.
[3] You need to empty your caches of course for testing this. Compiling and
running the attached a.cpp should do that (wait for it to be killed by OOM
killer or break it when your computer starts hitting swap).
--
Lubos Lunak
KDE developer
---------------------------------------------------------------------
SuSE CR, s.r.o. e-mail: l.lunak@suse.cz , l.lunak@kde.org
Drahobejlova 27 tel: +420 2 9654 2373
190 00 Praha 9 fax: +420 2 9654 2374
Czech Republic http://www.suse.cz/
["qt.patch" (text/x-diff)]
--- qmake/generators/unix/unixmake2.cpp.sav 2003-12-05 02:47:10.000000000 +0100
+++ qmake/generators/unix/unixmake2.cpp 2004-03-07 23:32:31.000000000 +0100
@@ -566,7 +566,9 @@ UnixMakefileGenerator::writeMakeParts(QT
<< "-$(DEL_FILE) " << var("DESTDIR") << "$(TARGET0)\n\t"
<< "-$(DEL_FILE) " << var("DESTDIR") << "$(TARGET1)\n\t"
<< "-$(DEL_FILE) " << var("DESTDIR") << "$(TARGET2)\n\t"
- << "-$(MOVE) $(TARGET) $(TARGET0) $(TARGET1) $(TARGET2) " << var("DESTDIR");
+ << "-$(MOVE) $(TARGET0) $(TARGET1) $(TARGET2) " << var("DESTDIR") << "\n\t"
+ << "-$(COPY) $(TARGET) " << var("DESTDIR") << "\n\t"
+ << "-$(DEL_FILE) $(TARGET)";
if(!project->isEmpty("QMAKE_POST_LINK"))
t << "\n\t" << var("QMAKE_POST_LINK");
t << endl << endl;
["preload.cpp" (text/x-c++src)]
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
struct data_t
{
const char* file;
size_t size;
};
#define PREFIXK "/opt/_k/"
#define PREFIXQ "/opt/_q/"
const data_t data[] = {
{ PREFIXK "lib/libkdecore.so", 0x215240 }, // pridat potom .<verze>
{ PREFIXK "lib/libkdeui.so", 0x2d5c80 },
{ PREFIXK "lib/libDCOP.so", 0x3c7a0 },
{ PREFIXQ "lib/libqt-mt.so", 0x784d40 },
{ PREFIXK "lib/libkio.so", 0x333320 },
{ PREFIXK "lib/libkparts.so", 0x4f6f0 },
{ PREFIXK "lib/libkdefx.so", 0x35a20 },
{ "/usr/X11R6/lib/libX11.so.6", 0xe2958 },
{ "/usr/lib/libstdc++.so", 0xb1b20 },
{ PREFIXK "lib/libkonq.so", 0x8f7e8 },
};
int main()
{
unsigned int i;
for( i = 0;
i < sizeof( data ) / sizeof( data[ 0 ] );
++i )
{
int fd = open( data[ i ].file, O_RDONLY );
if( fd >= 0 )
{
void* map = mmap( NULL, data[ i ].size, PROT_READ, MAP_SHARED, fd, 0 );
if( map != NULL )
{
volatile int tmp;
// CHECKME round up/down here?
int* end = reinterpret_cast< int* >( static_cast< char* >( map ) + \
data[ i ].size ); int* pos;
#if 1
fprintf( stderr, "Loading %s, size %d (%p-%p)\n", data[ i ].file, \
data[ i ].size, map, end ); #endif
madvise( map, data[ i ].size, MADV_WILLNEED );
for( pos = ( int* )( map );
pos < end;
pos += 4096 )
tmp = *pos;
munmap( map, data[ i ].size );
}
close( fd );
}
}
}
["a.cpp" (text/x-c++src)]
int main()
{
for(;;)
{
char* a = new char[ 1048576 ];
for( int i = 0;
i < 1048576;
i += 4096 )
a[ i ] = '\0';
}
}
["kinit.patch" (text/x-diff)]
--- kinit/Makefile.am.sav 2003-07-01 10:05:02.000000000 +0200
+++ kinit/Makefile.am 2004-03-07 20:52:16.000000000 +0100
@@ -28,7 +28,7 @@ kdeinit_SOURCES = kinit.cpp setproctitle
# NOTE: We link against all common libraries even if we don't need them ourselves.
kdeinit_LDFLAGS = $(KDE_MT_LDFLAGS) $(QT_LDFLAGS) $(X_LDFLAGS) $(USER_LDFLAGS) \
$(KDE_RPATH)
-kdeinit_LDADD = $(LIB_KPARTS)
+kdeinit_LDADD = $(LIB_KPARTS) -lbfd -liberty
kioslave_SOURCES = kioslave.cpp
kioslave_LDFLAGS = $(KDE_MT_LDFLAGS) $(QT_LDFLAGS) $(X_LDFLAGS) $(USER_LDFLAGS) \
--- kinit/kinit.cpp.sav 2003-11-18 19:51:15.000000000 +0100
+++ kinit/kinit.cpp 2004-03-08 00:39:55.000000000 +0100
@@ -371,6 +371,55 @@ QCString execpath_avoid_loops( const QCS
return execpath;
}
+static int preload_size;
+static bool preload_read;
+
+#include <bfd.h>
+
+static void preload_count_size( bfd*, asection* sect, PTR )
+{
+ if( !preload_read )
+ return;
+ if( sect->flags & SEC_LOAD )
+ preload_size += bfd_section_size( file, sect );
+ else
+ preload_read = false;
+}
+
+#include <sys/mman.h>
+
+static void preload( const QCString& libpath )
+{
+ return;
+ bfd_init();
+ QCString l( libpath.length() + 10 );
+ strcpy( l.data(), libpath.data());
+ l.data()[ l.length() - 1 ] = 'o';
+ l.data()[ l.length() - 2 ] = 's';
+ l.replace( "/kde3/", "/libkdeinit_" );
+ bfd* file = bfd_openr( l, NULL );
+ if( file == NULL )
+ return;
+ preload_size = 0;
+ preload_read = true;
+ if( !bfd_check_format( file, bfd_object ))
+ return;
+ bfd_map_over_sections (file, preload_count_size, (PTR) NULL);
+ bfd_close( file );
+ fprintf( stderr, "preloading: %d %s\n", preload_size, l.data());
+ int fd = open( libpath, O_RDONLY );
+ if( fd != -1 )
+ {
+ void* m = mmap( 0, preload_size, PROT_READ, MAP_SHARED, fd, 0 );
+ if( m != NULL && m != MAP_FAILED )
+ {
+ madvise( m, preload_size, POSIX_MADV_WILLNEED );
+ munmap( m, preload_size );
+ }
+ close( fd );
+ }
+}
+
static pid_t launch(int argc, const char *_name, const char *args,
const char *cwd=0, int envc=0, const char *envs=0,
bool reset_env = false,
@@ -526,6 +575,8 @@ static pid_t launch(int argc, const char
if ( !libpath.isEmpty() )
{
+ preload( libpath );
+
d.handle = lt_dlopen( QFile::encodeName(libpath) );
if (!d.handle )
{
_______________________________________________
Kde-optimize mailing list
Kde-optimize@kde.org
https://mail.kde.org/mailman/listinfo/kde-optimize
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic