diff options
Diffstat (limited to 'kstartperf')
-rw-r--r-- | kstartperf/Makefile.am | 14 | ||||
-rw-r--r-- | kstartperf/README | 31 | ||||
-rw-r--r-- | kstartperf/kstartperf.cpp | 124 | ||||
-rw-r--r-- | kstartperf/libkstartperf.c | 122 |
4 files changed, 291 insertions, 0 deletions
diff --git a/kstartperf/Makefile.am b/kstartperf/Makefile.am new file mode 100644 index 00000000..9214d389 --- /dev/null +++ b/kstartperf/Makefile.am @@ -0,0 +1,14 @@ +INCLUDES = $(all_includes) + +lib_LTLIBRARIES = libkstartperf.la +libkstartperf_la_LDFLAGS = $(all_libraries) -version-info 1:0 -no-undefined +# libkstartperf_la_LIBADD = ../libltdl/libltdlc.la +libkstartperf_la_SOURCES = libkstartperf.c + +bin_PROGRAMS = kstartperf +kstartperf_LDFLAGS = $(all_libraries) +kstartperf_LDADD = $(LIB_KDECORE) +kstartperf_SOURCES = kstartperf.cpp + +messages: + $(XGETTEXT) $(kstartperf_SOURCES) -o $(podir)/kstartperf.pot diff --git a/kstartperf/README b/kstartperf/README new file mode 100644 index 00000000..ff986444 --- /dev/null +++ b/kstartperf/README @@ -0,0 +1,31 @@ + +** kstartperf: startup time measurement for KDE apps ** + +** Usage: + +kstartperf measures startup time for KDE applications. Usage is simple: + + $ kstartperf konsole + +will show you the startup time of konsole in milliseconds. + + +** How does it work? + +1. Kstartperf stores the current time with microsecond resolution in an + environment variable ($KSTARTPERF). +2. Kstartperf executes the requested application, but with a LD_PRELOAD + library that overrides the X11 XMapWindow() function. +3. As soon as the app calls XMapWindow (this is the point where we assume + that the app has "started up"), our function is called instead of the + original XMapWindow(). This function calculates the time difference + between the current time and the time stored in the environment variable + and prints this information to standard error. +4. Our function disables itself and calls the original XMapWindow(). + +** Notes + +The appliation that is being profiled, needs to be linked against kdecore. + +Geert Jansen <jansen@kde.org>, +20 July 2000 diff --git a/kstartperf/kstartperf.cpp b/kstartperf/kstartperf.cpp new file mode 100644 index 00000000..3f029b62 --- /dev/null +++ b/kstartperf/kstartperf.cpp @@ -0,0 +1,124 @@ +/* vi: ts=8 sts=4 sw=4 + * + * $Id$ + * + * This file is part of the KDE project, module kstartperf. + * Copyright (C) 2000 Geert Jansen <jansen@kde.org> + * + * You can freely redistribute this program under the "Artistic License". + * See the file "LICENSE.readme" for the exact terms. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/time.h> + +#include <qstring.h> +#include <qtextstream.h> +#include <qfile.h> + +#include <kapplication.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <klocale.h> +#include <kstandarddirs.h> + + +static KCmdLineOptions options[] = +{ + { "+command", I18N_NOOP("Specifies the command to run"), 0 }, + KCmdLineLastOption +}; + + +QString libkstartperf() +{ + QString lib = QString::null; + QString la_file = locate("lib", "libkstartperf.la"); + + if (la_file.isEmpty()) + return lib; + + // Find the name of the .so file by reading the .la file + QFile la(la_file); + if (la.open(IO_ReadOnly)) + { + QTextStream is(&la); + QString line; + + while (!is.atEnd()) + { + line = is.readLine(); + if (line.left(15) == "library_names='") + { + lib = line.mid(15); + int pos = lib.find(" "); + if (pos > 0) + lib = lib.left(pos); + } + } + + la.close(); + } + + // Look up the actual .so file. + lib = locate("lib", lib); + return lib; +} + + +int main(int argc, char **argv) +{ + KAboutData aboutData("kstartperf", I18N_NOOP("KStartPerf"), + "1.0", I18N_NOOP("Measures start up time of a KDE application"), + KAboutData::License_Artistic, + "Copyright (c) 2000 Geert Jansen and libkmapnotify authors"); + aboutData.addAuthor("Geert Jansen", I18N_NOOP("Maintainer"), + "jansen@kde.org", "http://www.stack.nl/~geertj/"); + + KCmdLineArgs::init(argc, argv, &aboutData); + KCmdLineArgs::addCmdLineOptions(options); + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + KApplication *app = new KApplication(false, false); + + // Check arguments + + if (args->count() == 0) + { + fprintf(stderr, "No command specified!\n"); + fprintf(stderr, "usage: kstartperf command [arguments]\n"); + exit(1); + } + + // Build command + + char cmd[1024]; + sprintf(cmd, "LD_PRELOAD=%s %s", libkstartperf().latin1(), args->arg(0)); + for (int i=1; i<args->count(); i++) + { + strcat(cmd, " "); + strcat(cmd, args->arg(i)); + } + + // Put the current time in the environment variable `KSTARTPERF' + + struct timeval tv; + if (gettimeofday(&tv, 0L) != 0) + { + perror("gettimeofday()"); + exit(1); + } + char env[100]; + sprintf(env, "KSTARTPERF=%ld:%ld", tv.tv_sec, tv.tv_usec); + putenv(env); + + // And exec() the command + + execl("/bin/sh", "sh", "-c", cmd, (void *)0); + + perror("execl()"); + exit(1); +} diff --git a/kstartperf/libkstartperf.c b/kstartperf/libkstartperf.c new file mode 100644 index 00000000..3c8deae0 --- /dev/null +++ b/kstartperf/libkstartperf.c @@ -0,0 +1,122 @@ +/* vi: ts=8 sts=4 sw=4 + * + * $Id$ + * + * libkstartperf.c: LD_PRELOAD library for startup time measurements. + * + * Copyright (C) 2000 Geert Jansen <jansen@kde.org> + * + * Based heavily on kmapnotify.c: + * + * (C) 2000 Rik Hemsley <rik@kde.org> + * (C) 2000 Simon Hausmann <hausmann@kde.org> + * (C) 2000 Bill Soudan <soudan@kde.org> + */ + +#include <sys/time.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <X11/X.h> +#include <X11/Xlib.h> + +#include <ltdl.h> + + +/* Prototypes */ + +int XMapWindow(Display *, Window); +int XMapRaised(Display *, Window); +void KDE_InterceptXMapRequest(Display *, Window); +void KDE_ShowPerformance(); + +/* Globals */ + +typedef Window (*KDE_XMapRequestSignature)(Display *, Window); +KDE_XMapRequestSignature KDE_RealXMapWindow = 0L; +KDE_XMapRequestSignature KDE_RealXMapRaised = 0L; + + +/* Functions */ + +int XMapWindow(Display * d, Window w) +{ + if (KDE_RealXMapWindow == 0L) + { + KDE_InterceptXMapRequest(d, w); + KDE_ShowPerformance(); + } + return KDE_RealXMapWindow(d, w); +} + +int XMapRaised(Display * d, Window w) +{ + if (KDE_RealXMapRaised == 0L) + { + KDE_InterceptXMapRequest(d, w); + KDE_ShowPerformance(); + } + return KDE_RealXMapRaised(d, w); +} + +void KDE_InterceptXMapRequest(Display * d, Window w) +{ + lt_dlhandle handle; + + handle = lt_dlopen("libX11.so"); + if (handle == 0L) + handle = lt_dlopen("libX11.so.6"); + + if (handle == 0L) + { + fprintf(stderr, "kstartperf: Could not dlopen libX11\n"); + exit(1); + } + + KDE_RealXMapWindow = (KDE_XMapRequestSignature)lt_dlsym(handle, "XMapWindow"); + if (KDE_RealXMapWindow == 0L) + { + fprintf(stderr, "kstartperf: Could not find symbol XMapWindow in libX11\n"); + exit(1); + } + + KDE_RealXMapRaised = (KDE_XMapRequestSignature)lt_dlsym(handle, "XMapRaised"); + if (KDE_RealXMapRaised == 0L) + { + fprintf(stderr, "kstartperf: Could not find symbol XMapRaised in libX11\n"); + exit(1); + } +} + +void KDE_ShowPerformance() +{ + char *env; + long l1, l2; + float dt; + struct timeval tv; + + env = getenv("KSTARTPERF"); + if (env == 0L) + { + fprintf(stderr, "kstartperf: $KSTARTPERF not set!\n"); + exit(1); + } + if (sscanf(env, "%ld:%ld", &l1, &l2) != 2) + { + fprintf(stderr, "kstartperf: $KSTARTPERF illegal format\n"); + exit(1); + } + + if (gettimeofday(&tv, 0L) != 0) + { + fprintf(stderr, "kstartperf: gettimeofday() failed.\n"); + exit(1); + } + + dt = 1e3*(tv.tv_sec - l1) + 1e-3*(tv.tv_usec - l2); + fprintf(stderr, "\nkstartperf: measured startup time at %7.2f ms\n\n", dt); +} + |