|
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