summaryrefslogtreecommitdiff
path: root/extra/kdesdk-kcachegrind/kdebug-331715.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extra/kdesdk-kcachegrind/kdebug-331715.patch')
-rw-r--r--extra/kdesdk-kcachegrind/kdebug-331715.patch827
1 files changed, 827 insertions, 0 deletions
diff --git a/extra/kdesdk-kcachegrind/kdebug-331715.patch b/extra/kdesdk-kcachegrind/kdebug-331715.patch
new file mode 100644
index 000000000..ec3ae93d5
--- /dev/null
+++ b/extra/kdesdk-kcachegrind/kdebug-331715.patch
@@ -0,0 +1,827 @@
+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)