[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