Git commit 04abd13af61f71e16e79318a9c62ee1c9234dabf by Luigi Toscano. Committed on 20/02/2017 at 00:56. Pushed by ltoscano into branch 'frameworks'.
Remove kmtrace, kprofilemethod, kstartperf As discussed on release-team@ mailing list (thanks dfaure), they are obsolete, broken or both: - kprofilemethod should to be replaced with something better/more convienent; - kstartperf intercepts X11 calls, but Qt switched to XCB; - kmtrace, which still needed to replace Q3Support and was not possible to reproduce its behavior, is definitely replaced by the heaptrack memory profiler. See: https://mail.kde.org/pipermail/release-team/2017-February/010119.html M +0 -3 CMakeLists.txt D +0 -101 kmtrace/CMakeLists.txt D +0 -110 kmtrace/README D +0 -51 kmtrace/demangle.cpp D +0 -1 kmtrace/doc/CMakeLists.txt D +0 -63 kmtrace/doc/man-demangle.1.docbook D +0 -49 kmtrace/kde.excludes D +0 -9 kmtrace/kminspector.cmake D +0 -730 kmtrace/kmtrace.cpp D +0 -11 kmtrace/ksotrace.cpp D +0 -844 kmtrace/ktrace.c D +0 -10 kmtrace/ktrace.h D +0 -67 kmtrace/match.cpp D +0 -383 kmtrace/mtrace.c D +0 -9 kprofilemethod/CMakeLists.txt D +0 -21 kprofilemethod/README D +0 -51 kprofilemethod/kprofilemethod.h D +0 -57 kstartperf/CMakeLists.txt D +0 -2 kstartperf/Messages.sh D +0 -67 kstartperf/README D +0 -147 kstartperf/kstartperf.cpp D +0 -140 kstartperf/libkstartperf.c https://commits.kde.org/kde-dev-utils/04abd13af61f71e16e79318a9c62ee1c9234dabf diff --git a/CMakeLists.txt b/CMakeLists.txt index 7583bf1..cf05949 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,4 @@ cmake_minimum_required(VERSION 2.8.12) -# add_subdirectory(kmtrace) add_subdirectory(kpartloader) -add_subdirectory(kprofilemethod) -add_subdirectory(kstartperf) add_subdirectory(kuiviewer) diff --git a/kmtrace/CMakeLists.txt b/kmtrace/CMakeLists.txt deleted file mode 100644 index da4e131..0000000 --- a/kmtrace/CMakeLists.txt +++ /dev/null @@ -1,101 +0,0 @@ -project(kmtrace) - -cmake_minimum_required(VERSION 2.8.12) - -find_package(ECM 1.7 REQUIRED NO_MODULE) -set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) - -set(QT_MIN_VERSION "5.5.0") - -include(FeatureSummary) -include(KDEInstallDirs) -include(KDECMakeSettings) -include(KDECompilerSettings NO_POLICY_SCOPE) -include(CheckIncludeFile) -include(CheckIncludeFileCXX) -include(CheckLibraryExists) -include(CheckCSourceCompiles) - -find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE - COMPONENTS - Core -) - -find_package(KF5 REQUIRED - COMPONENTS - CoreAddons - KDELibs4Support -) - -check_c_source_compiles(" -#include <stdlib.h> - -int main() { -#ifndef __GLIBC__ - choke me -#endif - return 0; -}" LIBC_IS_GLIBC) - -# Check if libiberty is available -find_library(LIBIBERTY_LIBRARY NAMES iberty) -if (LIBIBERTY_LIBRARY AND LIBC_IS_GLIBC) - - include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kminspector.cmake ${CMAKE_CURRENT_BINARY_DIR}/kminspector ) - INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/kminspector DESTINATION ${KDE_INSTALL_BINDIR}) - ########### kmtrace ############### - - set(kmtrace_SRCS kmtrace.cpp) - - - add_executable(kmtrace ${kmtrace_SRCS}) - - target_link_libraries(kmtrace ${LIBIBERTY_LIBRARY} KF5::KDELibs4Support ${QT_QT3SUPPORT_LIBRARY}) - -install(TARGETS kmtrace ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) - - ########### demangle ############### - - set(demangle_SRCS demangle.cpp) - - - add_executable(demangle ${demangle_SRCS}) - - target_link_libraries(demangle ${LIBIBERTY_LIBRARY} Qt5::Core) - -install(TARGETS demangle ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) - - - ########### kmmatch ############### - - set(kmmatch_SRCS match.cpp) - - - add_executable(kmmatch ${kmmatch_SRCS}) - - target_link_libraries(kmmatch Qt5::Core) - -install(TARGETS kmmatch ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) - - - ########### ktrace ############### - - set(ktrace_LIB_SRCS ksotrace.cpp ktrace.c) - - - add_library(ktrace SHARED ${ktrace_LIB_SRCS}) - - target_link_libraries(ktrace dl) - - set_target_properties(ktrace PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) -install(TARGETS ktrace ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) - - ########### install files ############### - -install( FILES kde.excludes DESTINATION ${KDE_INSTALL_DATADIR}/kmtrace ) - install( FILES ktrace.h DESTINATION ${KDE_INSTALL_INCLUDEDIR} COMPONENT Devel ) - -add_subdirectory( doc ) - -endif () diff --git a/kmtrace/README b/kmtrace/README deleted file mode 100644 index 63e3522..0000000 --- a/kmtrace/README +++ /dev/null @@ -1,110 +0,0 @@ -This is a KDE tool to assist with malloc debugging using glibc's "mtrace" -functionality. Unfortunately the mtrace that is part of current (9/9/2000) -glibc versions only logs the return-address of the malloc/free call. -The file mtrace.c in this directory logs a complete backtrace upon malloc/ -free. - -THIS PROGRAM DEPENDS ON GLIBC! It does not pretend to be portable. - -Howto use: - -Install the libktrace.so shared library, the ktrace.h header file, the -and kde.excludes file and the kmtrace processing tool with: - - make install - -There are two ways to activate memory usage loggings by ktrace : - -1) The LD_PRELOAD way - -This way, you can debug any application without having to recompile it, -but you'll have to debug also the memory allocated by KApplication and -friends. - -You can activate malloc logging by starting yourApplication as: - - MALLOC_TRACE=/tmp/ktrace.out LD_PRELOAD=$KDEDIR/lib/libktrace.so yourApplication - -2) The manual way - -Take the KDE application that you want to investigate and add - - #include <ktrace.h> - -Add as first statement in main(): - - ktrace(); - -Add ktrace_s.a to the LDADD line in your Makefile.am like: - - kicker_LDADD = kicker.la /opt/kde/lib/libktrace_s.a - -Note that the static library is used. -You can now activate malloc logging by starting yourApplication as: - - MALLOC_TRACE=/tmp/ktrace.out yourApplication - -This will generate a huge log in /tmp/ktrace.out. - -You can process this log with: - - kmtrace /tmp/ktrace.out > ktrace.parsed - -By default the trace-output is stored in the current directory -as "ktrace.out". kmtrace also searches it there, so you don't need -to add any commandline options. - -TIPS -==== - -* If you can't be bothered with the stuff that KApplication allocates for you -you might want to put the ktrace() call after the KApplication constructor. -This will lead to a lot of warnings like: - - Freeing unalloacted memory: 0x08056108 - -Which are harmless, it just means that the memory was allocated before you -turned the tracing on. Note that you cannot use this if you're using -LD_PRELOAD to use ktrace. - -* To filter out harmless allocations out of the output file you can specify -with the --exclude option a file with symbols to exclude from output. If a -backtrace contains a symbol that starts with any of the symbols in this file, -this backtrace / leaked block is not shown in the output. - -In the file kde.exclude some example symbols are listed. Usage example: - - kmtrace /tmp/malloc.trace > /tmp/malloc.parsed - -* Be aware that the reported symbols may not be accurate under all -circumstances. E.g. consider the following backtrace: - - 0x405879c1 /lib/libdl.so.2(dlerror+0x1b1) - 0x405873b3 /lib/libdl.so.2(dlopen+0x33) - 0x4053c0b2 /ext/kde2.0/lib/libkdecore.so.3(QXmlSimpleReader::reportParseErro - 0x4053c74b /ext/kde2.0/lib/libkdecore.so.3(lt_dlexit+0x24b) - 0x4053c894 /ext/kde2.0/lib/libkdecore.so.3(lt_dlexit+0x394) - 0x4053dd49 /ext/kde2.0/lib/libkdecore.so.3(lt_dlopen+0x899) - -The QXmlSimpleReader is obviously wrong here. - -* You can use the --tree option to kmtrace to specify a file to print a tree -of the allocations. You can also use --treedepth and --treethreshold options -to hide subtrees that are deeper than the specified depth or allocated less -than the given memory amount. - -* The advantage of using libktrace_s.a (the static library) is that you can -put calls to ktrace() and kuntrace() around a block of code that -interests you. Only allocations and deallocations between the first call -to ktrace() and the first call to kuntrace() will be logged. - - -Have fun. - -Waldo Bastian [email protected] - -kmtrace.cpp by Waldo Bastian <[email protected]> -ktrace.c by Waldo Bastian <[email protected]> based on mtrace.c -mtrace.c by Mike Haertel <[email protected]> -mtrace.c patched by Andi Kleen <[email protected]> diff --git a/kmtrace/demangle.cpp b/kmtrace/demangle.cpp deleted file mode 100644 index 7712681..0000000 --- a/kmtrace/demangle.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// Qt -#include <QByteArray> -// C++ -#include <stdio.h> -#include <stdlib.h> - -extern "C" { -/* Options passed to cplus_demangle (in 2nd parameter). */ - -#define DMGL_NO_OPTS 0 /* For readability... */ -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ - -#define DMGL_AUTO (1 << 8) -#define DMGL_GNU (1 << 9) -#define DMGL_LUCID (1 << 10) -#define DMGL_ARM (1 << 11) -#define DMGL_HP (1 << 12) /* For the HP aCC compiler; same as ARM - except for template arguments, etc. */ -#define DMGL_EDG (1 << 13) -#define DMGL_GNU_V3 (1 << 14) -#define DMGL_GNAT (1 << 15) - - -extern char *cplus_demangle(const char *mangled, int options); -} - - -int main(int /*argc*/, char **/*argv*/) -{ - char buf[1024]; - - while(!feof(stdin)) - { - fgets(buf, 1024, stdin); - QByteArray line = buf; - line = line.trimmed(); - char *res = cplus_demangle(line.data(), DMGL_PARAMS | DMGL_AUTO | DMGL_ANSI ); - if (res) - { - printf("%s\n", res); - free(res); - } - else - { - printf("%s\n", line.data()); - } - } -} - diff --git a/kmtrace/doc/CMakeLists.txt b/kmtrace/doc/CMakeLists.txt deleted file mode 100644 index e518148..0000000 --- a/kmtrace/doc/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -kdoctools_create_manpage(man-demangle.1.docbook 1 INSTALL_DESTINATION ${KDE_INSTALL_MANDIR} SUBDIR kmtrace) diff --git a/kmtrace/doc/man-demangle.1.docbook b/kmtrace/doc/man-demangle.1.docbook deleted file mode 100644 index 4004325..0000000 --- a/kmtrace/doc/man-demangle.1.docbook +++ /dev/null @@ -1,63 +0,0 @@ -<?xml version="1.0" ?> -<!DOCTYPE refentry PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [ -<!ENTITY % English "INCLUDE"> -]> - -<refentry lang="&language;"> -<refentryinfo> -<author><personname><firstname>Ben</firstname><surname>Burton</surname></personname> -<email>[email protected]</email></author> -<date>April 7, 2003</date> -</refentryinfo> - -<refmeta> -<refentrytitle><command>demangle</command></refentrytitle> -<manvolnum>1</manvolnum> -</refmeta> - -<refnamediv> -<refname><command>demangle</command></refname> -<refpurpose>Undo C++ name mangling for symbols</refpurpose> -</refnamediv> - -<refsynopsisdiv> -<cmdsynopsis> -<command>demangle</command> -</cmdsynopsis> -</refsynopsisdiv> - -<refsect1> -<title>Description</title> - -<para><command>demangle</command> reads a list of C++ mangled symbol names from standard input and converts these names to human-readable form on standard output.</para> - -<para>This utility is part of the &kde; Software Development Kit.</para> - -</refsect1> - -<refsect1> -<title>Example</title> - -<para>Create a file called <filename>names</filename> containing the following mangled symbol names:</para> - -<programlisting>_ZNK6Object10metaObjectEv -_ZN8QPtrListI5ArrowE5clearEv -_ZTC4Kolf0_11KMainWindow</programlisting> - -<para>These names can then be demangled as follows:</para> - -<screen><prompt>example$</prompt> <userinput><command>demangle</command> < <filename>names</filename></userinput> -<computeroutput>Object::metaObject() const -QPtrList<Arrow>::clear() -construction vtable for KMainWindow-in-Kolf</computeroutput></screen> - -</refsect1> - -<refsect1> -<title>See Also</title> - -<para>kminspector(1) kmtrace(1) match(1)</para> - -</refsect1> - -</refentry> diff --git a/kmtrace/kde.excludes b/kmtrace/kde.excludes deleted file mode 100644 index 9e77eb5..0000000 --- a/kmtrace/kde.excludes +++ /dev/null @@ -1,49 +0,0 @@ -# We don't care about initialisation done by X11. -XLoadQueryFont -_XInitKeysymDB -IceRegisterForProtocolSetup -KDE_IceRegisterForProtocolSetup -IceOpenConnection -KDE_IceOpenConnection -KDE_IceProtocolSetup -#and we don't care about Xim memleaks -qt_init_internal -QApplication::create_xim -# workaround for Qt 2.2.0 bug -QFontDatabase::QFontDatabase -QFontDatabase::charSets - -#QRexExp does caching(?) -QRegExpEngine::QRegExpEngine -QRegExpEngine::parseExpression - -QStyleSheet::defaultSheet - -QTimer::singleShot -QTextCodec::codecForLocale -# Yeah, yeah we know that this metaobject stuff is never free'ed. -QMetaObject::new_meta -QObject::initMetaObject -QObject::staticMetaObject -QString::sprintf -QWidget::createTLExtra -# static KDE stuff -kdbgstream::flush -KCmdLineArgs::addCmdLineOptions -k_bindtextdomain -_nl_find_domain -KIconTheme::list -KIconTheme::current -KGlobalSettings::toolBarFont -KGlobalSettings::menuFont -KGlobalSettings::fixedFont -KGlobalSettings::generalFont -KGlobalSettings::toolBarFont -KImageIOFactory::self -objMap -# Some C functions that allocate data for initialisation -getpwuid -adjtime -getservbyname -# nothing created by static objects can be a memory leak -__static_initialization_and_destruction_0 diff --git a/kmtrace/kminspector.cmake b/kmtrace/kminspector.cmake deleted file mode 100755 index 18e35a2..0000000 --- a/kmtrace/kminspector.cmake +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -export MALLOC_TREE=kminspector.tree -export MALLOC_THRESHOLD=2000 -export LD_PRELOAD=${KDE_INSTALL_LIBDIR}/libktrace.so - -$* - -cat kminspector.tree | less diff --git a/kmtrace/kmtrace.cpp b/kmtrace/kmtrace.cpp deleted file mode 100644 index ce2ee1c..0000000 --- a/kmtrace/kmtrace.cpp +++ /dev/null @@ -1,730 +0,0 @@ -#include <q3intdict.h> -//Added by qt3to4: -#include <stdio.h> -#include <qstringlist.h> -#include <q3strlist.h> -#include <qtextstream.h> -#include <q3sortedlist.h> -#include <qfile.h> -#include <q3tl.h> -#include <q3valuelist.h> -#include <Q3CString> -#include <stdlib.h> -#include <QTemporaryFile> - -#include <kshell.h> -#include <QApplication> -#include <QCommandLineParser> -#include <QCommandLineOption> -#include <QStandardPaths> - -extern "C" { -/* Options passed to cplus_demangle (in 2nd parameter). */ - -#define DMGL_NO_OPTS 0 /* For readability... */ -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ - -#define DMGL_AUTO (1 << 8) -#define DMGL_GNU (1 << 9) -#define DMGL_LUCID (1 << 10) -#define DMGL_ARM (1 << 11) -#define DMGL_HP (1 << 12) /* For the HP aCC compiler; same as ARM - except for template arguments, etc. */ -#define DMGL_EDG (1 << 13) -#define DMGL_GNU_V3 (1 << 14) -#define DMGL_GNAT (1 << 15) - - -extern char *cplus_demangle(const char *mangled, int options); -} - -struct Entry { - int base; - int size; - int signature; - int count; - int total_size; - int backtrace[1]; - - bool operator==(const Entry &e) { return total_size == e.total_size; } - bool operator<(const Entry &e) { return total_size > e.total_size; } -}; - -Q3IntDict<Entry> *entryDict = 0; -Q3IntDict<char> *symbolDict = 0; -Q3IntDict<char> *formatDict = 0; -Q3SortedList<Entry> *entryList = 0; -Q3StrList *excludes = 0; - -const char * const unknown = "<unknown>"; -const char * const excluded = "<excluded>"; -int allocCount = 0; -int leakedCount = 0; -int count = 0; -int maxCount; -int totalBytesAlloced = 0; -int totalBytesLeaked = 0; -int totalBytes = 0; -int maxBytes; - -int fromHex(const char *str); -void parseLine(const QString &_line, char operation); -void dumpBlocks(); - -int fromHex(const char *str) -{ - if (*str == '[') str++; - str += 2; // SKip "0x" - return strtoll(str, NULL, 16); -} - -// [address0][address1] .... [address] + base size -void parseLine(const QString &_line, char operation) -{ - char *line= (char *) _line.data(); - const char *cols[200]; - int i = 0; - cols[i++] = line; - while(*line) - { - if (*line == ' ') - { - *line = 0; - line++; - while (*line && (*line==' ')) line++; - if (*line) cols[i++] = line; - } - else line++; - } - int cols_count = i; - if (cols_count > 199) fprintf(stderr, "Error cols_count = %d\n", cols_count); - if (cols_count < 4) return; - switch (operation) - { - case '+': - { - Entry *entry = (Entry *) malloc((cols_count+3) *sizeof(int)); - entry->base = fromHex(cols[cols_count-2]); - entry->size = fromHex(cols[cols_count-1]); - int signature = 0; - for(int i = cols_count-3; i--;) - { - signature += (entry->backtrace[i-1] = fromHex(cols[i])); - } - entry->signature = (signature / 4)+cols_count; - entry->count = 1; - entry->total_size = entry->size; - entry->backtrace[cols_count-4] = 0; - totalBytesAlloced += entry->size; - totalBytes += entry->size; - count++; - if (totalBytes > maxBytes) - maxBytes = totalBytes; - if (count > maxCount) - maxCount = count; - if (entryDict->find(entry->base)) - fprintf(stderr, "\rAllocated twice: 0x%08x \n", entry->base); - entryDict->replace(entry->base, entry); - } break; - case '-': - { - int base = fromHex(cols[cols_count-1]); - Entry *entry = entryDict->take(base); - if (!entry) - { - if (base) - fprintf(stderr, "\rFreeing unalloacted memory: 0x%08x \n", base); - } - else - { - totalBytes -= entry->size; - count--; - free(entry); - } - } break; - default: - break; - } -} - -void sortBlocks() -{ - Q3IntDictIterator<Entry> it(*entryDict); - for(;it.current(); ++it) - { - Entry *entry = it.current(); - totalBytesLeaked += entry->total_size; - entryList->append(entry); - for(int i = 0; entry->backtrace[i]; i++) - { - if (!symbolDict->find(entry->backtrace[i])) - symbolDict->insert(entry->backtrace[i], unknown); - } - } - entryList->sort(); -} - -void collectDupes() -{ - Q3IntDict<Entry> dupeDict; - Q3IntDictIterator<Entry> it(*entryDict); - for(;it.current();) - { - Entry *entry = it.current(); - ++it; - Entry *entry2 = dupeDict.find(entry->signature); - if (entry2) - { - entry2->count++; - entry2->total_size += entry->size; - entryDict->remove(entry->base); - } - else - { - dupeDict.insert(entry->signature, entry); - } - } -} - -int lookupSymbols(FILE *stream) -{ - int i = 0; - int symbols = 0; - char line2[1024]; - while(!feof(stream)) - { - fgets(line2, 1023, stream); - if (line2[0] == '=' ) - { - if(strcmp(line2,"= End") == 0 ) - break; - } - else if (line2[0] == '#') - ; - else if (line2[0] == '@') - ; - else if (line2[0] == '[') - ; - else if (line2[0] == '-') - ; - else if (line2[0] == '<') - ; - else if (line2[0] == '>') - ; - else if (line2[0] == '+') - { - i++; - if (i & 1024) - { - fprintf(stderr, "\rLooking up symbols: %d found %d of %d symbols", i, symbols, symbolDict->count()); - } - } - else - { - char *addr = index(line2, '['); - if (addr) - { - long i_addr = fromHex(addr); - const char* str = symbolDict->find(i_addr); - if (str == unknown) - { - *addr = 0; - char* str; - if( rindex(line2, '/') != NULL ) - str = qstrdup(rindex(line2, '/')+1); - else - str = qstrdup(line2); - symbolDict->replace(i_addr, str); - symbols++; - } - } - } - } - fprintf(stderr, "\rLooking up symbols: %d found %d of %d symbols\n", i, symbols, symbolDict->count()); - return symbolDict->count()-symbols; -} - -void lookupUnknownSymbols(const char *appname) -{ - QTemporaryFile inputFile; - QTemporaryFile outputFile; - inputFile.open(); - outputFile.open(); - QTextStream str ( &inputFile ); - Q3IntDict<char> oldDict = *symbolDict; - Q3IntDictIterator<char> it(oldDict); - for(;it.current(); ++it) - { - QString temp; - temp.sprintf("%08lx\n", it.currentKey()); - str << temp; - } - str.flush(); - Q3CString command; - command.sprintf("addr2line -e %s -f -C -s < %s > %s", appname, - QFile::encodeName(KShell::quoteArg(inputFile.fileName())).data(), - QFile::encodeName(KShell::quoteArg(outputFile.fileName())).data()); - system(command.data()); - FILE *fInputFile = fopen(QFile::encodeName(outputFile.fileName()), "r"); - if (!fInputFile) - { - fprintf(stderr, "Error opening temp file.\n"); - return; - } - Q3IntDictIterator<char> it2(oldDict); - char buffer1[1024]; - char buffer2[1024]; - for(;it2.current(); ++it2) - { - if (feof(fInputFile)) - { - fprintf(stderr, "Premature end of symbol output.\n"); - fclose(fInputFile); - return; - } - if (!fgets(buffer1, 1023, fInputFile)) continue; - if (!fgets(buffer2, 1023, fInputFile)) continue; - buffer1[strlen(buffer1)-1]=0; - buffer2[strlen(buffer2)-1]=0; - Q3CString symbol(sizeof(buffer1) + sizeof(buffer2) + 3); - symbol.sprintf("%s(%s)", buffer2, buffer1); - if(*buffer1 != '?') - symbolDict->replace(it2.currentKey(),qstrdup(symbol.data())); - } - fclose(fInputFile); -} - -int match(const char *s1, const char *s2) -{ - register int result; - while(true) - { - result = *s1 - *s2; - if (result) - return result; - s1++; - s2++; - if (!*s2) return 0; - if (!*s1) return -1; - } - return 0; -} - -const char *lookupAddress(int addr) -{ - char *str = formatDict->find(addr); - if (str) return str; - QByteArray s = symbolDict->find(addr); - if (s.isEmpty()) - { -fprintf(stderr, "Error!\n"); - exit(1); - } - else - { - int start = s.indexOf('('); - int end = s.lastIndexOf('+'); - if (end < 0) - end = s.lastIndexOf(')'); - if ((start > 0) && (end > start)) - { - QByteArray symbol = s.mid(start+1, end-start-1); - char *res = 0; - if (symbol.indexOf(')') == -1) - res = cplus_demangle(symbol.data(), DMGL_PARAMS | DMGL_AUTO | DMGL_ANSI ); - - if (res) - { - symbol = res; - free(res); - } - res = (char *) symbol.data(); - for(const char *it = excludes->first();it;it = excludes->next()) - { - int i = match(res, it); - if (i == 0) - { - formatDict->insert(addr,excluded); - return excluded; - } - } - s.replace(start+1, end-start-1, symbol); - } - } - str = qstrdup(s.data()); - formatDict->insert(addr,str); - return str; -} - -void dumpBlocks() -{ - int filterBytes = 0; - int filterCount = 0; - for(Entry *entry = entryList->first();entry; entry = entryList->next()) - { - for(int i = 0; entry->backtrace[i]; i++) - { - const char *str = lookupAddress(entry->backtrace[i]); - if (str == excluded) - { - entry->total_size = 0; - continue; - } - } - if (!entry->total_size) continue; - filterBytes += entry->total_size; - filterCount++; - } - printf("Leaked memory after filtering: %d bytes in %d blocks.\n", filterBytes, filterCount); - for(Entry *entry = entryList->first();entry; entry = entryList->next()) - { - if (!entry->total_size) continue; - printf("[%d bytes in %d blocks, 1st. block is %d bytes at 0x%08x] ", entry->total_size, entry->count, entry->size, entry->base); - printf("\n"); - for(int i = 0; entry->backtrace[i]; i++) - { - const char *str = lookupAddress(entry->backtrace[i]); - printf(" 0x%08x %s\n", entry->backtrace[i], str); - } - } -} - -struct TreeEntry -{ - int address; // backtrace - int total_size; - int total_count; - typedef QList < TreeEntry > TreeList; - TreeList *subentries () const; - mutable TreeList *_subentries; - TreeEntry (int adr = 0, int size = 0, int count = 0, TreeList * sub = NULL ); - bool operator == (const TreeEntry &) const; - bool operator < (const TreeEntry &) const; -}; - -typedef QList < TreeEntry > TreeList; - -inline TreeEntry::TreeEntry (int adr, int size, int count, TreeList * sub) - : address (adr), total_size (size), total_count (count), _subentries (sub) -{ -} - -inline bool TreeEntry::operator == (const TreeEntry & r) const -{ // this one is for QValueList - return address == r.address; -} - -inline -bool TreeEntry::operator < (const TreeEntry & r) const -{ // this one is for qBubbleSort() ... yes, ugly hack - // the result is also reversed to get descending order - return total_size > r.total_size; -} - -inline TreeList * TreeEntry::subentries () const -{ // must be allocated only on-demand - if (_subentries == NULL) - _subentries = new TreeList; // this leaks memory, but oh well - return _subentries; -} - -TreeList * treeList = 0; - -void buildTree () -{ - for (Entry * entry = entryList->first (); - entry != NULL; entry = entryList->next ()) - { - if (!entry->total_size) - continue; - TreeList * list = treeList; - int i; - for (i = 0; entry->backtrace[i]; ++i) - ; // find last (topmost) backtrace entry - for (--i; i >= 0; --i) - { - TreeList::Iterator pos = qFind(list->begin(), list->end(), entry->backtrace[i]); - if (pos == list->end ()) - { - list->prepend (TreeEntry (entry->backtrace[i], entry->total_size, - entry->count)); - pos = list->begin(); - } - else - *pos = TreeEntry (entry->backtrace[i], - entry->total_size + (*pos).total_size, - entry->count + (*pos).total_count, - (*pos)._subentries); - list = (*pos).subentries (); - } - } -} - -void processTree (TreeList * list, int threshold, int maxdepth, int depth) -{ - if (++depth > maxdepth && maxdepth > 0) // maxdepth <= 0 means no limit - return; - for (TreeList::Iterator it = list->begin (); it != list->end ();) - { - if ((*it).subentries ()->count () > 0) - processTree ((*it).subentries (), threshold, maxdepth, depth); - if ((*it).total_size < threshold || (depth > maxdepth && maxdepth > 0)) - { - it = list->erase(it); - continue; - } - ++it; - } - qBubbleSort (*list); -} - -void -dumpTree (const TreeEntry & entry, int level, char *indent, FILE * file) -{ - bool extra_ind = (entry.subentries ()->count () > 0); - if(extra_ind) - indent[level++] = '+'; - indent[level] = '\0'; - char savindent[2]; - const char * str = lookupAddress (entry.address); - fprintf (file, "%s- %d/%d %s[0x%08x]\n", indent, - entry.total_size, entry.total_count, str, entry.address); - if (level > 1) - { - savindent[0] = indent[level - 2]; - savindent[1] = indent[level - 1]; - if (indent[level - 2] == '+') - indent[level - 2] = '|'; - else if (indent[level - 2] == '\\') - indent[level - 2] = ' '; - } - int pos = 0; - int last = entry.subentries ()->count() - 1; - for (TreeList::ConstIterator it = entry.subentries ()->constBegin (); - it != entry.subentries ()->constEnd (); ++it) - { - if (pos == last) - indent[level - 1] = '\\'; - dumpTree ((*it), level, indent, file); - ++pos; - } - if (level > 1) - { - indent[level - 2] = savindent[0]; - indent[level - 1] = savindent[1]; - } - if (extra_ind) - --level; - indent[level] = '\0'; -} - -void dumpTree (FILE * file) -{ - char indent[1024]; - indent[0] = '\0'; - for (TreeList::ConstIterator it = treeList->constBegin (); - it != treeList->constEnd (); ++it) - dumpTree (*it, 0, indent, file); -} - -void createTree (const QString & treefile, int threshold, int maxdepth) -{ - FILE * file = fopen (treefile.toLocal8Bit(), "w"); - if (file == NULL) - { - fprintf (stderr, "Can't write tree file.\n"); - return; - } - treeList = new TreeList; - buildTree (); - processTree (treeList, threshold, maxdepth, 0); - dumpTree (file); - fclose (file); -} - -void readExcludeFile(const char *name) -{ - FILE *stream = fopen(name, "r"); - if (!stream) - { - fprintf(stderr, "Error: Can't open %s.\n", name); - exit(1); - } - char line[1024]; - while(!feof(stream)) - { - if (!fgets(line, 1023, stream)) break; - if ((line[0] == 0) || (line[0] == '#')) continue; - line[strlen(line)-1] = 0; - excludes->append(line); - } - fclose(stream); - excludes->sort(); -} - -int main(int argc, char *argv[]) -{ - QApplication app(argc, argv); - - KAboutData aboutData( QLatin1String("kmtrace"), i18n("kmtrace"), QLatin1String("v1.0")); - aboutData.setShortDescription(i18n("KDE Memory leak tracer")); - QCommandLineParser parser; - KAboutData::setApplicationData(aboutData); - parser.addVersionOption(); - parser.addHelpOption(); - aboutData.setupCommandLine(&parser); - - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("x") << QLatin1String("exclude"), i18n("File containing symbols to exclude from output"), QLatin1String("file"))); - - - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("e") << QLatin1String("exe"), i18n("Executable to use for looking up unknown symbols"), QLatin1String("file"))); - - parser.addPositionalArgument(QLatin1String("<trace-log>"), i18n("Log file to investigate")); - - - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("t") << QLatin1String("tree"), i18n("File to write allocations tree"), QLatin1String("file"))); - - - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("th") << QLatin1String("treethreshold"), i18n("Do not print subtrees which allocated less than <value> memory"), QLatin1String("value"))); - - - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("td") << QLatin1String("treedepth"), i18n("Do not print subtrees that are deeper than <value>"), QLatin1String("value"))); - - parser.process(app); - aboutData.processCommandLine(&parser); - - (void) parser.positionalArguments().count(); - const char *logfile; - if(parser.positionalArguments().count()) - logfile = args->arg(0).toLocal8Bit(); - else - logfile = "ktrace.out"; - - QString exe = parser.value("exe"); - QByteArray exclude; - - excludes = new Q3StrList; - - exclude = QFile::encodeName(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kmtrace/kde.excludes")); - if(!exclude.isEmpty()) - readExcludeFile(exclude); - - exclude = parser.value("exclude").toLocal8Bit().data(); - if (!exclude.isEmpty()) - { - fprintf(stderr, "Reading %s\n", exclude.data()); - readExcludeFile(exclude); - } - - FILE *stream = fopen(logfile, "r"); - if (!stream) - { - fprintf(stderr, "Can't open %s\n", logfile); - exit(1); - } - - entryDict = new Q3IntDict<Entry>(9973); - symbolDict = new Q3IntDict<char>(9973); - formatDict = new Q3IntDict<char>(9973); - entryList = new Q3SortedList<Entry>; - - fprintf(stderr, "Running\n"); - QString line; - char line2[1024]; - while(!feof(stream)) - { - fgets(line2, 1023, stream); - line2[strlen(line2)-1] = 0; - if (line2[0] == '=') - { - printf("%s\n", line2); - if( strcmp( line2, "= End" ) == 0 ) - break; - } - else if (line2[0] == '#') - { - QByteArray app(line2+1); - if(exe.isEmpty()) - { - exe = app.trimmed(); - fprintf(stderr, "ktrace.out: malloc trace of %s\n", exe.data()); - } - else if(!app.contains(exe.toLocal8Bit().data())) - { - fprintf(stderr, "trace file was for application '%s', not '%s'\n", app.data(), exe.data()); - exit(1); - } - } - else if (line2[0] == '@') - line = QString(); - else if (line2[0] == '[') - line = line + ' ' + line2; - else if (line2[0] == '+') - { - allocCount++; - line = line + ' ' + line2; - parseLine(line, '+'); - line = QString(); - if (allocCount & 128) - { - fprintf(stderr, "\rTotal long term allocs: %d still allocated: %d ", allocCount, entryDict->count()); - } - } - else if (line2[0] == '-') - { - line = line + ' ' + line2; - parseLine(line, '-'); - line = QString(); - } - else if (line2[0] == '<') - { - line2[0] = '-'; - // First part of realloc (free) - QString reline = line + ' ' + line2; - parseLine(reline, '-'); - } - else if (line2[0] == '>') - { - line2[0] = '+'; - // Second part of realloc (alloc) - line = line + ' ' + line2; - parseLine(line, '+'); - line = QString(); - } - else - { - const char *addr = index(line2,'['); - if (addr) - { - line = line + QChar(' ') + addr; - } - } - } - leakedCount = count; - fprintf(stderr, "\rTotal long term allocs: %d still allocated: %d(%d) \n", allocCount, leakedCount, entryDict->count()); - printf("Totals allocated: %d bytes in %d blocks.\n", totalBytesAlloced, allocCount); - printf("Maximum allocated: %d bytes / %d blocks.\n", maxBytes, maxCount); - fprintf(stderr, "Collecting duplicates...\n"); - collectDupes(); - fprintf(stderr, "Sorting...\n"); - sortBlocks(); - printf("Totals leaked: %d bytes in %d blocks.\n", totalBytesLeaked, leakedCount); - fprintf(stderr, "Looking up symbols...\n"); - rewind(stream); - lookupSymbols(stream); - fprintf(stderr, "Looking up unknown symbols...\n"); - lookupUnknownSymbols(exe.toLocal8Bit()); - fprintf(stderr, "Printing...\n"); - dumpBlocks(); - QString treeFile = parser.value ("tree"); - if (!treeFile.isEmpty ()) - { - fprintf (stderr, "Creating allocation tree...\n"); - createTree (treeFile, parser.value ("treethreshold").toInt (), - parser.value ("treedepth").toInt ()); - } - fprintf(stderr, "Done.\n"); - return 0; -} diff --git a/kmtrace/ksotrace.cpp b/kmtrace/ksotrace.cpp deleted file mode 100644 index 9f37941..0000000 --- a/kmtrace/ksotrace.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "ktrace.h" -#include <stdlib.h> - -class KTraceActivate -{ -public: - KTraceActivate() { setenv("LD_PRELOAD","",1); ktrace(); } - ~KTraceActivate() { kuntrace(); } -} kTraceActivateInstance; - - diff --git a/kmtrace/ktrace.c b/kmtrace/ktrace.c deleted file mode 100644 index b61af0c..0000000 --- a/kmtrace/ktrace.c +++ /dev/null @@ -1,844 +0,0 @@ -/* More debugging hooks for `malloc'. - Copyright (C) 1991,92,93,94,96,97,98,99,2000 Free Software Foundation, Inc. - Written April 2, 1991 by John Gilmore of Cygnus Support. - Based on mcheck.c by Mike Haertel. - Hacked by AK - Cleanup and performance improvements by - Chris Schlaeger <[email protected]> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - The author may be reached (Email) at the address [email protected], - or (US mail) as Mike Haertel c/o Free Software Foundation. -*/ - -#define MALLOC_HOOKS -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <pthread.h> -#include <malloc.h> - -#include <dlfcn.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <execinfo.h> -#include <unistd.h> - -#ifdef USE_IN_LIBIO -# include <libio/iolibio.h> -# define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l) -#endif - -/* This is the most important parameter. It should be set to two times - * the maximum number of mallocs the application uses at a time. Prime - * numbers are very good candidates for this value. I added a list of - * some prime numbers for conveniance. - * - * 10007, 20011, 30013, 40031, 50033, 60037, 70039, 80051, 90053, - * 100057, 110059, 120067, 130069, 140071, 150077, 160079, 170081, - * 180097, 190121, 200131, 210139, 220141, 230143, 240151, 250153, - * 260171, 270191, 280199, 290201, 300221, 310223, 320237, 330241, - * 340261, 350281, 360287, 370373, 380377, 390389 */ -#define TR_CACHE_SIZE 100057 - -/* The DELTA value is also a value for the maximum - * number of iterations during a positive free/realloc - * search. It must NOT divide TR_CACHE_SIZE without - * remainder! */ -#define DELTA 23 - -/* The high and low mark control the flushing algorithm. Whenever the - * hashtable reaches the high mark every DELTAth entry is written to - * disk until the low filling mark is reached. A hash table becomes - * very inefficient when it becomes filled to 50% or more. */ -#define TR_HIGH_MARK ((int) (TR_CACHE_SIZE * 0.5)) -#define TR_LOW_MARK ((int) (TR_HIGH_MARK - (TR_CACHE_SIZE / DELTA))) - -/* Maximum call stack depth. No checking for overflows - * is done. Adjust this value with care! */ -#define TR_BT_SIZE 100 - -#define PROFILE 1 - -/* The hash function. Since the smallest allocated block is probably - * not smaller than 8 bytes we ignore the last 3 LSBs. */ -#define HASHFUNC(a) (((((unsigned long) a) << 1) ^ \ - (((unsigned long) a) >> 3)) % \ - TR_CACHE_SIZE) - -#define TR_HASHTABLE_SIZE 9973 - -#define TR_NONE 0 -#define TR_MALLOC 1 -#define TR_REALLOC 2 -#define TR_FREE 3 - -#define TRACE_BUFFER_SIZE 512 - -typedef struct -{ - void* ptr; - size_t size; - int bt_size; - void** bt; -} tr_entry; - -typedef struct CallerNode -{ - void* funcAdr; - unsigned long mallocs; - unsigned long mallocsSum; - unsigned int noCallees; - unsigned int maxCallees; - struct CallerNode** callees; -} CallerNode; - -void ktrace(void); -void kuntrace(void); - -static void addAllocationToTree(void); - -static void tr_freehook __P ((void*, const void*)); -static void* tr_reallochook __P ((void*, size_t, - const void*)); -static void* tr_mallochook __P ((size_t, const void*)); -/* Old hook values. */ -static void (*tr_old_free_hook) __P ((void* ptr, const void*)); -static void* (*tr_old_malloc_hook) __P ((size_t size, - const void*)); -static void* (*tr_old_realloc_hook) __P ((void* ptr, - size_t size, - const void*)); - -static FILE* mallstream; -static char malloc_trace_buffer[TRACE_BUFFER_SIZE]; - - -/* Address to breakpoint on accesses to... */ -void* mallwatch; - -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - - -static int bt_size; -static void *bt[TR_BT_SIZE + 1]; -static char tr_offsetbuf[20]; -static tr_entry tr_cache[TR_CACHE_SIZE]; -static int tr_cache_level; -static int tr_cache_pos; -static int tr_max_offset = 0; -static void *tr_hashtable[TR_HASHTABLE_SIZE]; -#ifdef PROFILE -static unsigned long tr_mallocs = 0; -static unsigned long tr_logged_mallocs = 0; -static unsigned long tr_frees = 0; -static unsigned long tr_logged_frees = 0; -static unsigned long tr_current_mallocs = 0; -static unsigned long tr_max_mallocs = 0; -static unsigned long tr_flashes = 0; -static unsigned long tr_failed_free_lookups = 0; -static unsigned long tr_malloc_collisions = 0; -#endif - -static CallerNode* CallTree = NULL; -static char* mallTreeFile = NULL; -static FILE* mallTreeStream = NULL; -static long mallThreshold = 2000; - -extern __pid_t __fork (void); - -/* This function is called when the block being alloc'd, realloc'd, or - * freed has an address matching the variable "mallwatch". In a - * debugger, set "mallwatch" to the address of interest, then put a - * breakpoint on tr_break. */ -void tr_break __P ((void)); -void -tr_break() -{ -} - -__inline__ static void -tr_backtrace(void **_bt, int size) -{ - int i; - Dl_info info; - for (i = 0; i < size; i++) - { - long hash = (((unsigned long)_bt[i]) / 4) % TR_HASHTABLE_SIZE; - if ((tr_hashtable[hash]!= _bt[i]) && dladdr(_bt[i], &info) && - info.dli_fname && *info.dli_fname) - { - if (_bt[i] >= (void *) info.dli_saddr) - sprintf(tr_offsetbuf, "+%#lx", (unsigned long) - (_bt[i] - info.dli_saddr)); - else - sprintf(tr_offsetbuf, "-%#lx", (unsigned long) - (info.dli_saddr - _bt[i])); - fprintf(mallstream, "%s%s%s%s%s[%p]\n", - info.dli_fname ?: "", - info.dli_sname ? "(" : "", - info.dli_sname ?: "", - info.dli_sname ? tr_offsetbuf : "", - info.dli_sname ? ")" : "", - _bt[i]); - tr_hashtable[hash] = _bt[i]; - } - else - { - fprintf(mallstream, "[%p]\n", _bt[i]); - } - } -} - -__inline__ static void -tr_log(const void* caller, void* ptr, void* old, - size_t size, int op) -{ - int i, offset; - - switch (op) - { - case TR_FREE: - i = HASHFUNC(ptr); - if ((offset = (i + tr_max_offset + 1)) >= TR_CACHE_SIZE) - offset -= TR_CACHE_SIZE; - do - { - if (tr_cache[i].ptr == ptr) - { - tr_cache[i].ptr = NULL; - free(tr_cache[i].bt); - tr_cache_level--; - return; - } - if (++i >= TR_CACHE_SIZE) - i = 0; -#ifdef PROFILE - tr_failed_free_lookups++; -#endif - } while (i != offset); - - /* We don't know this allocation, so it has been flushed to disk - * already. So flush free as well. */ - fprintf(mallstream, "@\n"); - bt_size = backtrace(bt, TR_BT_SIZE); - tr_backtrace(&(bt[1]), bt_size - 2); - fprintf(mallstream, "- %p\n", ptr); -#ifdef PROFILE - tr_logged_frees++; -#endif - return; - - case TR_REALLOC: - /* If old is 0 it's actually a malloc. */ - if (old) - { - i = HASHFUNC(old); - if ((offset = (i + tr_max_offset + 1)) >= TR_CACHE_SIZE) - offset -= TR_CACHE_SIZE; - do - { - if (tr_cache[i].ptr == old) - { - int j = HASHFUNC(ptr); - /* We move the entry otherwise the free will be - * fairly expensive due to the wrong place in the - * hash table. */ - tr_cache[i].ptr = NULL; - for ( ; ; ) - { - if (tr_cache[j].ptr == NULL) - break; - - if (++j >= TR_CACHE_SIZE) - i = 0; - } - tr_cache[j].ptr = ptr; - if (ptr) - { - tr_cache[j].size = tr_cache[i].size; - tr_cache[j].bt_size = tr_cache[i].bt_size; - tr_cache[j].bt = tr_cache[i].bt; - } - else - tr_cache_level--; - tr_cache[i].size = size; - return; - } - if (++i >= TR_CACHE_SIZE) - i = 0; - } while (i != offset); - - fprintf(mallstream, "@\n"); - bt_size = backtrace(bt, TR_BT_SIZE); - tr_backtrace(&(bt[1]), bt_size - 2); - fprintf(mallstream, "< %p\n", old); - fprintf(mallstream, "> %p %#lx\n", ptr, - (unsigned long) size); - return; - } - - case TR_MALLOC: - if (tr_cache_level >= TR_HIGH_MARK) - { - /* The hash table becomes ineffective when the high mark has - * been reached. We still need some more experience with - * the low mark. It's unclear what reasonable values are. */ -#ifdef PROFILE - tr_flashes++; -#endif - i = HASHFUNC(ptr); - do - { - if (tr_cache[i].ptr) - { -#ifdef PROFILE - tr_logged_mallocs++; -#endif - fprintf(mallstream, "@\n"); - tr_backtrace(&(tr_cache[i].bt[1]), - tr_cache[i].bt_size - 2); - fprintf(mallstream, "+ %p %#lx\n", - tr_cache[i].ptr, - (unsigned long int) - tr_cache[i].size); - tr_cache[i].ptr = NULL; - tr_cache_level--; - } - if ((i += DELTA) >= TR_CACHE_SIZE) - i -= TR_CACHE_SIZE; - } while (tr_cache_level > TR_LOW_MARK); - } - - i = HASHFUNC(ptr); - for ( ; ; ) - { - if (tr_cache[i].ptr == NULL) - break; - - if (++i >= TR_CACHE_SIZE) - i = 0; -#ifdef PROFILE - tr_malloc_collisions++; -#endif - } - if ((offset = (i - HASHFUNC(ptr))) < 0) - offset += TR_CACHE_SIZE; - if (offset > tr_max_offset) - tr_max_offset = offset; - - tr_cache[i].ptr = ptr; - tr_cache[i].size = size; - tr_cache[i].bt = (void**) malloc(TR_BT_SIZE * sizeof(void*)); - tr_cache[i].bt_size = backtrace( - tr_cache[i].bt, TR_BT_SIZE); - tr_cache[i].bt = realloc(tr_cache[i].bt, tr_cache[i].bt_size * sizeof(void*)); - tr_cache_level++; - - return; - - case TR_NONE: - if (tr_cache[tr_cache_pos].ptr) - { -#ifdef PROFILE - tr_logged_mallocs++; -#endif - fprintf(mallstream, "@\n"); - tr_backtrace(&(tr_cache[tr_cache_pos].bt[1]), - tr_cache[tr_cache_pos].bt_size - 2); - fprintf(mallstream, "+ %p %#lx\n", - tr_cache[tr_cache_pos].ptr, - (unsigned long int) - tr_cache[tr_cache_pos].size); - tr_cache[tr_cache_pos].ptr = NULL; - free(tr_cache[tr_cache_pos].bt); - tr_cache_level--; - } - - if (++tr_cache_pos >= TR_CACHE_SIZE) - tr_cache_pos = 0; - break; - } -} - -static void -tr_freehook (ptr, caller) - void* ptr; - const void* caller; -{ - if (ptr == NULL) - return; - if (ptr == mallwatch) - tr_break (); - - pthread_mutex_lock(&lock); -#ifdef PROFILE - tr_frees++; - tr_current_mallocs--; -#endif - - __free_hook = tr_old_free_hook; - - if (tr_old_free_hook != NULL) - (*tr_old_free_hook) (ptr, caller); - else - free(ptr); - tr_log(caller, ptr, 0, 0, TR_FREE); - - __free_hook = tr_freehook; - pthread_mutex_unlock(&lock); -} - -static void* -tr_mallochook (size, caller) - size_t size; - const void* caller; -{ - void* hdr; - - pthread_mutex_lock(&lock); - - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; - __free_hook = tr_old_free_hook; - - if (tr_old_malloc_hook != NULL) - hdr = (void*) (*tr_old_malloc_hook) (size, caller); - else - hdr = (void*) malloc(size); - tr_log(caller, hdr, 0, size, TR_MALLOC); - /* We only build the allocation tree if mallTreeFile has been set. */ - if (mallTreeFile) - addAllocationToTree(); - - __malloc_hook = tr_mallochook; - __realloc_hook = tr_reallochook; - __free_hook = tr_freehook; - -#ifdef PROFILE - tr_mallocs++; - tr_current_mallocs++; - if (tr_current_mallocs > tr_max_mallocs) - tr_max_mallocs = tr_current_mallocs; -#endif - pthread_mutex_unlock(&lock); - - if (hdr == mallwatch) - tr_break (); - - return hdr; -} - -static void* -tr_reallochook (ptr, size, caller) - void* ptr; - size_t size; - const void* caller; -{ - void* hdr; - - if (ptr == mallwatch) - tr_break (); - - pthread_mutex_lock(&lock); - - __free_hook = tr_old_free_hook; - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; - - if (tr_old_realloc_hook != NULL) - hdr = (void*) (*tr_old_realloc_hook) (ptr, size, caller); - else - hdr = (void*) realloc (ptr, size); - - tr_log(caller, hdr, ptr, size, TR_REALLOC); - - __free_hook = tr_freehook; - __malloc_hook = tr_mallochook; - __realloc_hook = tr_reallochook; - -#ifdef PROFILE - /* If ptr is 0 there was no previos malloc of this location */ - if (ptr == NULL) - { - tr_mallocs++; - tr_current_mallocs++; - if (tr_current_mallocs > tr_max_mallocs) - tr_max_mallocs = tr_current_mallocs; - } -#endif - - pthread_mutex_unlock(&lock); - - if (hdr == mallwatch) - tr_break (); - - return hdr; -} - -void -addAllocationToTree(void) -{ - int bt_size; - int i, j; - void *bt[TR_BT_SIZE + 1]; - CallerNode* cn = CallTree; - CallerNode** parent = &CallTree; - - bt_size = backtrace(bt, TR_BT_SIZE); - for (i = bt_size - 1; i >= 4; i--) - { - if (cn == NULL) - { - *parent = cn = (CallerNode*) malloc(sizeof(CallerNode)); - cn->funcAdr = bt[i]; - cn->mallocs = 0; - cn->noCallees = 0; - cn->maxCallees = 0; - cn->callees = NULL; - } - if (i == 4) - cn->mallocs++; - else - { - int knownCallee = 0; - for (j = 0; j < cn->noCallees; j++) - if (bt[i - 1] == cn->callees[j]->funcAdr) - { - parent = &cn->callees[j]; - cn = cn->callees[j]; - knownCallee = 1; - break; - } - if (!knownCallee) - { - if (cn->noCallees == cn->maxCallees) - { - /* Copy callees into new, larger array. */ - CallerNode** tmp; - int newSize = 2 * cn->maxCallees; - if (newSize == 0) - newSize = 4; - tmp = (CallerNode**) malloc(newSize * sizeof(CallerNode*)); - memcpy(tmp, cn->callees, - cn->maxCallees * sizeof(CallerNode*)); - if (cn->callees) - free(cn->callees); - cn->callees = tmp; - memset(&cn->callees[cn->maxCallees], 0, - (newSize - cn->maxCallees) * sizeof(CallerNode*)); - cn->maxCallees = newSize; - } - parent = &cn->callees[cn->noCallees++]; - cn = 0; - } - } - } -} - -static int -removeBranchesBelowThreshold(CallerNode* root) -{ - int i; - int max; - - if (!root) - return (0); - for (i = 0; i < root->noCallees; i++) - { - if (removeBranchesBelowThreshold(root->callees[i])) - { - free(root->callees[i]); - if (root->noCallees > 1) - { - root->callees[i] = root->callees[root->noCallees - 1]; - root->callees[root->noCallees - 1] = 0; - } - else if (root->noCallees == 1) - root->callees[i] = 0; - - root->noCallees--; - i--; - } - } - if (root->noCallees == 0 && root->mallocs < mallThreshold ) - return (1); - - return (0); -} - -static void -dumpCallTree(CallerNode* root, char* indentStr, int rawMode) -{ - int i; - Dl_info info; - char* newIndentStr = 0; - size_t indDepth = 0; - - if (!root || !mallTreeStream) - return; - - if (rawMode) - { - fprintf(mallTreeStream, "-"); - } - else - { - newIndentStr = (char*) malloc(strlen(indentStr) + 2); - strcpy(newIndentStr, indentStr); - if (root->noCallees > 0) - strcat(newIndentStr, "+"); - indDepth = strlen(newIndentStr); - fprintf(mallTreeStream, "%s- ", newIndentStr); - } - - if (dladdr(root->funcAdr, &info) && info.dli_fname && *info.dli_fname) - { - if (root->funcAdr >= (void *) info.dli_saddr) - sprintf(tr_offsetbuf, "+%#lx", (unsigned long) - (root->funcAdr - info.dli_saddr)); - else - sprintf(tr_offsetbuf, "-%#lx", (unsigned long) - (info.dli_saddr - root->funcAdr)); - fprintf(mallTreeStream, "%s%s%s%s%s[%p]", - info.dli_fname ?: "", - info.dli_sname ? "(" : "", - info.dli_sname ?: "", - info.dli_sname ? tr_offsetbuf : "", - info.dli_sname ? ")" : "", - root->funcAdr); - } - else - { - fprintf(mallTreeStream, "[%p]", root->funcAdr); - } - fprintf(mallTreeStream, ": %lu\n", root->mallocs); - if (indDepth > 1 && !rawMode) - { - if (newIndentStr[indDepth - 2] == '+') - newIndentStr[indDepth - 2] = '|'; - else if (newIndentStr[indDepth - 2] == '\\') - newIndentStr[indDepth - 2] = ' '; - } - - for (i = 0; i < root->noCallees; i++) - { - if (rawMode) - dumpCallTree(root->callees[i], "", 1); - else - { - if (i == root->noCallees - 1) - newIndentStr[indDepth - 1] = '\\'; - dumpCallTree(root->callees[i], newIndentStr, rawMode); - } - } - if (rawMode) - fprintf(mallTreeStream, ".\n"); - else - free(newIndentStr); - -} - -#ifdef _LIBC -extern void __libc_freeres (void); - -/* This function gets called to make sure all memory the library - * allocates get freed and so does not irritate the user when studying - * the mtrace output. */ -static void -release_libc_mem (void) -{ - /* Only call the free function if we still are running in mtrace - * mode. */ - /*if (mallstream != NULL) - __libc_freeres ();*/ - - kuntrace(); - write(2, "kuntrace()\n", 11); -} -#endif - -/* We enable tracing if either the environment variable MALLOC_TRACE - * or the variable MALLOC_TREE are set, or if the variable mallwatch - * has been patched to an address that the debugging user wants us to - * stop on. When patching mallwatch, don't forget to set a breakpoint - * on tr_break! */ -void -ktrace() -{ -#ifdef _LIBC - static int added_atexit_handler; -#endif - char* mallfile; - - /* Don't panic if we're called more than once. */ - if (mallstream != NULL) - return; - -#ifdef _LIBC - /* When compiling the GNU libc we use the secure getenv function - * which prevents the misuse in case of SUID or SGID enabled - * programs. */ - mallfile = __secure_getenv("MALLOC_TRACE"); - mallTreeFile = __secure_getenv("MALLOC_TREE"); - if( __secure_getenv("MALLOC_THRESHOLD") != NULL ) - mallThreshold = atol(__secure_getenv("MALLOC_THRESHOLD")); -#else - mallfile = getenv("MALLOC_TRACE"); - mallTreeFile = getenv("MALLOC_TREE"); - if( getenv("MALLOC_THRESHOLD") != NULL ) - mallThreshold = atol(getenv("MALLOC_THRESHOLD")); -#endif - if (mallfile != NULL || mallTreeFile != NULL || mallwatch != NULL) - { - mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w"); - if (mallstream != NULL) - { - char buf[512]; - - /* Be sure it doesn't malloc its buffer! */ - setvbuf (mallstream, malloc_trace_buffer, _IOFBF, - TRACE_BUFFER_SIZE); - fprintf (mallstream, "= Start\n"); - memset(buf, 0, sizeof(buf)); - readlink("/proc/self/exe", buf, sizeof(buf)); - if(*buf) - fprintf (mallstream, "#%s\n", buf); - - /* Save old hooks and hook in our own functions for all - * malloc, realloc and free calls */ - tr_old_free_hook = __free_hook; - __free_hook = tr_freehook; - tr_old_malloc_hook = __malloc_hook; - __malloc_hook = tr_mallochook; - tr_old_realloc_hook = __realloc_hook; - __realloc_hook = tr_reallochook; - - tr_cache_pos = TR_CACHE_SIZE; - do - { - tr_cache[--tr_cache_pos].ptr = NULL; - } while (tr_cache_pos); - tr_cache_level = 0; - - memset(tr_hashtable, 0, sizeof(void*) * TR_HASHTABLE_SIZE); -#ifdef _LIBC - if (!added_atexit_handler) - { - added_atexit_handler = 1; - atexit (release_libc_mem); - } -#endif - } - } -} - -void -kuntrace() -{ - if (mallstream == NULL) - return; - - /* restore hooks to original values */ - __free_hook = tr_old_free_hook; - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; - - if (removeBranchesBelowThreshold(CallTree)) - CallTree = 0; - if (mallTreeFile) - { - if (mallTreeStream = fopen(mallTreeFile, "w")) - { - dumpCallTree(CallTree, "", 0); - fclose(mallTreeStream); - } - } - - /* Flush cache. */ - while (tr_cache_level) - tr_log(NULL, 0, 0, 0, TR_NONE); - - fprintf (mallstream, "= End\n"); -#ifdef PROFILE - fprintf(mallstream, "\nMax Mallocs: %8ld Cache Size: %8ld" - " Flashes: %8ld\n" - "Mallocs: %8ld Frees: %8ld Leaks: %8ld\n" - "Logged Mallocs: %8ld Logged Frees: %8ld Logged Leaks: %8ld\n" - "Avg. Free lookups: %ld Malloc collisions: %ld Max offset: %ld\n", - tr_max_mallocs, TR_CACHE_SIZE, tr_flashes, - tr_mallocs, tr_frees, tr_current_mallocs, - tr_logged_mallocs, tr_logged_frees, - tr_logged_mallocs - tr_logged_frees, - tr_frees > 0 ? ( tr_failed_free_lookups / tr_frees ) : 0, - tr_malloc_collisions, tr_max_offset); -#endif - fclose (mallstream); - mallstream = NULL; - write(2, "kuntrace()\n", 11); -} - -int fork() -{ - int result; - if (mallstream) - fflush(mallstream); - result = __fork(); - if (result == 0) - { - if (mallstream) - { - close(fileno(mallstream)); - mallstream = NULL; - __free_hook = tr_old_free_hook; - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; - } - } - return result; -} - - -static int my_mcount_lock = 0; -void mcount() -{ - Dl_info info; - int i = 1; - if (my_mcount_lock) return; - my_mcount_lock = 1; - bt_size = backtrace(bt, TR_BT_SIZE); -#if 0 -for(i = 1; (i < 5) && (i < bt_size); i++) -{ -#endif - if (dladdr(bt[i], &info) && info.dli_fname && *info.dli_fname) - { - fprintf(stdout, "%s\n", info.dli_sname ? info.dli_sname : ""); - } - else - { - fprintf(stdout, "[%p]\n", bt[i]); - } -#if 0 -} - fprintf(stdout, "\n"); -#endif - my_mcount_lock = 0; -} - diff --git a/kmtrace/ktrace.h b/kmtrace/ktrace.h deleted file mode 100644 index 366f214..0000000 --- a/kmtrace/ktrace.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _KTRACE_H -#define _KTRACE_H - -extern "C" { -/* Activate a standard collection of tracing hooks. */ -extern void ktrace (void); -extern void kuntrace (void); -} - -#endif /* ktrace.h */ diff --git a/kmtrace/match.cpp b/kmtrace/match.cpp deleted file mode 100644 index 44a5806..0000000 --- a/kmtrace/match.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Qt -#include <QStringList> -#include <QHash> -// C++ -#include <stdio.h> -#include <stdlib.h> - - -int main(int argc, char **argv) -{ - char buf[1024]; - if (argc != 3) - { - fprintf(stderr, "Usage: kmmatch <map-file> <call-file>\n"); - fprintf(stderr, "\n<map-file> is a file as output by 'nm'.\n"); - fprintf(stderr, "<call-file> is a file that contains symbols, e.g. a list of all\n" - "function calls made by a program.\n"); - fprintf(stderr, "The program will print all symbols from <call-file> that are present\n" - "in <map-file>, in the same order as they appear in <call-file>.\n"); - return 1; - } - - int i = 1; - QHash<QString,int> dict; - dict.reserve(20011); - - FILE *map_file = fopen(argv[1], "r"); - if (!map_file) - { - fprintf(stderr, "Error opening '%s'\n", argv[1]); - return 1; - } - while(!feof(map_file)) - { - fgets(buf, 1024, map_file); - QString line = QString::fromLatin1(buf).trimmed(); - const QStringList split = line.split(QLatin1Char(' '), QString::SkipEmptyParts); - if (split.count() <= 1) - return 1; - - if (split.at(1) == QLatin1String("T")) - { - dict.insert(split.value(2), i); - } - } - fclose(map_file); - - FILE *call_file = fopen(argv[2], "r"); - if (!call_file) - { - fprintf(stderr, "Error opening '%s'\n", argv[2]); - return 1; - } - - while(!feof(call_file)) - { - fgets(buf, 1024, call_file); - QString line = QString::fromLatin1(buf).trimmed(); - if (dict.contains(line)) - { - qWarning("%s", qPrintable(line)); - } - } - fclose(call_file); - return 0; -} - diff --git a/kmtrace/mtrace.c b/kmtrace/mtrace.c deleted file mode 100644 index cef7478..0000000 --- a/kmtrace/mtrace.c +++ /dev/null @@ -1,383 +0,0 @@ -/* More debugging hooks for `malloc'. - Copyright (C) 1991,92,93,94,96,97,98,99,2000 Free Software Foundation, Inc. - Written April 2, 1991 by John Gilmore of Cygnus Support. - Based on mcheck.c by Mike Haertel. - Hacked by AK - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - - The author may be reached (Email) at the address [email protected], - or (US mail) as Mike Haertel c/o Free Software Foundation. */ - -#define _LIBC -#define MALLOC_HOOKS - -#ifndef _MALLOC_INTERNAL -#define _MALLOC_INTERNAL -#include <malloc.h> -#include <mcheck.h> -#include <bits/libc-lock.h> -#endif - -#include <dlfcn.h> - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include <stdio-common/_itoa.h> -#include <elf/ldsodefs.h> - -#ifdef USE_IN_LIBIO -# include <libio/iolibio.h> -# define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l) -#endif - -#define TRACE_BUFFER_SIZE 512 - -static FILE *mallstream; -static const char mallenv[]= "MALLOC_TRACE"; -static char malloc_trace_buffer[TRACE_BUFFER_SIZE]; - -__libc_lock_define_initialized (static, lock) - -/* Address to breakpoint on accesses to... */ -__ptr_t mallwatch; - -/* File name and line number information, for callers that had - the foresight to call through a macro. */ -char *_mtrace_file; -int _mtrace_line; - -/* Old hook values. */ -static void (*tr_old_free_hook) __P ((__ptr_t ptr, const __ptr_t)); -static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size, - const __ptr_t)); -static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, - __malloc_size_t size, - const __ptr_t)); - -#define TR_PIPELINE_SIZE 16 -#define TR_BT_SIZE 80 -#define TR_HASHTABLE_SIZE 9973 - -#define TR_NONE 0 -#define TR_MALLOC 1 -#define TR_REALLOC 2 -#define TR_FREE 3 - -typedef struct { - int op; - __ptr_t ptr; - __ptr_t old; - __malloc_size_t size; - int bt_size; - void *bt[TR_BT_SIZE+1]; -} tr_entry; - -static tr_entry tr_pipeline[TR_PIPELINE_SIZE]; -static int tr_pipeline_pos; -static void *tr_hashtable[TR_HASHTABLE_SIZE]; - - -/* This function is called when the block being alloc'd, realloc'd, or - freed has an address matching the variable "mallwatch". In a debugger, - set "mallwatch" to the address of interest, then put a breakpoint on - tr_break. */ - -void tr_break __P ((void)); -void -tr_break () -{ -} - -static void -tr_backtrace(void **bt, int size) -{ - char buf[20]; - int i; - Dl_info info; - for(i = 0; i < size; i++) - { - long hash = (((unsigned long)bt[i]) / 4) % TR_HASHTABLE_SIZE; - if ((tr_hashtable[hash]!= bt[i]) && _dl_addr(bt[i], &info) && info.dli_fname && *info.dli_fname) - { - if (bt[i] >= (void *) info.dli_saddr) - sprintf(buf, "+%#lx", (unsigned long)(bt[i] - info.dli_saddr)); - else - sprintf(buf, "-%#lx", (unsigned long)(info.dli_saddr - bt[i])); - fprintf(mallstream, "%s%s%s%s%s[%p]\n", - info.dli_fname ?: "", - info.dli_sname ? "(" : "", - info.dli_sname ?: "", - info.dli_sname ? buf : "", - info.dli_sname ? ")" : "", - bt[i]); - tr_hashtable[hash] = bt[i]; - } - else { - fprintf(mallstream, "[%p]\n", bt[i]); - } - } -} - -static void -inline -tr_log(const __ptr_t caller, __ptr_t ptr, __ptr_t old, __malloc_size_t size, int op) -{ - switch(op) - { - case TR_REALLOC: - break; - case TR_MALLOC: - break; - case TR_FREE: - { - int i = tr_pipeline_pos; - do { - if (i) i--; else i = TR_PIPELINE_SIZE-1; - if (tr_pipeline[i].ptr == ptr) - { - if (tr_pipeline[i].op == TR_MALLOC) - { - tr_pipeline[i].op = TR_NONE; - tr_pipeline[i].ptr = NULL; - return; - } - break; - } - } while (i != tr_pipeline_pos); - } - } - - if (tr_pipeline[tr_pipeline_pos].op) - { - putc('@', mallstream); - putc('\n', mallstream); - /* Generate backtrace... - * We throw out the first frame (tr_mallochook) - * end the last one (_start) - */ - tr_backtrace(&(tr_pipeline[tr_pipeline_pos].bt[1]), - tr_pipeline[tr_pipeline_pos].bt_size-2); - - switch(tr_pipeline[tr_pipeline_pos].op) - { - case TR_MALLOC: - fprintf (mallstream, "+ %p %#lx\n", - tr_pipeline[tr_pipeline_pos].ptr, - (unsigned long int) tr_pipeline[tr_pipeline_pos].size); - break; - case TR_FREE: - fprintf (mallstream, "- %p\n", - tr_pipeline[tr_pipeline_pos].ptr); - break; - case TR_REALLOC: - fprintf (mallstream, "< %p\n", - tr_pipeline[tr_pipeline_pos].old); - fprintf (mallstream, "> %p %#lx\n", - tr_pipeline[tr_pipeline_pos].ptr, - (unsigned long int) tr_pipeline[tr_pipeline_pos].size); - break; - } - } - - tr_pipeline[tr_pipeline_pos].op = op; - tr_pipeline[tr_pipeline_pos].ptr = ptr; - tr_pipeline[tr_pipeline_pos].old = old; - tr_pipeline[tr_pipeline_pos].size = size; - tr_pipeline[tr_pipeline_pos].bt_size = backtrace( - tr_pipeline[tr_pipeline_pos].bt, TR_BT_SIZE); - tr_pipeline_pos++; - if (tr_pipeline_pos == TR_PIPELINE_SIZE) - tr_pipeline_pos = 0; -} - -static void tr_freehook __P ((__ptr_t, const __ptr_t)); -static void -tr_freehook (ptr, caller) - __ptr_t ptr; - const __ptr_t caller; -{ - if (ptr == NULL) - return; - __libc_lock_lock (lock); - tr_log(caller, ptr, 0, 0, TR_FREE ); - __libc_lock_unlock (lock); - if (ptr == mallwatch) - tr_break (); - __libc_lock_lock (lock); - __free_hook = tr_old_free_hook; - if (tr_old_free_hook != NULL) - (*tr_old_free_hook) (ptr, caller); - else - free (ptr); - __free_hook = tr_freehook; - __libc_lock_unlock (lock); -} - -static __ptr_t tr_mallochook __P ((__malloc_size_t, const __ptr_t)); -static __ptr_t -tr_mallochook (size, caller) - __malloc_size_t size; - const __ptr_t caller; -{ - __ptr_t hdr; - - __libc_lock_lock (lock); - - __malloc_hook = tr_old_malloc_hook; - if (tr_old_malloc_hook != NULL) - hdr = (__ptr_t) (*tr_old_malloc_hook) (size, caller); - else - hdr = (__ptr_t) malloc (size); - __malloc_hook = tr_mallochook; - - tr_log(caller, hdr, 0, size, TR_MALLOC); - - __libc_lock_unlock (lock); - - if (hdr == mallwatch) - tr_break (); - - return hdr; -} - -static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t)); -static __ptr_t -tr_reallochook (ptr, size, caller) - __ptr_t ptr; - __malloc_size_t size; - const __ptr_t caller; -{ - __ptr_t hdr; - - if (ptr == mallwatch) - tr_break (); - - __libc_lock_lock (lock); - - __free_hook = tr_old_free_hook; - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; - if (tr_old_realloc_hook != NULL) - hdr = (__ptr_t) (*tr_old_realloc_hook) (ptr, size, caller); - else - hdr = (__ptr_t) realloc (ptr, size); - __free_hook = tr_freehook; - __malloc_hook = tr_mallochook; - __realloc_hook = tr_reallochook; - - tr_log(caller, hdr, ptr, size, TR_REALLOC); - - __libc_lock_unlock (lock); - - if (hdr == mallwatch) - tr_break (); - - return hdr; -} - - -#ifdef _LIBC -extern void __libc_freeres (void); - -/* This function gets called to make sure all memory the library - allocates get freed and so does not irritate the user when studying - the mtrace output. */ -static void -release_libc_mem (void) -{ - /* Only call the free function if we still are running in mtrace mode. */ - if (mallstream != NULL) - __libc_freeres (); -} -#endif - - -/* We enable tracing if either the environment variable MALLOC_TRACE - is set, or if the variable mallwatch has been patched to an address - that the debugging user wants us to stop on. When patching mallwatch, - don't forget to set a breakpoint on tr_break! */ - -void -mtrace () -{ -#ifdef _LIBC - static int added_atexit_handler; -#endif - char *mallfile; - - /* Don't panic if we're called more than once. */ - if (mallstream != NULL) - return; - -#ifdef _LIBC - /* When compiling the GNU libc we use the secure getenv function - which prevents the misuse in case of SUID or SGID enabled - programs. */ - mallfile = __secure_getenv (mallenv); -#else - mallfile = getenv (mallenv); -#endif - if (mallfile != NULL || mallwatch != NULL) - { - mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w"); - if (mallstream != NULL) - { - /* Be sure it doesn't malloc its buffer! */ - setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE); - fprintf (mallstream, "= Start\n"); - tr_old_free_hook = __free_hook; - __free_hook = tr_freehook; - tr_old_malloc_hook = __malloc_hook; - __malloc_hook = tr_mallochook; - tr_old_realloc_hook = __realloc_hook; - __realloc_hook = tr_reallochook; - - tr_pipeline_pos = TR_PIPELINE_SIZE; - for(;tr_pipeline_pos--;) - { - tr_pipeline[tr_pipeline_pos].op = TR_NONE; - tr_pipeline[tr_pipeline_pos].ptr = NULL; - } - memset(tr_hashtable, 0, sizeof(void *)*TR_HASHTABLE_SIZE); -#ifdef _LIBC - if (!added_atexit_handler) - { - added_atexit_handler = 1; - atexit (release_libc_mem); - } -#endif - } - } -} - -void -muntrace () -{ - if (mallstream == NULL) - return; - - fprintf (mallstream, "= End\n"); - fclose (mallstream); - mallstream = NULL; - __free_hook = tr_old_free_hook; - __malloc_hook = tr_old_malloc_hook; - __realloc_hook = tr_old_realloc_hook; -} - - diff --git a/kprofilemethod/CMakeLists.txt b/kprofilemethod/CMakeLists.txt deleted file mode 100644 index 76118ae..0000000 --- a/kprofilemethod/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -project(kprofilemethod) -cmake_minimum_required(VERSION 2.8.12) - -find_package(ECM 1.7 REQUIRED NO_MODULE) -set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) -include(KDEInstallDirs) -include(KDECMakeSettings) - -install( FILES kprofilemethod.h DESTINATION ${KDE_INSTALL_INCLUDEDIR} COMPONENT Devel) diff --git a/kprofilemethod/README b/kprofilemethod/README deleted file mode 100644 index 543e841..0000000 --- a/kprofilemethod/README +++ /dev/null @@ -1,21 +0,0 @@ -As the docu in kprofilemethod.h says: - - Those macros help profiling using QTime. - They allow to sum up the time taken by a given bit of code - in a method called several times. - This way one can find out which low-level method used by a high-level - method is taking most of its time. - -WARNING: - - Please do not commit code that uses kprofilemethod.h - Since not everyone has kdesdk installed, it won't build for everyone. - This is a tool to be used for a one-time profiling, and then you need - to remove all its traces before committing. - -TODO: - - KDevelop, XEmacs and vi shortcuts to insert begin/end macros around a block - of code (e.g. after selecting it) - this macro would also insert the - int variable, and another shortcut for inserting the print macro. - diff --git a/kprofilemethod/kprofilemethod.h b/kprofilemethod/kprofilemethod.h deleted file mode 100644 index 0a62039..0000000 --- a/kprofilemethod/kprofilemethod.h +++ /dev/null @@ -1,51 +0,0 @@ -/* This file is part of the KDE project - Copyright (C) 2002 David Faure <[email protected]> - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2, as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#ifndef KPROFILEMETHOD_H -#define KPROFILEMETHOD_H - -#include <QTime> -#include <QDebug> - -/** - * Those macros help profiling using QTime. - * They allow to sum up the time taken by a given bit of code - * in a method called several times. - * This way one can find out which low-level method used by a high-level - * method is taking most of its time - * - * - * Declare the var somewhere, out of any method: - * int pr_theMethod = 0; - * (the name pr_* helps finding and removing all of this before committing) - * - * Then in the method, around the code to be timed: - * PROFILE_METHOD_BEGIN( pr_theMethod ); - * ... - * PROFILE_METHOD_END( pr_theMethod ); - * - * And finally, to see the result, put this call in a method - * called after all that (destructor, program exit...) - * PROFILE_METHOD_PRINT( pr_theMethod, "theMethod" ); - * - */ -#define PROFILE_METHOD_BEGIN(sym) extern int sym; QTime profile_dt##sym; profile_dt##sym.start(); -#define PROFILE_METHOD_END(sym) extern int sym; sym += profile_dt##sym.elapsed(); -#define PROFILE_METHOD_PRINT(sym, name) extern int sym; qDebug() << name << " took " << sym << " milliseconds" << endl; - -#endif // KPROFILEMETHOD_H diff --git a/kstartperf/CMakeLists.txt b/kstartperf/CMakeLists.txt deleted file mode 100644 index 36a35be..0000000 --- a/kstartperf/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -project(kstartperf) -cmake_minimum_required(VERSION 2.8.12) - -find_package(ECM 1.7 REQUIRED NO_MODULE) -set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) - -set(QT_MIN_VERSION "5.5.0") - -include(FeatureSummary) -include(CheckIncludeFile) -include(KDEInstallDirs) -include(KDECMakeSettings) -include(KDECompilerSettings NO_POLICY_SCOPE) -include(ECMMarkNonGuiExecutable) - -find_package(Qt5 ${QT_MIN_VERSION} REQUIRED NO_MODULE - COMPONENTS - Core -) - -find_package(KF5 REQUIRED - COMPONENTS - CoreAddons - KDELibs4Support -) - - -# By default in kde3 kstartpref was not compiled, but well, if it compiles... -check_include_file(ltdl.h HAVE_LTDL_H) -if(HAVE_LTDL_H AND NOT APPLE AND NOT WIN32) -########### next target ############### - -set(kstartperf_LIB_SRCS libkstartperf.c ) - - -add_library(kstartperf MODULE ${kstartperf_LIB_SRCS}) - -target_link_libraries(kstartperf ${CMAKE_DL_LIBS}) - -install(TARGETS kstartperf DESTINATION ${KDE_INSTALL_PLUGINDIR} ) - - -########### next target ############### - -set(kstartperf_bin_SRCS kstartperf.cpp ) - - -add_executable(kstartperf_bin ${kstartperf_bin_SRCS}) -ecm_mark_nongui_executable(kstartperf_bin) - -set_target_properties(kstartperf_bin PROPERTIES OUTPUT_NAME kstartperf) - - -target_link_libraries(kstartperf_bin KF5::CoreAddons KF5::KDELibs4Support) - -install(TARGETS kstartperf_bin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) -endif() diff --git a/kstartperf/Messages.sh b/kstartperf/Messages.sh deleted file mode 100644 index d02ceea..0000000 --- a/kstartperf/Messages.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -$XGETTEXT *.cpp -o $podir/kstartperf.pot diff --git a/kstartperf/README b/kstartperf/README deleted file mode 100644 index bfa4cce..0000000 --- a/kstartperf/README +++ /dev/null @@ -1,67 +0,0 @@ - -kstartperf: Startup time measurement tool for KDE applications - -Usage: -====== - -kstartperf measures startup time for KDE applications. -The startup time is taken as the amount of time from starting the application to the first -window created by that application appearing on screen. - -Usage is simple: - - $ kstartperf konsole - -will show you the startup time of konsole in milliseconds. - -If the KDE application you wish to profile has been build in debugging mode, -it is likely to produce a lot of additional output in addition to the -results from kstartperf. You can filter out this information by running: - -kstartperf <application> 2>&1 | grep ^kstartperf: - -The "2>&1" combines the output from the standard error and standard output -streams of your application, and then passes this merged output -through the grep tool to select only lines beginning with "kstartperf" - - -How can I get more detailed information about the startup of my application? -============================================================================ - -Various tools are available. One of the most popular is callgrind to profile -your application, with kcachegrind to analyse the results. -KCacheGrind can display a detailed breakdown of where your application -spends its CPU cycles during startup. - -More information about KCacheGrind can be found here: - -http://kcachegrind.sourceforge.net/ - -TODO: Add a link to pages on the KDE techbase ( http://techbase.kde.org ) - about optimising KDE applications. - -How does kstartperf 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(). - - - -Additional notes -================ - -The appliation that is being profiled needs to be linked against kdecore. - -Credits -======= -Geert Jansen <[email protected]>, -20 July 2000 diff --git a/kstartperf/kstartperf.cpp b/kstartperf/kstartperf.cpp deleted file mode 100644 index 677e5de..0000000 --- a/kstartperf/kstartperf.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * $Id$ - * - * This file is part of the KDE project, module kstartperf. - * Copyright (C) 2000 Geert Jansen <[email protected]> - * - * Permission to use, copy, modify, and distribute this software - * and its documentation for any purpose and without fee is hereby - * granted, provided that the above copyright notice appear in all - * copies and that both that the copyright notice and this - * permission notice and warranty disclaimer appear in supporting - * documentation, and that the name of the author not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * The author disclaim all warranties with regard to this - * software, including all implied warranties of merchantability - * and fitness. In no event shall the author be liable for any - * special, indirect or consequential damages or any damages - * whatsoever resulting from loss of use, data or profits, whether - * in an action of contract, negligence or other tortious action, - * arising out of or in connection with the use or performance of - * this software. - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <sys/time.h> - -#include <QCoreApplication> -#include <QCommandLineParser> -#include <QCommandLineOption> -#include <QFile> -#include <QString> -#include <QTextStream> - -#include <KAboutData> -#include <KLocalizedString> - -#include <kstandarddirs.h> - -QString libkstartperf() -{ - QString lib; - QString la_file = KStandardDirs::locate("module", "kstartperf.la"); - - if (la_file.isEmpty()) - { - // if no '.la' file could be found, fallback to a search for the .so file - // in the standard KDE directories - lib = KStandardDirs::locate("module","kstartperf.so"); - return lib; - } - - // Find the name of the .so file by reading the .la file - QFile la(la_file); - if (la.open(QIODevice::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.indexOf(' '); - if (pos > 0) - lib = lib.left(pos); - } - } - - la.close(); - } - - // Look up the actual .so file. - lib = KStandardDirs::locate("module", lib); - return lib; -} - - -int main(int argc, char **argv) -{ - QCoreApplication app( argc, argv ); - - KAboutData aboutData(QStringLiteral("kstartperf"), i18n("KStartPerf"), - QStringLiteral("1.0"), i18n("Measures start up time of a KDE application"), - KAboutLicense::Artistic, - i18n("Copyright (c) 2000 Geert Jansen and libkmapnotify authors")); - aboutData.addAuthor(i18n("Geert Jansen"), i18n("Maintainer"), - "[email protected]", "http://www.stack.nl/~geertj/"); - - QCommandLineParser parser; - KAboutData::setApplicationData(aboutData); - parser.addVersionOption(); - parser.addHelpOption(); - aboutData.setupCommandLine(&parser); - parser.addPositionalArgument(QLatin1String("command"), i18n("Specifies the command to run")); - parser.addOption(QCommandLineOption(QStringList() << QLatin1String("!+[args]"), i18n("Arguments to 'command'"))); - - parser.process(app); // PORTING SCRIPT: move this to after any parser.addOption - aboutData.processCommandLine(&parser); - - // Check arguments - - if (parser.positionalArguments().count() == 0) - { - fprintf(stderr, "No command specified!\n"); - fprintf(stderr, "usage: kstartperf command [arguments]\n"); - exit(1); - } - - // Build command - - char cmd[1024]; - snprintf(cmd, sizeof(cmd), "LD_PRELOAD=%s %s", - qPrintable( libkstartperf() ), qPrintable(parser.positionalArguments().at(0))); - for (int i=1; i<parser.positionalArguments().count(); i++) - { - strcat(cmd, " "); - strcat(cmd, parser.positionalArguments().at(i).toLocal8Bit()); - } - - // 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 deleted file mode 100644 index 8faa812..0000000 --- a/kstartperf/libkstartperf.c +++ /dev/null @@ -1,140 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * $Id$ - * - * libkstartperf.c: LD_PRELOAD library for startup time measurements. - * - * Copyright (C) 2000 Geert Jansen <[email protected]> - * - * Permission to use, copy, modify, and distribute this software - * and its documentation for any purpose and without fee is hereby - * granted, provided that the above copyright notice appear in all - * copies and that both that the copyright notice and this - * permission notice and warranty disclaimer appear in supporting - * documentation, and that the name of the author not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * The author disclaim all warranties with regard to this - * software, including all implied warranties of merchantability - * and fitness. In no event shall the author be liable for any - * special, indirect or consequential damages or any damages - * whatsoever resulting from loss of use, data or profits, whether - * in an action of contract, negligence or other tortious action, - * arising out of or in connection with the use or performance of - * this software. - * - * Based heavily on kmapnotify.c: - * - * (C) 2000 Rik Hemsley <[email protected]> - * (C) 2000 Simon Hausmann <[email protected]> - * (C) 2000 Bill Soudan <[email protected]> - */ - -#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 <dlfcn.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) -{ - void* handle; - - handle = dlopen("libX11.so", RTLD_LAZY); - if (handle == 0L) - handle = dlopen("libX11.so.6", RTLD_LAZY); - - if (handle == 0L) - { - fprintf(stderr, "kstartperf: Could not dlopen libX11\n"); - exit(1); - } - - KDE_RealXMapWindow = (KDE_XMapRequestSignature)dlsym(handle, "XMapWindow"); - if (KDE_RealXMapWindow == 0L) - { - fprintf(stderr, "kstartperf: Could not find symbol XMapWindow in libX11\n"); - exit(1); - } - - KDE_RealXMapRaised = (KDE_XMapRequestSignature)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); -} -
