/usr/share/pyshared/zope/testrunner/profiling.py is in python-zope.testrunner 4.0.3-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | ##############################################################################
#
# Copyright (c) 2004-2008 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Profiler support for the test runner
"""
import os
import glob
import sys
import tempfile
import zope.testrunner.feature
available_profilers = {}
try:
import cProfile
import pstats
except ImportError:
pass
else:
class CProfiler(object):
"""cProfiler"""
def __init__(self, filepath):
self.filepath = filepath
self.profiler = cProfile.Profile()
self.enable = self.profiler.enable
self.disable = self.profiler.disable
def finish(self):
self.profiler.dump_stats(self.filepath)
def loadStats(self, prof_glob):
stats = None
for file_name in glob.glob(prof_glob):
if stats is None:
stats = pstats.Stats(file_name)
else:
stats.add(file_name)
return stats
available_profilers['cProfile'] = CProfiler
# some Linux distributions don't include the profiler, which hotshot uses
if not sys.hexversion >= 0x02060000:
# Hotshot is not maintained any longer in 2.6. It does not support
# merging to hotshot files. Thus we won't use it in python2.6 and
# onwards
try:
import hotshot
import hotshot.stats
except ImportError:
pass
else:
class HotshotProfiler(object):
"""hotshot interface"""
def __init__(self, filepath):
self.profiler = hotshot.Profile(filepath)
self.enable = self.profiler.start
self.disable = self.profiler.stop
def finish(self):
self.profiler.close()
def loadStats(self, prof_glob):
stats = None
for file_name in glob.glob(prof_glob):
loaded = hotshot.stats.load(file_name)
if stats is None:
stats = loaded
else:
stats.add(loaded)
return stats
available_profilers['hotshot'] = HotshotProfiler
class Profiling(zope.testrunner.feature.Feature):
def __init__(self, runner):
super(Profiling, self).__init__(runner)
if (self.runner.options.profile
and sys.version_info[:3] <= (2,4,1)
and __debug__):
self.runner.options.output.error(
'Because of a bug in Python < 2.4.1, profiling '
'during tests requires the -O option be passed to '
'Python (not the test runner).')
sys.exit()
self.active = bool(self.runner.options.profile)
self.profiler = self.runner.options.profile
def global_setup(self):
self.prof_prefix = 'tests_profile.'
self.prof_suffix = '.prof'
self.prof_glob = self.prof_prefix + '*' + self.prof_suffix
# if we are going to be profiling, and this isn't a subprocess,
# clean up any stale results files
if not self.runner.options.resume_layer:
for file_name in glob.glob(self.prof_glob):
os.unlink(file_name)
# set up the output file
self.oshandle, self.file_path = tempfile.mkstemp(self.prof_suffix,
self.prof_prefix, '.')
self.profiler = available_profilers[self.runner.options.profile](self.file_path)
# Need to do this rebinding to support the stack-frame annoyance with
# hotshot.
self.late_setup = self.profiler.enable
self.early_teardown = self.profiler.disable
def global_teardown(self):
self.profiler.finish()
# We must explicitly close the handle mkstemp returned, else on
# Windows this dies the next time around just above due to an
# attempt to unlink a still-open file.
os.close(self.oshandle)
if not self.runner.options.resume_layer:
self.profiler_stats = self.profiler.loadStats(self.prof_glob)
self.profiler_stats.sort_stats('cumulative', 'calls')
def report(self):
if not self.runner.options.resume_layer:
self.runner.options.output.profiler_stats(self.profiler_stats)
|