summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Pipping <sping@gentoo.org>2012-03-15 20:16:55 +0000
committerSebastian Pipping <sping@gentoo.org>2012-03-15 20:16:55 +0000
commit0a7b434b157316d3e5c679c587f9f6b87423d4c6 (patch)
treeb576432c4cd1860ec3f80da79ce474b5ff94ad68
parentUpdated sidebar-dotpathsep patch for ignoring trailing path separators, bug #... (diff)
downloadgentoo-2-0a7b434b157316d3e5c679c587f9f6b87423d4c6.tar.gz
gentoo-2-0a7b434b157316d3e5c679c587f9f6b87423d4c6.tar.bz2
gentoo-2-0a7b434b157316d3e5c679c587f9f6b87423d4c6.zip
dev-util/gprof2dot: Python 3.x (bug #341687)
(Portage version: 2.1.10.49/cvs/Linux x86_64)
-rw-r--r--dev-util/gprof2dot/ChangeLog8
-rw-r--r--dev-util/gprof2dot/files/gprof2dot-0_p20100216-python3.patch489
-rw-r--r--dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild10
3 files changed, 502 insertions, 5 deletions
diff --git a/dev-util/gprof2dot/ChangeLog b/dev-util/gprof2dot/ChangeLog
index 4e8580132600..8932e3d7ae19 100644
--- a/dev-util/gprof2dot/ChangeLog
+++ b/dev-util/gprof2dot/ChangeLog
@@ -1,6 +1,10 @@
# ChangeLog for dev-util/gprof2dot
-# Copyright 1999-2010 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/dev-util/gprof2dot/ChangeLog,v 1.3 2010/10/21 00:45:46 sping Exp $
+# Copyright 1999-2012 Gentoo Foundation; Distributed under the GPL v2
+# $Header: /var/cvsroot/gentoo-x86/dev-util/gprof2dot/ChangeLog,v 1.4 2012/03/15 20:16:55 sping Exp $
+
+ 15 Mar 2012; Sebastian Pipping <sping@gentoo.org>
+ gprof2dot-0_p20100216.ebuild, +files/gprof2dot-0_p20100216-python3.patch:
+ Support Python 3.x (bug #341687)
21 Oct 2010; Sebastian Pipping <sping@gentoo.org>
gprof2dot-0_p20100216.ebuild:
diff --git a/dev-util/gprof2dot/files/gprof2dot-0_p20100216-python3.patch b/dev-util/gprof2dot/files/gprof2dot-0_p20100216-python3.patch
new file mode 100644
index 000000000000..875ccbc1ebd9
--- /dev/null
+++ b/dev-util/gprof2dot/files/gprof2dot-0_p20100216-python3.patch
@@ -0,0 +1,489 @@
+From 6087a16e81d5c41647e05291dd25bb6eac9493eb Mon Sep 17 00:00:00 2001
+From: Sebastian Pipping <sebastian@pipping.org>
+Date: Fri, 5 Nov 2010 18:10:29 +0100
+Subject: [PATCH] Support both Python 2.x and 3.x
+
+---
+ gprof2dot.py | 138 ++++++++++++++++++++++++++++++++++------------------------
+ 1 files changed, 81 insertions(+), 57 deletions(-)
+
+diff --git a/gprof2dot.py b/gprof2dot.py
+index bf0aba8..888081f 100755
+--- a/gprof2dot.py
++++ b/gprof2dot.py
+@@ -32,6 +32,27 @@ import optparse
+ import xml.parsers.expat
+
+
++# Python 2.x/3.x compatibility
++if sys.version_info[0] == 3:
++ PYTHON_3 = True
++ def compat_iteritems(x): return x.items() # No iteritems() in Python 3
++ def compat_itervalues(x): return x.values() # No itervalues() in Python 3
++ def compat_keys(x): return list(x.keys()) # keys() is a generator in Python 3
++ compat_basestring = str # No class basestring in Python 3
++
++ CALL_TIMES_FORMAT = "%u\xd7" # All strings are unicode in Python 3, no u"" marking
++else:
++ PYTHON_3 = False
++ def compat_iteritems(x): return x.iteritems()
++ def compat_itervalues(x): return x.itervalues()
++ def compat_keys(x): return x.keys()
++ compat_basestring = basestring
++
++ # u"" strings not supported in Python 3
++ # By using eval() we don't get a syntax error
++ CALL_TIMES_FORMAT = eval('u"%u\xd7"')
++
++
+ try:
+ # Debugging helper module
+ import debug
+@@ -40,7 +61,7 @@ except ImportError:
+
+
+ def times(x):
+- return u"%u\xd7" % (x,)
++ return CALL_TIMES_FORMAT % (x,)
+
+ def percentage(p):
+ return "%.02f%%" % (p*100.0,)
+@@ -236,8 +257,8 @@ class Profile(Object):
+ def validate(self):
+ """Validate the edges."""
+
+- for function in self.functions.itervalues():
+- for callee_id in function.calls.keys():
++ for function in compat_itervalues(self.functions):
++ for callee_id in compat_keys(function.calls):
+ assert function.calls[callee_id].callee_id == callee_id
+ if callee_id not in self.functions:
+ sys.stderr.write('warning: call to undefined function %s from function %s\n' % (str(callee_id), function.name))
+@@ -248,11 +269,11 @@ class Profile(Object):
+
+ # Apply the Tarjan's algorithm successively until all functions are visited
+ visited = set()
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ if function not in visited:
+ self._tarjan(function, 0, [], {}, {}, visited)
+ cycles = []
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ if function.cycle is not None and function.cycle not in cycles:
+ cycles.append(function.cycle)
+ self.cycles = cycles
+@@ -275,7 +296,7 @@ class Profile(Object):
+ order += 1
+ pos = len(stack)
+ stack.append(function)
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ callee = self.functions[call.callee_id]
+ # TODO: use a set to optimize lookup
+ if callee not in orders:
+@@ -299,10 +320,10 @@ class Profile(Object):
+ for cycle in self.cycles:
+ cycle_totals[cycle] = 0.0
+ function_totals = {}
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ function_totals[function] = 0.0
+- for function in self.functions.itervalues():
+- for call in function.calls.itervalues():
++ for function in compat_itervalues(self.functions):
++ for call in compat_itervalues(function.calls):
+ if call.callee_id != function.id:
+ callee = self.functions[call.callee_id]
+ function_totals[callee] += call[event]
+@@ -310,8 +331,8 @@ class Profile(Object):
+ cycle_totals[callee.cycle] += call[event]
+
+ # Compute the ratios
+- for function in self.functions.itervalues():
+- for call in function.calls.itervalues():
++ for function in compat_itervalues(self.functions):
++ for call in compat_itervalues(function.calls):
+ assert call.ratio is None
+ if call.callee_id != function.id:
+ callee = self.functions[call.callee_id]
+@@ -332,10 +353,10 @@ class Profile(Object):
+
+ # Sanity checking
+ assert outevent not in self
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ assert outevent not in function
+ assert inevent in function
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ assert outevent not in call
+ if call.callee_id != function.id:
+ assert call.ratio is not None
+@@ -343,13 +364,13 @@ class Profile(Object):
+ # Aggregate the input for each cycle
+ for cycle in self.cycles:
+ total = inevent.null()
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ total = inevent.aggregate(total, function[inevent])
+ self[inevent] = total
+
+ # Integrate along the edges
+ total = inevent.null()
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ total = inevent.aggregate(total, function[inevent])
+ self._integrate_function(function, outevent, inevent)
+ self[outevent] = total
+@@ -360,7 +381,7 @@ class Profile(Object):
+ else:
+ if outevent not in function:
+ total = function[inevent]
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ if call.callee_id != function.id:
+ total += self._integrate_call(call, outevent, inevent)
+ function[outevent] = total
+@@ -381,7 +402,7 @@ class Profile(Object):
+ total = inevent.null()
+ for member in cycle.functions:
+ subtotal = member[inevent]
+- for call in member.calls.itervalues():
++ for call in compat_itervalues(member.calls):
+ callee = self.functions[call.callee_id]
+ if callee.cycle is not cycle:
+ subtotal += self._integrate_call(call, outevent, inevent)
+@@ -390,9 +411,9 @@ class Profile(Object):
+
+ # Compute the time propagated to callers of this cycle
+ callees = {}
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ if function.cycle is not cycle:
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ callee = self.functions[call.callee_id]
+ if callee.cycle is cycle:
+ try:
+@@ -403,7 +424,7 @@ class Profile(Object):
+ for member in cycle.functions:
+ member[outevent] = outevent.null()
+
+- for callee, call_ratio in callees.iteritems():
++ for callee, call_ratio in compat_iteritems(callees):
+ ranks = {}
+ call_ratios = {}
+ partials = {}
+@@ -418,7 +439,7 @@ class Profile(Object):
+ def _rank_cycle_function(self, cycle, function, rank, ranks):
+ if function not in ranks or ranks[function] > rank:
+ ranks[function] = rank
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ if call.callee_id != function.id:
+ callee = self.functions[call.callee_id]
+ if callee.cycle is cycle:
+@@ -427,7 +448,7 @@ class Profile(Object):
+ def _call_ratios_cycle(self, cycle, function, ranks, call_ratios, visited):
+ if function not in visited:
+ visited.add(function)
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ if call.callee_id != function.id:
+ callee = self.functions[call.callee_id]
+ if callee.cycle is cycle:
+@@ -438,7 +459,7 @@ class Profile(Object):
+ def _integrate_cycle_function(self, cycle, function, partial_ratio, partials, ranks, call_ratios, outevent, inevent):
+ if function not in partials:
+ partial = partial_ratio*function[inevent]
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ if call.callee_id != function.id:
+ callee = self.functions[call.callee_id]
+ if callee.cycle is not cycle:
+@@ -465,7 +486,7 @@ class Profile(Object):
+ """Aggregate an event for the whole profile."""
+
+ total = event.null()
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ try:
+ total = event.aggregate(total, function[event])
+ except UndefinedEvent:
+@@ -475,11 +496,11 @@ class Profile(Object):
+ def ratio(self, outevent, inevent):
+ assert outevent not in self
+ assert inevent in self
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ assert outevent not in function
+ assert inevent in function
+ function[outevent] = ratio(function[inevent], self[inevent])
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ assert outevent not in call
+ if inevent in call:
+ call[outevent] = ratio(call[inevent], self[inevent])
+@@ -489,13 +510,13 @@ class Profile(Object):
+ """Prune the profile"""
+
+ # compute the prune ratios
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ try:
+ function.weight = function[TOTAL_TIME_RATIO]
+ except UndefinedEvent:
+ pass
+
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ callee = self.functions[call.callee_id]
+
+ if TOTAL_TIME_RATIO in call:
+@@ -509,24 +530,24 @@ class Profile(Object):
+ pass
+
+ # prune the nodes
+- for function_id in self.functions.keys():
++ for function_id in compat_keys(self.functions):
+ function = self.functions[function_id]
+ if function.weight is not None:
+ if function.weight < node_thres:
+ del self.functions[function_id]
+
+ # prune the egdes
+- for function in self.functions.itervalues():
+- for callee_id in function.calls.keys():
++ for function in compat_itervalues(self.functions):
++ for callee_id in compat_keys(function.calls):
+ call = function.calls[callee_id]
+ if callee_id not in self.functions or call.weight is not None and call.weight < edge_thres:
+ del function.calls[callee_id]
+
+ def dump(self):
+- for function in self.functions.itervalues():
++ for function in compat_itervalues(self.functions):
+ sys.stderr.write('Function %s:\n' % (function.name,))
+ self._dump_events(function.events)
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ callee = self.functions[call.callee_id]
+ sys.stderr.write(' Call %s:\n' % (callee.name,))
+ self._dump_events(call.events)
+@@ -537,7 +558,7 @@ class Profile(Object):
+ sys.stderr.write(' Function %s\n' % (function.name,))
+
+ def _dump_events(self, events):
+- for event, value in events.iteritems():
++ for event, value in compat_iteritems(events):
+ sys.stderr.write(' %s: %s\n' % (event.name, event.format(value)))
+
+
+@@ -695,7 +716,7 @@ class XmlTokenizer:
+ self.final = len(data) < size
+ try:
+ self.parser.Parse(data, self.final)
+- except xml.parsers.expat.ExpatError, e:
++ except xml.parsers.expat.ExpatError as e:
+ #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS:
+ if e.code == 3:
+ pass
+@@ -801,7 +822,7 @@ class GprofParser(Parser):
+ """Extract a structure from a match object, while translating the types in the process."""
+ attrs = {}
+ groupdict = mo.groupdict()
+- for name, value in groupdict.iteritems():
++ for name, value in compat_iteritems(groupdict):
+ if value is None:
+ value = None
+ elif self._int_re.match(value):
+@@ -977,7 +998,7 @@ class GprofParser(Parser):
+ for index in self.cycles.iterkeys():
+ cycles[index] = Cycle()
+
+- for entry in self.functions.itervalues():
++ for entry in compat_itervalues(self.functions):
+ # populate the function
+ function = Function(entry.index, entry.name)
+ function[TIME] = entry.self
+@@ -1019,7 +1040,7 @@ class GprofParser(Parser):
+
+ profile[TIME] = profile[TIME] + function[TIME]
+
+- for cycle in cycles.itervalues():
++ for cycle in compat_itervalues(cycles):
+ profile.add_cycle(cycle)
+
+ # Compute derived events
+@@ -1350,7 +1371,7 @@ class OprofileParser(LineParser):
+ self.update_subentries_dict(callees_total, callees)
+
+ def update_subentries_dict(self, totals, partials):
+- for partial in partials.itervalues():
++ for partial in compat_itervalues(partials):
+ try:
+ total = totals[partial.id]
+ except KeyError:
+@@ -1372,7 +1393,7 @@ class OprofileParser(LineParser):
+
+ # populate the profile
+ profile[SAMPLES] = 0
+- for _callers, _function, _callees in self.entries.itervalues():
++ for _callers, _function, _callees in compat_itervalues(self.entries):
+ function = Function(_function.id, _function.name)
+ function[SAMPLES] = _function.samples
+ profile.add_function(function)
+@@ -1384,10 +1405,10 @@ class OprofileParser(LineParser):
+ function.module = os.path.basename(_function.image)
+
+ total_callee_samples = 0
+- for _callee in _callees.itervalues():
++ for _callee in compat_itervalues(_callees):
+ total_callee_samples += _callee.samples
+
+- for _callee in _callees.itervalues():
++ for _callee in compat_itervalues(_callees):
+ if not _callee.self:
+ call = Call(_callee.id)
+ call[SAMPLES2] = _callee.samples
+@@ -1548,7 +1569,7 @@ class SysprofParser(XmlParser):
+ profile = Profile()
+
+ profile[SAMPLES] = 0
+- for id, object in objects.iteritems():
++ for id, object in compat_iteritems(objects):
+ # Ignore fake objects (process names, modules, "Everything", "kernel", etc.)
+ if object['self'] == 0:
+ continue
+@@ -1558,7 +1579,7 @@ class SysprofParser(XmlParser):
+ profile.add_function(function)
+ profile[SAMPLES] += function[SAMPLES]
+
+- for id, node in nodes.iteritems():
++ for id, node in compat_iteritems(nodes):
+ # Ignore fake calls
+ if node['self'] == 0:
+ continue
+@@ -1672,7 +1693,7 @@ class SharkParser(LineParser):
+
+ profile = Profile()
+ profile[SAMPLES] = 0
+- for _function, _callees in self.entries.itervalues():
++ for _function, _callees in compat_itervalues(self.entries):
+ function = Function(_function.id, _function.name)
+ function[SAMPLES] = _function.samples
+ profile.add_function(function)
+@@ -1681,7 +1702,7 @@ class SharkParser(LineParser):
+ if _function.image:
+ function.module = os.path.basename(_function.image)
+
+- for _callee in _callees.itervalues():
++ for _callee in compat_itervalues(_callees):
+ call = Call(_callee.id)
+ call[SAMPLES] = _callee.samples
+ function.add_call(call)
+@@ -1965,7 +1986,8 @@ class PstatsParser:
+ self.profile = Profile()
+ self.function_ids = {}
+
+- def get_function_name(self, (filename, line, name)):
++ def get_function_name(self, info):
++ filename, line, name = info
+ module = os.path.splitext(filename)[0]
+ module = os.path.basename(module)
+ return "%s:%d:%s" % (module, line, name)
+@@ -1986,14 +2008,14 @@ class PstatsParser:
+ def parse(self):
+ self.profile[TIME] = 0.0
+ self.profile[TOTAL_TIME] = self.stats.total_tt
+- for fn, (cc, nc, tt, ct, callers) in self.stats.stats.iteritems():
++ for fn, (cc, nc, tt, ct, callers) in compat_iteritems(self.stats.stats):
+ callee = self.get_function(fn)
+ callee.called = nc
+ callee[TOTAL_TIME] = ct
+ callee[TIME] = tt
+ self.profile[TIME] += tt
+ self.profile[TOTAL_TIME] = max(self.profile[TOTAL_TIME], ct)
+- for fn, value in callers.iteritems():
++ for fn, value in compat_iteritems(callers):
+ caller = self.get_function(fn)
+ call = Call(callee.id)
+ if isinstance(value, tuple):
+@@ -2190,7 +2212,7 @@ class DotWriter:
+ self.attr('node', fontname=fontname, shape="box", style="filled", fontcolor="white", width=0, height=0)
+ self.attr('edge', fontname=fontname)
+
+- for function in profile.functions.itervalues():
++ for function in compat_itervalues(profile.functions):
+ labels = []
+ if function.process is not None:
+ labels.append(function.process)
+@@ -2202,7 +2224,7 @@ class DotWriter:
+ label = event.format(function[event])
+ labels.append(label)
+ if function.called is not None:
+- labels.append(u"%u\xd7" % (function.called,))
++ labels.append(CALL_TIMES_FORMAT % (function.called,))
+
+ if function.weight is not None:
+ weight = function.weight
+@@ -2217,7 +2239,7 @@ class DotWriter:
+ fontsize = "%.2f" % theme.node_fontsize(weight),
+ )
+
+- for call in function.calls.itervalues():
++ for call in compat_itervalues(function.calls):
+ callee = profile.functions[call.callee_id]
+
+ labels = []
+@@ -2278,7 +2300,7 @@ class DotWriter:
+ return
+ self.write(' [')
+ first = True
+- for name, value in attrs.iteritems():
++ for name, value in compat_iteritems(attrs):
+ if first:
+ first = False
+ else:
+@@ -2291,7 +2313,7 @@ class DotWriter:
+ def id(self, id):
+ if isinstance(id, (int, float)):
+ s = str(id)
+- elif isinstance(id, basestring):
++ elif isinstance(id, compat_basestring):
+ if id.isalnum() and not id.startswith('0x'):
+ s = id
+ else:
+@@ -2300,7 +2322,8 @@ class DotWriter:
+ raise TypeError
+ self.write(s)
+
+- def color(self, (r, g, b)):
++ def color(self, rgb):
++ r, g, b = rgb
+
+ def float2int(f):
+ if f <= 0.0:
+@@ -2312,7 +2335,8 @@ class DotWriter:
+ return "#" + "".join(["%02x" % float2int(c) for c in (r, g, b)])
+
+ def escape(self, s):
+- s = s.encode('utf-8')
++ if not PYTHON_3:
++ s = s.encode('utf-8')
+ s = s.replace('\\', r'\\')
+ s = s.replace('\n', r'\n')
+ s = s.replace('\t', r'\t')
+@@ -2505,7 +2529,7 @@ class Main:
+ profile = self.profile
+ profile.prune(self.options.node_thres/100.0, self.options.edge_thres/100.0)
+
+- for function in profile.functions.itervalues():
++ for function in compat_itervalues(profile.functions):
+ function.name = self.compress_function_name(function.name)
+
+ dot.graph(profile, self.theme)
+--
+1.7.3.2
+
diff --git a/dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild b/dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild
index 91d5a9d40ca2..2f009ab8b3da 100644
--- a/dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild
+++ b/dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild
@@ -1,13 +1,13 @@
-# Copyright 1999-2010 Gentoo Foundation
+# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild,v 1.3 2010/10/21 00:45:46 sping Exp $
+# $Header: /var/cvsroot/gentoo-x86/dev-util/gprof2dot/gprof2dot-0_p20100216.ebuild,v 1.4 2012/03/15 20:16:55 sping Exp $
EAPI="3"
SUPPORT_PYTHON_ABIS="1"
PYTHON_DEPEND="*"
PYTHON_USE_WITH="xml"
-inherit python
+inherit eutils python
DESCRIPTION="Converts profiling output to dot graphs"
HOMEPAGE="http://code.google.com/p/jrfonseca/wiki/Gprof2Dot"
@@ -21,6 +21,10 @@ IUSE=""
DEPEND=""
RDEPEND=""
+src_prepare() {
+ epatch "${FILESDIR}"/${P}-python3.patch
+}
+
src_install() {
abi_specific_install() {
local code_dir="$(python_get_sitedir)"/${PN}