|
4 | 4 |
|
5 | 5 | Sumer Cip 2014
|
6 | 6 | """
|
| 7 | +import itertools |
7 | 8 | import os
|
8 | 9 | import sys
|
9 | 10 | import _yappi
|
|
14 | 15 | except ImportError:
|
15 | 16 | from threading import get_ident # Python 3
|
16 | 17 |
|
| 18 | +from collections import defaultdict |
17 | 19 | from contextlib import contextmanager
|
18 | 20 |
|
19 | 21 | class YappiError(Exception): pass
|
@@ -648,26 +650,43 @@ def _save_as_CALLGRIND(self, path):
|
648 | 650 |
|
649 | 651 | lines = [header]
|
650 | 652 |
|
651 |
| - # add function definitions |
652 |
| - file_ids = [''] |
653 |
| - func_ids = [''] |
| 653 | + # Each function has a distinct number even if its name already has a |
| 654 | + # number because kcachegrind merges functions with the same number. |
| 655 | + numbers_seq = itertools.count() |
| 656 | + func_defs = lambda: defaultdict(lambda: defaultdict(lambda: next(numbers_seq))) |
| 657 | + modules_seq = enumerate(iter(func_defs, None)) |
| 658 | + modules = defaultdict(lambda: next(modules_seq)) |
| 659 | + # modules = {'file.py': [module_index, {'func': {line: func_index}}]} |
| 660 | + fl = lambda x: modules[x.module][0] |
| 661 | + fn = lambda x: modules[x.module][1][x.name][x.lineno] |
| 662 | + |
| 663 | + # enumerate modules and functions |
654 | 664 | for func_stat in self:
|
655 |
| - file_ids += [ 'fl=(%d) %s' % (func_stat.index, func_stat.module) ] |
656 |
| - func_ids += [ 'fn=(%d) %s %s:%s' % (func_stat.index, func_stat.name, func_stat.module, func_stat.lineno) ] |
| 665 | + fn(func_stat) |
| 666 | + for child in func_stat.children: |
| 667 | + fn(child) |
657 | 668 |
|
658 |
| - lines += file_ids + func_ids |
| 669 | + # add function definitions |
| 670 | + for module in sorted(modules): |
| 671 | + lines += ['', 'fl=(%d) %s' % (modules[module][0], module)] |
| 672 | + for func, defs in sorted(modules[module][1].items()): |
| 673 | + suffix = '' |
| 674 | + for line in sorted(defs): |
| 675 | + if len(defs) > 1: # disambiguate redefined functions |
| 676 | + suffix = ' +' + str(line) |
| 677 | + lines += ['fn=(%d) %s%s' % (defs[line], func, suffix)] |
659 | 678 |
|
660 | 679 | # add stats for each function we have a record of
|
661 | 680 | for func_stat in self:
|
662 | 681 | func_stats = [ '',
|
663 |
| - 'fl=(%d)' % func_stat.index, |
664 |
| - 'fn=(%d)' % func_stat.index] |
| 682 | + 'fl=(%d)' % fl(func_stat), |
| 683 | + 'fn=(%d)' % fn(func_stat)] |
665 | 684 | func_stats += [ '%s %s' % (func_stat.lineno, int(func_stat.tsub * 1e6)) ]
|
666 | 685 |
|
667 | 686 | # children functions stats
|
668 | 687 | for child in func_stat.children:
|
669 |
| - func_stats += [ 'cfl=(%d)' % child.index, |
670 |
| - 'cfn=(%d)' % child.index, |
| 688 | + func_stats += [ 'cfl=(%d)' % fl(child), |
| 689 | + 'cfn=(%d)' % fn(child), |
671 | 690 | 'calls=%d 0' % child.ncall,
|
672 | 691 | '0 %d' % int(child.ttot * 1e6)
|
673 | 692 | ]
|
|
0 commit comments