Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion _unittests/ut_pycode/test_profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
import unittest
import warnings
import time
from pstats import SortKey
try:
from pstats import SortKey
except ImportError:
# python < 3.7
from pyquickhelper.pycode.profiling import SortKey
import pandas
from pyquickhelper.pycode import ExtTestCase
from pyquickhelper.pandashelper import df2rst
Expand Down Expand Up @@ -119,6 +123,8 @@ def simple():
self.assertIn('"start_time"', res)
self.assertNotEmpty(ps)

@unittest.skipIf(sys.version_info[:2] < (3, 7),
reason="not supported")
def test_profile_graph(self):
calls = [0]

Expand Down
2 changes: 2 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ jobs:
matrix:
Python39:
python.version: '3.9'
Python36:
python.version: '3.6'
maxParallel: 3

steps:
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,8 @@ sphinx-gallery
sphinxcontrib-imagesvg
sphinx_rtd_theme
tabulate
thebe
tqdm
traitlets>=5.0
traitlets
unify
virtualenv
wheel
40 changes: 29 additions & 11 deletions src/pyquickhelper/pycode/profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,17 @@
import os
import site
import cProfile
from pstats import SortKey, Stats
from pstats import Stats

try:
from pstarts import SortKey
except ImportError: # pragma: no cover
# Python < 3.7

class SortKey:
LINE = 'line'
CUMULATIVE = 'cumulative'
TIME = 'time'


class ProfileNode:
Expand Down Expand Up @@ -53,9 +63,7 @@ def add_calls_to(self, pnode, time_elements):

@staticmethod
def _key(filename, line, fct):
key = "%s:%d" % (filename, line)
if key == "~:0":
key += ":%s" % fct
key = "%s:%d:%s" % (filename, line, fct)
return key

@property
Expand All @@ -68,11 +76,13 @@ def get_root(self):
"Returns the root of the graph."
done = set()

def _get_root(node):
def _get_root(node, stor=None):
if stor is not None:
stor.append(node)
if len(node.called_by) == 0:
return node
if len(node.called_by) == 1:
return _get_root(node.called_by[0])
return _get_root(node.called_by[0], stor=stor)
res = None
for ct in node.called_by:
k = id(node), id(ct)
Expand All @@ -81,12 +91,20 @@ def _get_root(node):
res = ct
break
if res is None:
raise RuntimeError( # pragma: no cover
"All paths have been explored and no entry point was found.")
# All paths have been explored and no entry point was found.
# Choosing the most consuming function.
return None
done.add((id(node), id(res)))
return _get_root(res)
return _get_root(res, stor=stor)

return _get_root(self)
root = _get_root(self)
if root is None:
candidates = []
_get_root(self, stor=candidates)
tall = [(n.tall, n) for n in candidates]
tall.sort()
root = tall[-1][-1]
return root

def __repr__(self):
"usual"
Expand Down Expand Up @@ -537,7 +555,7 @@ def better_name(row):
return ps, res
if as_df:
raise ValueError( # pragma: no cover
"as_df is not a compatible option with pyinst_format")
"as_df is not a compatible option with pyinst_format.")

try:
from pyinstrument import Profiler
Expand Down