summaryrefslogtreecommitdiff
path: root/extra/kdesdk-kcachegrind
diff options
context:
space:
mode:
Diffstat (limited to 'extra/kdesdk-kcachegrind')
-rw-r--r--extra/kdesdk-kcachegrind/PKGBUILD14
-rw-r--r--extra/kdesdk-kcachegrind/kdebug-331715.patch827
2 files changed, 4 insertions, 837 deletions
diff --git a/extra/kdesdk-kcachegrind/PKGBUILD b/extra/kdesdk-kcachegrind/PKGBUILD
index 56ccd8a31..af6d56b86 100644
--- a/extra/kdesdk-kcachegrind/PKGBUILD
+++ b/extra/kdesdk-kcachegrind/PKGBUILD
@@ -1,8 +1,8 @@
-# $Id: PKGBUILD 209594 2014-03-31 10:24:13Z svenstaro $
+# $Id: PKGBUILD 211471 2014-04-18 18:03:20Z andrea $
# Maintainer: Andrea Scarpino <andrea@archlinux.org>
pkgname=kdesdk-kcachegrind
-pkgver=4.12.4
+pkgver=4.13.0
pkgrel=1
pkgdesc='Visualization of Performance Profiling Data'
url='http://kde.org/applications/development/kcachegrind/'
@@ -13,17 +13,11 @@ depends=('kdebase-runtime' 'python2')
makedepends=('cmake' 'automoc4')
optdepends=('php: PHP support')
install=${pkgname}.install
-source=("http://download.kde.org/stable/${pkgver}/src/kcachegrind-${pkgver}.tar.xz"
- 'kdebug-331715.patch')
-sha1sums=('3d82002c20dcbc26cde2581fa8b86a0e98ffa425'
- '3e7f4a265079c509aa08aab92a7ceaf6208353b3')
+source=("http://download.kde.org/stable/${pkgver}/src/kcachegrind-${pkgver}.tar.xz")
+sha1sums=('b2f7d1855030302ecfab1e038ccd2004b5db8cc4')
prepare() {
mkdir build
-
- # KDEBUG#331715
- cd kcachegrind-${pkgver}
- patch -p1 -i "${srcdir}"/kdebug-331715.patch
}
build() {
diff --git a/extra/kdesdk-kcachegrind/kdebug-331715.patch b/extra/kdesdk-kcachegrind/kdebug-331715.patch
deleted file mode 100644
index ec3ae93d5..000000000
--- a/extra/kdesdk-kcachegrind/kdebug-331715.patch
+++ /dev/null
@@ -1,827 +0,0 @@
-commit 2858c560b2b5af8a9fa4bd9692a306b5edfe264f
-Author: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
-Date: Tue Mar 4 00:31:51 2014 +0100
-
- Fix hotshot2calltree: remove SVN keyword substitution
-
- Replaced by cmake configuration file substitution feature
- BUG: 331715
-
-diff --git a/converters/CMakeLists.txt b/converters/CMakeLists.txt
-index 10fe81f..2589d7c 100644
---- a/converters/CMakeLists.txt
-+++ b/converters/CMakeLists.txt
-@@ -1,2 +1,11 @@
--install( PROGRAMS hotshot2calltree op2calltree pprof2calltree dprof2calltree memprof2calltree
-- DESTINATION ${BIN_INSTALL_DIR} )
-+configure_file(
-+ ${CMAKE_CURRENT_SOURCE_DIR}/hotshot2calltree.cmake
-+ ${CMAKE_CURRENT_BINARY_DIR}/hotshot2calltree
-+ )
-+macro_additional_clean_files(
-+ ${CMAKE_CURRENT_BINARY_DIR}/hotshot2calltree
-+ )
-+
-+install( PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/hotshot2calltree
-+ op2calltree pprof2calltree dprof2calltree memprof2calltree
-+ DESTINATION ${BIN_INSTALL_DIR} )
-diff --git a/converters/hotshot2calltree b/converters/hotshot2calltree
-deleted file mode 100644
-index b7b9992..0000000
---- a/converters/hotshot2calltree
-+++ /dev/null
-@@ -1,394 +0,0 @@
--#!/usr/bin/env python
--# _*_ coding: latin1 _*_
--
--#
--# Copyright (c) 2003 by WEB.DE, Karlsruhe
--# Autor: Jörg Beyer <job@webde-ag.de>
--#
--# hotshot2cachegrind is free software; you can redistribute it and/or
--# modify it under the terms of the GNU General Public
--# License as published by the Free Software Foundation, version 2.
--#
--# 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
--# General Public License for more details.
--
--# You should have received a copy of the GNU 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.
--#
--#
--# This script transforms the pstat output of the hotshot
--# python profiler into the input of kcachegrind.
--#
--# example usage:
--# modify you python script to run this code:
--#
--# import hotshot
--# filename = "pythongrind.prof"
--# prof = hotshot.Profile(filename, lineevents=1)
--# prof.runcall(run) # assuming that "run" should be called.
--# prof.close()
--#
--# it will run the "run"-method under profiling and write
--# the results in a file, called "pythongrind.prof".
--#
--# then call this script:
--# hotshot2cachegrind -o <output> <input>
--# or here:
--# hotshot2cachegrind cachegrind.out.0 pythongrind.prof
--#
--# then call kcachegrind:
--# kcachegrind cachegrind.out.0
--#
--# TODO:
--# * es gibt Probleme mit rekursiven (direkt und indirekt) Aufrufen - dann
--# stimmen die Kosten nicht.
--#
--# * einige Funktionen werden mit "?" als Name angezeigt. Evtl sind
--# das nur die C/C++ extensions.
--#
--# * es fehlt noch ein Funktionsnamen Mangling, dass die Filenamen berücksichtigt,
--# zZ sind alle __init__'s und alle run's schwer unterscheidbar :-(
--#
--version = "$Revision$"
--progname = "hotshot2cachegrind"
--
--import os, sys
--from hotshot import stats,log
--import os.path
--
--file_limit=0
--
--what2text = {
-- log.WHAT_ADD_INFO : "ADD_INFO",
-- log.WHAT_DEFINE_FUNC : "DEFINE_FUNC",
-- log.WHAT_DEFINE_FILE : "DEFINE_FILE",
-- log.WHAT_LINENO : "LINENO",
-- log.WHAT_EXIT : "EXIT",
-- log.WHAT_ENTER : "ENTER"}
--
--# a pseudo caller on the caller stack. This represents
--# the Python interpreter that executes the given python
--# code.
--root_caller = ("PythonInterpreter",0,"execute")
--
--class CallStack:
-- """A tiny Stack implementation, based on python lists"""
-- def __init__(self):
-- self.stack = []
-- self.recursion_counter = {}
-- def push(self, elem):
-- """put something on the stack"""
-- self.stack.append(elem)
-- rc = self.recursion_counter.get(elem, 0)
-- self.recursion_counter[elem] = rc + 1
--
-- def pop(self):
-- """get the head element of the stack and remove it from the stack"""
-- elem = self.stack[-1:][0]
-- rc = self.recursion_counter.get(elem) - 1
-- if rc>0:
-- self.recursion_counter[elem] = rc
-- else:
-- del self.recursion_counter[elem]
-- return self.stack.pop()
--
-- def top(self):
-- """get the head element of the stack, stack is unchanged."""
-- return self.stack[-1:][0]
-- def handleLineCost(self, tdelta):
-- p, c = self.stack.pop()
-- self.stack.append( (p,c + tdelta) )
-- def size(self):
-- """ return how many elements the stack has"""
-- return len(self.stack)
--
-- def __str__(self):
-- return "[stack: %s]" % self.stack
--
-- def recursion(self, pos):
-- return self.recursion_counter.get(pos, 0)
-- #return self.recursion_dict.has_key((entry[0][0], entry[0][2]))
--
--def return_from_call(caller_stack, call_dict, cost_now):
-- """return from a function call
-- remove the function from the caller stack,
-- add the costs to the calling function.
-- """
-- called, cost_at_enter = caller_stack.pop()
-- caller, caller_cost = caller_stack.top()
--
-- #print "return_from_call: %s ruft %s" % (caller, called,)
--
-- per_file_dict = call_dict.get(called[0], {})
-- per_caller_dict = per_file_dict.get(called[2], {})
-- cost_so_far, call_counter = per_caller_dict.get(caller, (0, 0))
--
-- if caller_stack.recursion(called):
-- per_caller_dict[caller] = (cost_so_far, call_counter + 1)
-- else:
-- per_caller_dict[caller] = (cost_so_far + cost_now - cost_at_enter, call_counter + 1)
--
-- per_file_dict[called[2]] = per_caller_dict
-- call_dict[called[0]] = per_file_dict
--
--
--def updateStatus(filecount):
-- sys.stdout.write("reading File #%d \r" % filecount)
-- sys.stdout.flush()
--def convertProfFiles(output, inputfilenames):
-- """convert all the given input files into one kcachegrind
-- input file.
-- """
-- call_dict = {}
-- cost_per_pos = {}
-- cost_per_function = {}
-- caller_stack = CallStack()
-- caller_stack.push((root_caller, 0))
--
-- total_cost = 0
-- filecount = 1
-- number_of_files = len(inputfilenames)
-- for inputfilename in inputfilenames:
-- updateStatus(filecount)
-- cost, filecount = convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
-- total_cost += cost
-- if (file_limit > 0) and (filecount > file_limit):
-- break
--
-- print
-- print "total_cost: % d Ticks",total_cost
-- dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function)
--
--def convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
-- updateStatus(filecount)
-- if not ((file_limit > 0) and (filecount > file_limit)):
-- if os.path.isdir(inputfilename):
-- cost, filecount = convertProfDir(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
-- elif os.path.isfile(inputfilename):
-- cost = convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function)
-- filecount += 1
-- else:
-- sys.stderr.write("warn: ignoring '%s', is no file and no directory\n" % inputfilename)
-- cost = 0
-- return (cost, filecount)
--
--def convertProfDir(start, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
-- cost = 0
-- filenames = os.listdir(start)
-- for f in filenames:
-- if (file_limit > 0) and (filecount > file_limit):
-- break
-- full = os.path.join(start, f)
-- c, filecount = convertHandleFilename(full, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
-- cost += c;
-- return (cost, filecount)
--
--def handleCostPerPos(cost_per_pos, pos, current_cost):
-- """
-- the cost per source position are managed in a dict in a dict.
--
-- the cost are handled per file and there per function.
-- so, the per-file-dict contains some per-function-dicts
-- which sum up the cost per line (in this function and in
-- this file).
-- """
-- filename = pos[0]
-- lineno = pos[1]
-- funcname = pos[2]
-- file_dict = cost_per_pos.get(filename, {})
-- func_dict = file_dict.get(funcname, {})
-- func_dict.setdefault(lineno, 0)
-- func_dict[lineno] += current_cost
-- file_dict[funcname] = func_dict
-- cost_per_pos[filename] = file_dict
--
--def convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function):
-- """convert a single input file into one kcachegrind
-- data.
--
-- this is the most expensive function in this python source :-)
-- """
--
-- total_cost = 0
-- try:
-- logreader = log.LogReader(inputfilename)
-- current_cost = 0
-- hc = handleCostPerPos # shortcut
-- for item in logreader:
-- what, pos ,tdelta = item
-- (file, lineno, func) = pos
-- #line = "%s %s %d %s %d" % (what2text[what], file, lineno, func, tdelta)
-- #print line
-- # most common cases first
-- if what == log.WHAT_LINENO:
-- # add the current cost to the current function
-- hc(cost_per_pos, pos, tdelta)
-- total_cost += tdelta
-- elif what == log.WHAT_ENTER:
-- caller_stack.push((pos, total_cost))
-- hc(cost_per_pos, pos, tdelta)
-- total_cost += tdelta
-- elif what == log.WHAT_EXIT:
-- hc(cost_per_pos, pos, tdelta)
-- total_cost += tdelta
-- return_from_call(caller_stack, call_dict, total_cost)
-- else:
-- assert 0, "duh: %d" % what
--
--
-- # I have no idea, why sometimes the stack is not empty - we
-- # have to rewind the stack to get 100% for the root_caller
-- while caller_stack.size() > 1:
-- return_from_call(caller_stack, call_dict, total_cost)
--
-- except IOError:
-- print "could not open inputfile '%s', ignore this." % inputfilename
-- except EOFError, m:
-- print "EOF: %s" % (m,)
-- return total_cost
--
--def pretty_name(file, function):
-- #pfile = os.path.splitext(os.path.basename(file)) [0]
-- #return "%s_[%s]" % (function, file)
-- return "%s" % function
-- #return "%s::%s" % (file, function)
-- #return "%s_%s" % (pfile, function)
--
--class TagWriter:
-- def __init__(self, output):
-- self.output = output
-- self.last_values = {}
--
-- def clearTag(self, tag):
-- if self.last_values.has_key(tag):
-- del self.last_values[ tag ]
-- def clear(self):
-- self.last_values = {}
--
-- def write(self, tag, value):
-- self.output.write("%s=%s\n" % (tag, value))
-- #if (not self.last_values.has_key(tag)) or self.last_values[tag] != value:
-- # self.last_values[ tag ] = value
-- # self.output.write("%s=%s\n" % (tag, value))
--
--def dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function):
-- """write the collected results in the format kcachegrind
-- could read.
-- """
-- # the intro
-- output.write("events: Tick\n")
-- output.write("summary: %d\n" % total_cost)
-- output.write("cmd: your python script\n")
-- output.write("\n")
-- tagwriter = TagWriter(output)
--
-- # now the costs per line
-- for file in cost_per_pos.keys():
-- func_dict = cost_per_pos[file]
-- for func in func_dict.keys():
-- line_dict = func_dict[func]
-- tagwriter.write("ob", file)
-- tagwriter.write("fn", func)# pretty_name(file, func)) ; output.write("# ^--- 2\n")
-- tagwriter.write("fl", file)
-- for line in line_dict:
-- output.write("%d %d\n" %( line, line_dict[line] ))
--
-- output.write("\n\n")
-- # now the function calls. For each caller all the called
-- # functions and their costs are written.
-- for file in call_dict.keys():
-- per_file_dict = call_dict[file]
-- #print "file %s -> %s" % (file, per_file_dict)
-- for called_x in per_file_dict.keys():
-- #print "called_x:",called_x
-- per_caller_dict = per_file_dict[called_x]
-- #print "called_x %s wird gerufen von: %s" % (called_x, per_caller_dict)
-- for caller_x in per_caller_dict.keys():
-- tagwriter.write("ob", caller_x[0])
-- tagwriter.write("fn", caller_x[2])# pretty_name(caller_x[2], caller_x[0])) ; output.write("# ^--- 1\n")
-- tagwriter.write("fl", caller_x[0])
-- tagwriter.write("cob", file)
-- tagwriter.write("cfn", called_x) #pretty_name(file, called_x))
-- tagwriter.write("cfl", file)
-- cost, count = per_caller_dict[caller_x]
-- #print "called_x:",called_x
-- output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
-- tagwriter.clear()
-- #tagwriter.clearTag("cob")
-- # is it a bug in kcachegrind, that the "cob=xxx" line has
-- # to be rewritten after a calls entry with costline ?
-- #assert cost <= total_cost, "caller_x: %s, per_caller_dict: %s " % (caller_x, per_caller_dict, )
-- #output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
-- output.write("\n")
--
--def run_without_optparse():
-- """parse the options without optparse, use sys.argv"""
-- if len(sys.argv) < 4 or sys.argv[1] != "-o" :
-- print "usage: hotshot2cachegrind -o outputfile in1 [in2 [in3 [...]]]"
-- return
-- outputfilename = sys.argv[2]
-- try:
-- output = file(outputfilename, "w")
-- args = sys.argv[3:]
-- convertProfFiles(output, args)
-- output.close()
-- except IOError:
-- print "could not open '%s' for writing." % outputfilename
--
--def run_with_optparse():
-- """parse the options with optparse"""
--
-- global file_limit
--
-- versiontext = "%s version: %s" % ( progname, version.split()[1], )
-- parser = OptionParser(version=versiontext)
-- parser.add_option("-o", "--output",
-- action="store", type="string", dest="outputfilename",
-- help="write output into FILE")
-- parser.add_option("--file-limit",
-- action="store", dest="file_limit", default=0,
-- help="stop after given number of input files")
-- output = sys.stdout
-- close_output = 0
-- (options, args) = parser.parse_args()
-- file_limit = int(options.file_limit)
-- try:
-- if options.outputfilename and options.outputfilename != "-":
-- output = file(options.outputfilename, "w")
-- close_output = 1
-- except IOError:
-- print "could not open '%s' for writing." % options.outputfilename
-- if output:
-- convertProfFiles(output, args)
-- if close_output:
-- output.close()
--
--
--def profile_myself():
-- import hotshot
-- filename = "self.prof"
-- if not os.path.exists(filename):
-- prof = hotshot.Profile(filename, lineevents=1)
-- prof.runcall(run)
-- prof.close()
-- else:
-- print "not profiling myself, since '%s' exists, running normal" % filename
-- run()
--
--# check if optparse is available.
--try:
-- from optparse import OptionParser
-- run = run_with_optparse
--except ImportError:
-- run = run_without_optparse
--
--if __name__ == "__main__":
-- try:
-- run()
-- #profile_myself()
-- except KeyboardInterrupt:
-- sys.exit(1)
-diff --git a/converters/hotshot2calltree.cmake b/converters/hotshot2calltree.cmake
-new file mode 100644
-index 0000000..c2dcc17
---- /dev/null
-+++ b/converters/hotshot2calltree.cmake
-@@ -0,0 +1,394 @@
-+#!/usr/bin/env python
-+# _*_ coding: latin1 _*_
-+
-+#
-+# Copyright (c) 2003 by WEB.DE, Karlsruhe
-+# Autor: Jörg Beyer <job@webde-ag.de>
-+#
-+# hotshot2cachegrind is free software; you can redistribute it and/or
-+# modify it under the terms of the GNU General Public
-+# License as published by the Free Software Foundation, version 2.
-+#
-+# 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
-+# General Public License for more details.
-+
-+# You should have received a copy of the GNU 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.
-+#
-+#
-+# This script transforms the pstat output of the hotshot
-+# python profiler into the input of kcachegrind.
-+#
-+# example usage:
-+# modify you python script to run this code:
-+#
-+# import hotshot
-+# filename = "pythongrind.prof"
-+# prof = hotshot.Profile(filename, lineevents=1)
-+# prof.runcall(run) # assuming that "run" should be called.
-+# prof.close()
-+#
-+# it will run the "run"-method under profiling and write
-+# the results in a file, called "pythongrind.prof".
-+#
-+# then call this script:
-+# hotshot2cachegrind -o <output> <input>
-+# or here:
-+# hotshot2cachegrind cachegrind.out.0 pythongrind.prof
-+#
-+# then call kcachegrind:
-+# kcachegrind cachegrind.out.0
-+#
-+# TODO:
-+# * es gibt Probleme mit rekursiven (direkt und indirekt) Aufrufen - dann
-+# stimmen die Kosten nicht.
-+#
-+# * einige Funktionen werden mit "?" als Name angezeigt. Evtl sind
-+# das nur die C/C++ extensions.
-+#
-+# * es fehlt noch ein Funktionsnamen Mangling, dass die Filenamen berücksichtigt,
-+# zZ sind alle __init__'s und alle run's schwer unterscheidbar :-(
-+#
-+version = "Version ${KCACHEGRIND_VERSION}"
-+progname = "hotshot2cachegrind"
-+
-+import os, sys
-+from hotshot import stats,log
-+import os.path
-+
-+file_limit=0
-+
-+what2text = {
-+ log.WHAT_ADD_INFO : "ADD_INFO",
-+ log.WHAT_DEFINE_FUNC : "DEFINE_FUNC",
-+ log.WHAT_DEFINE_FILE : "DEFINE_FILE",
-+ log.WHAT_LINENO : "LINENO",
-+ log.WHAT_EXIT : "EXIT",
-+ log.WHAT_ENTER : "ENTER"}
-+
-+# a pseudo caller on the caller stack. This represents
-+# the Python interpreter that executes the given python
-+# code.
-+root_caller = ("PythonInterpreter",0,"execute")
-+
-+class CallStack:
-+ """A tiny Stack implementation, based on python lists"""
-+ def __init__(self):
-+ self.stack = []
-+ self.recursion_counter = {}
-+ def push(self, elem):
-+ """put something on the stack"""
-+ self.stack.append(elem)
-+ rc = self.recursion_counter.get(elem, 0)
-+ self.recursion_counter[elem] = rc + 1
-+
-+ def pop(self):
-+ """get the head element of the stack and remove it from the stack"""
-+ elem = self.stack[-1:][0]
-+ rc = self.recursion_counter.get(elem) - 1
-+ if rc>0:
-+ self.recursion_counter[elem] = rc
-+ else:
-+ del self.recursion_counter[elem]
-+ return self.stack.pop()
-+
-+ def top(self):
-+ """get the head element of the stack, stack is unchanged."""
-+ return self.stack[-1:][0]
-+ def handleLineCost(self, tdelta):
-+ p, c = self.stack.pop()
-+ self.stack.append( (p,c + tdelta) )
-+ def size(self):
-+ """ return how many elements the stack has"""
-+ return len(self.stack)
-+
-+ def __str__(self):
-+ return "[stack: %s]" % self.stack
-+
-+ def recursion(self, pos):
-+ return self.recursion_counter.get(pos, 0)
-+ #return self.recursion_dict.has_key((entry[0][0], entry[0][2]))
-+
-+def return_from_call(caller_stack, call_dict, cost_now):
-+ """return from a function call
-+ remove the function from the caller stack,
-+ add the costs to the calling function.
-+ """
-+ called, cost_at_enter = caller_stack.pop()
-+ caller, caller_cost = caller_stack.top()
-+
-+ #print "return_from_call: %s ruft %s" % (caller, called,)
-+
-+ per_file_dict = call_dict.get(called[0], {})
-+ per_caller_dict = per_file_dict.get(called[2], {})
-+ cost_so_far, call_counter = per_caller_dict.get(caller, (0, 0))
-+
-+ if caller_stack.recursion(called):
-+ per_caller_dict[caller] = (cost_so_far, call_counter + 1)
-+ else:
-+ per_caller_dict[caller] = (cost_so_far + cost_now - cost_at_enter, call_counter + 1)
-+
-+ per_file_dict[called[2]] = per_caller_dict
-+ call_dict[called[0]] = per_file_dict
-+
-+
-+def updateStatus(filecount):
-+ sys.stdout.write("reading File #%d \r" % filecount)
-+ sys.stdout.flush()
-+def convertProfFiles(output, inputfilenames):
-+ """convert all the given input files into one kcachegrind
-+ input file.
-+ """
-+ call_dict = {}
-+ cost_per_pos = {}
-+ cost_per_function = {}
-+ caller_stack = CallStack()
-+ caller_stack.push((root_caller, 0))
-+
-+ total_cost = 0
-+ filecount = 1
-+ number_of_files = len(inputfilenames)
-+ for inputfilename in inputfilenames:
-+ updateStatus(filecount)
-+ cost, filecount = convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
-+ total_cost += cost
-+ if (file_limit > 0) and (filecount > file_limit):
-+ break
-+
-+ print
-+ print "total_cost: % d Ticks",total_cost
-+ dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function)
-+
-+def convertHandleFilename(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
-+ updateStatus(filecount)
-+ if not ((file_limit > 0) and (filecount > file_limit)):
-+ if os.path.isdir(inputfilename):
-+ cost, filecount = convertProfDir(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
-+ elif os.path.isfile(inputfilename):
-+ cost = convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function)
-+ filecount += 1
-+ else:
-+ sys.stderr.write("warn: ignoring '%s', is no file and no directory\n" % inputfilename)
-+ cost = 0
-+ return (cost, filecount)
-+
-+def convertProfDir(start, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount):
-+ cost = 0
-+ filenames = os.listdir(start)
-+ for f in filenames:
-+ if (file_limit > 0) and (filecount > file_limit):
-+ break
-+ full = os.path.join(start, f)
-+ c, filecount = convertHandleFilename(full, caller_stack, call_dict, cost_per_pos, cost_per_function, filecount)
-+ cost += c;
-+ return (cost, filecount)
-+
-+def handleCostPerPos(cost_per_pos, pos, current_cost):
-+ """
-+ the cost per source position are managed in a dict in a dict.
-+
-+ the cost are handled per file and there per function.
-+ so, the per-file-dict contains some per-function-dicts
-+ which sum up the cost per line (in this function and in
-+ this file).
-+ """
-+ filename = pos[0]
-+ lineno = pos[1]
-+ funcname = pos[2]
-+ file_dict = cost_per_pos.get(filename, {})
-+ func_dict = file_dict.get(funcname, {})
-+ func_dict.setdefault(lineno, 0)
-+ func_dict[lineno] += current_cost
-+ file_dict[funcname] = func_dict
-+ cost_per_pos[filename] = file_dict
-+
-+def convertProfFile(inputfilename, caller_stack, call_dict, cost_per_pos, cost_per_function):
-+ """convert a single input file into one kcachegrind
-+ data.
-+
-+ this is the most expensive function in this python source :-)
-+ """
-+
-+ total_cost = 0
-+ try:
-+ logreader = log.LogReader(inputfilename)
-+ current_cost = 0
-+ hc = handleCostPerPos # shortcut
-+ for item in logreader:
-+ what, pos ,tdelta = item
-+ (file, lineno, func) = pos
-+ #line = "%s %s %d %s %d" % (what2text[what], file, lineno, func, tdelta)
-+ #print line
-+ # most common cases first
-+ if what == log.WHAT_LINENO:
-+ # add the current cost to the current function
-+ hc(cost_per_pos, pos, tdelta)
-+ total_cost += tdelta
-+ elif what == log.WHAT_ENTER:
-+ caller_stack.push((pos, total_cost))
-+ hc(cost_per_pos, pos, tdelta)
-+ total_cost += tdelta
-+ elif what == log.WHAT_EXIT:
-+ hc(cost_per_pos, pos, tdelta)
-+ total_cost += tdelta
-+ return_from_call(caller_stack, call_dict, total_cost)
-+ else:
-+ assert 0, "duh: %d" % what
-+
-+
-+ # I have no idea, why sometimes the stack is not empty - we
-+ # have to rewind the stack to get 100% for the root_caller
-+ while caller_stack.size() > 1:
-+ return_from_call(caller_stack, call_dict, total_cost)
-+
-+ except IOError:
-+ print "could not open inputfile '%s', ignore this." % inputfilename
-+ except EOFError, m:
-+ print "EOF: %s" % (m,)
-+ return total_cost
-+
-+def pretty_name(file, function):
-+ #pfile = os.path.splitext(os.path.basename(file)) [0]
-+ #return "%s_[%s]" % (function, file)
-+ return "%s" % function
-+ #return "%s::%s" % (file, function)
-+ #return "%s_%s" % (pfile, function)
-+
-+class TagWriter:
-+ def __init__(self, output):
-+ self.output = output
-+ self.last_values = {}
-+
-+ def clearTag(self, tag):
-+ if self.last_values.has_key(tag):
-+ del self.last_values[ tag ]
-+ def clear(self):
-+ self.last_values = {}
-+
-+ def write(self, tag, value):
-+ self.output.write("%s=%s\n" % (tag, value))
-+ #if (not self.last_values.has_key(tag)) or self.last_values[tag] != value:
-+ # self.last_values[ tag ] = value
-+ # self.output.write("%s=%s\n" % (tag, value))
-+
-+def dumpResults(output, call_dict, total_cost, cost_per_pos, cost_per_function):
-+ """write the collected results in the format kcachegrind
-+ could read.
-+ """
-+ # the intro
-+ output.write("events: Tick\n")
-+ output.write("summary: %d\n" % total_cost)
-+ output.write("cmd: your python script\n")
-+ output.write("\n")
-+ tagwriter = TagWriter(output)
-+
-+ # now the costs per line
-+ for file in cost_per_pos.keys():
-+ func_dict = cost_per_pos[file]
-+ for func in func_dict.keys():
-+ line_dict = func_dict[func]
-+ tagwriter.write("ob", file)
-+ tagwriter.write("fn", func)# pretty_name(file, func)) ; output.write("# ^--- 2\n")
-+ tagwriter.write("fl", file)
-+ for line in line_dict:
-+ output.write("%d %d\n" %( line, line_dict[line] ))
-+
-+ output.write("\n\n")
-+ # now the function calls. For each caller all the called
-+ # functions and their costs are written.
-+ for file in call_dict.keys():
-+ per_file_dict = call_dict[file]
-+ #print "file %s -> %s" % (file, per_file_dict)
-+ for called_x in per_file_dict.keys():
-+ #print "called_x:",called_x
-+ per_caller_dict = per_file_dict[called_x]
-+ #print "called_x %s wird gerufen von: %s" % (called_x, per_caller_dict)
-+ for caller_x in per_caller_dict.keys():
-+ tagwriter.write("ob", caller_x[0])
-+ tagwriter.write("fn", caller_x[2])# pretty_name(caller_x[2], caller_x[0])) ; output.write("# ^--- 1\n")
-+ tagwriter.write("fl", caller_x[0])
-+ tagwriter.write("cob", file)
-+ tagwriter.write("cfn", called_x) #pretty_name(file, called_x))
-+ tagwriter.write("cfl", file)
-+ cost, count = per_caller_dict[caller_x]
-+ #print "called_x:",called_x
-+ output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
-+ tagwriter.clear()
-+ #tagwriter.clearTag("cob")
-+ # is it a bug in kcachegrind, that the "cob=xxx" line has
-+ # to be rewritten after a calls entry with costline ?
-+ #assert cost <= total_cost, "caller_x: %s, per_caller_dict: %s " % (caller_x, per_caller_dict, )
-+ #output.write("calls=%d\n%d %d\n" % (count, caller_x[1], cost))
-+ output.write("\n")
-+
-+def run_without_optparse():
-+ """parse the options without optparse, use sys.argv"""
-+ if len(sys.argv) < 4 or sys.argv[1] != "-o" :
-+ print "usage: hotshot2cachegrind -o outputfile in1 [in2 [in3 [...]]]"
-+ return
-+ outputfilename = sys.argv[2]
-+ try:
-+ output = file(outputfilename, "w")
-+ args = sys.argv[3:]
-+ convertProfFiles(output, args)
-+ output.close()
-+ except IOError:
-+ print "could not open '%s' for writing." % outputfilename
-+
-+def run_with_optparse():
-+ """parse the options with optparse"""
-+
-+ global file_limit
-+
-+ versiontext = "%s version: %s" % ( progname, version.split()[1], )
-+ parser = OptionParser(version=versiontext)
-+ parser.add_option("-o", "--output",
-+ action="store", type="string", dest="outputfilename",
-+ help="write output into FILE")
-+ parser.add_option("--file-limit",
-+ action="store", dest="file_limit", default=0,
-+ help="stop after given number of input files")
-+ output = sys.stdout
-+ close_output = 0
-+ (options, args) = parser.parse_args()
-+ file_limit = int(options.file_limit)
-+ try:
-+ if options.outputfilename and options.outputfilename != "-":
-+ output = file(options.outputfilename, "w")
-+ close_output = 1
-+ except IOError:
-+ print "could not open '%s' for writing." % options.outputfilename
-+ if output:
-+ convertProfFiles(output, args)
-+ if close_output:
-+ output.close()
-+
-+
-+def profile_myself():
-+ import hotshot
-+ filename = "self.prof"
-+ if not os.path.exists(filename):
-+ prof = hotshot.Profile(filename, lineevents=1)
-+ prof.runcall(run)
-+ prof.close()
-+ else:
-+ print "not profiling myself, since '%s' exists, running normal" % filename
-+ run()
-+
-+# check if optparse is available.
-+try:
-+ from optparse import OptionParser
-+ run = run_with_optparse
-+except ImportError:
-+ run = run_without_optparse
-+
-+if __name__ == "__main__":
-+ try:
-+ run()
-+ #profile_myself()
-+ except KeyboardInterrupt:
-+ sys.exit(1)