From 4d8724d2ae72ab2ea20a9ad299dd36f33bda4658 Mon Sep 17 00:00:00 2001 From: Nicolás Reynolds Date: Sat, 19 Apr 2014 04:00:43 +0000 Subject: Sat Apr 19 03:57:19 UTC 2014 --- extra/kdesdk-kcachegrind/PKGBUILD | 14 +- extra/kdesdk-kcachegrind/kdebug-331715.patch | 827 --------------------------- 2 files changed, 4 insertions(+), 837 deletions(-) delete mode 100644 extra/kdesdk-kcachegrind/kdebug-331715.patch (limited to 'extra/kdesdk-kcachegrind') 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 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 -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 --# --# 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 --# 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 -+# -+# 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 -+# 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) -- cgit v1.2.3-54-g00ecf