100 lines
3.4 KiB
Python
100 lines
3.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2014 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import cProfile
|
|
import os
|
|
from pstats import Stats
|
|
import time
|
|
|
|
from fuelclient.cli import error
|
|
from fuelclient import fuelclient_settings
|
|
|
|
|
|
def profiling_enabled():
|
|
settings = fuelclient_settings.get_settings()
|
|
return bool(settings.PERFORMANCE_PROFILING_TESTS)
|
|
|
|
|
|
class Profiler(object):
|
|
"""Runs profiler and saves results."""
|
|
|
|
def __init__(self, method='', handler_name=''):
|
|
self.method = method
|
|
self.handler_name = handler_name
|
|
settings = fuelclient_settings.get_settings()
|
|
self.paths = settings.PERF_TESTS_PATHS
|
|
|
|
if not os.path.exists(self.paths['last_performance_test']):
|
|
os.makedirs(self.paths['last_performance_test'])
|
|
|
|
self.profiler = cProfile.Profile()
|
|
self.profiler.enable()
|
|
self.start = time.time()
|
|
|
|
def save_data(self):
|
|
try:
|
|
import gprof2dot
|
|
import pyprof2calltree
|
|
except ImportError:
|
|
msg = ('Unable to start profiling.\n Please either '
|
|
'disable performance profiling in settings.yaml or '
|
|
'install all modules listed in test-requirements.txt.')
|
|
raise error.ProfilingError(msg)
|
|
|
|
self.profiler.disable()
|
|
elapsed = time.time() - self.start
|
|
pref_filename = os.path.join(
|
|
self.paths['last_performance_test'],
|
|
'{method:s}.{handler_name:s}.{elapsed_time:.0f}ms.{t_time}.'.
|
|
format(
|
|
method=self.method,
|
|
handler_name=self.handler_name or 'root',
|
|
elapsed_time=elapsed * 1000.0,
|
|
t_time=time.time()))
|
|
tree_file = pref_filename + 'prof'
|
|
stats_file = pref_filename + 'txt'
|
|
callgraph_file = pref_filename + 'dot'
|
|
|
|
# write pstats
|
|
with file(stats_file, 'w') as file_o:
|
|
stats = Stats(self.profiler, stream=file_o)
|
|
stats.sort_stats('time', 'cumulative').print_stats()
|
|
|
|
# write callgraph in dot format
|
|
parser = gprof2dot.PstatsParser(self.profiler)
|
|
|
|
def get_function_name(args):
|
|
filename, line, name = args
|
|
module = os.path.splitext(filename)[0]
|
|
module_pieces = module.split(os.path.sep)
|
|
return "{module:s}:{line:d}:{name:s}".format(
|
|
module="/".join(module_pieces[-4:]),
|
|
line=line,
|
|
name=name)
|
|
|
|
parser.get_function_name = get_function_name
|
|
gprof = parser.parse()
|
|
|
|
with open(callgraph_file, 'w') as file_o:
|
|
dot = gprof2dot.DotWriter(file_o)
|
|
theme = gprof2dot.TEMPERATURE_COLORMAP
|
|
dot.graph(gprof, theme)
|
|
|
|
# write calltree
|
|
call_tree = pyprof2calltree.CalltreeConverter(stats)
|
|
with file(tree_file, 'wb') as file_o:
|
|
call_tree.output(file_o)
|