6
6
import os
7
7
import cProfile
8
8
import pstats
9
- import pipes
10
9
import errno
11
10
from hashlib import md5
11
+ from subprocess import Popen , PIPE
12
12
13
13
import six
14
14
import pytest
@@ -28,6 +28,9 @@ class Profiling(object):
28
28
svg_name = None
29
29
profs = []
30
30
combined = None
31
+ svg_err = None
32
+ dot_cmd = None
33
+ gprof2dot_cmd = None
31
34
32
35
def __init__ (self , svg , dir = None , element_number = 20 ):
33
36
self .svg = svg
@@ -54,17 +57,51 @@ def pytest_sessionfinish(self, session, exitstatus): # @UnusedVariable
54
57
combined .dump_stats (self .combined )
55
58
if self .svg :
56
59
self .svg_name = os .path .abspath (os .path .join (self .dir , "combined.svg" ))
57
- t = pipes .Template ()
58
- t .append ("{} -f pstats $IN" .format (self .gprof2dot ), "f-" )
59
- t .append ("dot -Tsvg -o $OUT" , "-f" )
60
- t .copy (self .combined , self .svg_name )
60
+
61
+ # convert file <self.combined> into file <self.svg_name> using a pipe of gprof2dot | dot
62
+ # gprof2dot -f pstats prof/combined.prof | dot -Tsvg -o prof/combined.svg
63
+
64
+ # the 2 commands that we wish to execute
65
+ gprof2dot_args = [self .gprof2dot , "-f" , "pstats" , self .combined ]
66
+ dot_args = ["dot" , "-Tsvg" , "-o" , self .svg_name ]
67
+ self .dot_cmd = " " .join (dot_args )
68
+ self .gprof2dot_cmd = " " .join (gprof2dot_args )
69
+
70
+ # A handcrafted Popen pipe actually seems to work on both windows and unix:
71
+ # do it in 2 subprocesses, with a pipe in between
72
+ pdot = Popen (dot_args , stdin = PIPE , shell = True )
73
+ pgprof = Popen (gprof2dot_args , stdout = pdot .stdin , shell = True )
74
+ (stdoutdata1 , stderrdata1 ) = pgprof .communicate ()
75
+ (stdoutdata2 , stderrdata2 ) = pdot .communicate ()
76
+ if stderrdata1 is not None or pgprof .poll () > 0 :
77
+ # error: gprof2dot
78
+ self .svg_err = 1
79
+ elif stderrdata2 is not None or pdot .poll () > 0 :
80
+ # error: dot
81
+ self .svg_err = 2
82
+ else :
83
+ # success
84
+ self .svg_err = 0
61
85
62
86
def pytest_terminal_summary (self , terminalreporter ):
63
87
if self .combined :
64
88
terminalreporter .write ("Profiling (from {prof}):\n " .format (prof = self .combined ))
65
89
pstats .Stats (self .combined , stream = terminalreporter ).strip_dirs ().sort_stats ('cumulative' ).print_stats (self .element_number )
66
90
if self .svg_name :
67
- terminalreporter .write ("SVG profile in {svg}.\n " .format (svg = self .svg_name ))
91
+ if not self .svg_err :
92
+ # 0 - SUCCESS
93
+ terminalreporter .write ("SVG profile created in {svg}.\n " .format (svg = self .svg_name ))
94
+ else :
95
+ if self .svg_err == 1 :
96
+ # 1 - GPROF2DOT ERROR
97
+ terminalreporter .write ("Error creating SVG profile in {svg}.\n "
98
+ "Command failed: {cmd}" .format (svg = self .svg_name , cmd = self .gprof2dot_cmd ))
99
+ elif self .svg_err == 2 :
100
+ # 2 - DOT ERROR
101
+ terminalreporter .write ("Error creating SVG profile in {svg}.\n "
102
+ "Command succeeded: {cmd} \n "
103
+ "Command failed: {cmd2}" .format (svg = self .svg_name , cmd = self .gprof2dot_cmd ,
104
+ cmd2 = self .dot_cmd ))
68
105
69
106
@pytest .hookimpl (hookwrapper = True )
70
107
def pytest_runtest_protocol (self , item , nextitem ):
0 commit comments