#!/usr/bin/env python
#
# Copyright (c) 2010-2011 Corey Goldberg (corey@goldb.org)
# License: GNU LGPLv3
#
# This file is part of Multi-Mechanize
import time
from collections import defaultdict
import graph
import reportwriter
import reportwriterxml
def output_results(results_dir, results_file, run_time, rampup, ts_interval, user_group_configs=None, xml_reports=False):
results = Results(results_dir + results_file, run_time)
report = reportwriter.Report(results_dir)
print 'transactions: %i' % results.total_transactions
print 'errors: %i' % results.total_errors
print ''
print 'test start: %s' % results.start_datetime
print 'test finish: %s' % results.finish_datetime
print ''
# write the results in XML
if xml_reports:
reportwriterxml.write_jmeter_output(results.resp_stats_list, results_dir)
report.write_line('
Performance Results Report
')
report.write_line('Summary
')
report.write_line('')
report.write_line('
transactions: %d
' % results.total_transactions)
report.write_line('
errors: %d
' % results.total_errors)
report.write_line('
run time: %d secs
' % run_time)
report.write_line('
rampup: %d secs
' % rampup)
report.write_line('
test start: %s
' % results.start_datetime)
report.write_line('
test finish: %s
' % results.finish_datetime)
report.write_line('
time-series interval: %s secs
' % ts_interval)
if user_group_configs:
report.write_line('
workload configuration:')
report.write_line('
')
report.write_line('group name | threads | script name |
')
for user_group_config in user_group_configs:
report.write_line('%s | %d | %s |
' %
(user_group_config.name, user_group_config.num_threads, user_group_config.script_file))
report.write_line('
')
report.write_line('
')
report.write_line('All Transactions
')
# all transactions - response times
trans_timer_points = [] # [elapsed, timervalue]
trans_timer_vals = []
for resp_stats in results.resp_stats_list:
t = (resp_stats.elapsed_time, resp_stats.trans_time)
trans_timer_points.append(t)
trans_timer_vals.append(resp_stats.trans_time)
graph.resp_graph_raw(trans_timer_points, 'All_Transactions_response_times.png', results_dir)
report.write_line('Transaction Response Summary (secs)
')
report.write_line('')
report.write_line('count | min | avg | 80pct | 90pct | 95pct | max | stdev |
')
report.write_line('%i | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f |
' % (
results.total_transactions,
min(trans_timer_vals),
average(trans_timer_vals),
percentile(trans_timer_vals, 80),
percentile(trans_timer_vals, 90),
percentile(trans_timer_vals, 95),
max(trans_timer_vals),
standard_dev(trans_timer_vals),
))
report.write_line('
')
# all transactions - interval details
avg_resptime_points = {} # {intervalnumber: avg_resptime}
percentile_80_resptime_points = {} # {intervalnumber: 80pct_resptime}
percentile_90_resptime_points = {} # {intervalnumber: 90pct_resptime}
interval_secs = ts_interval
splat_series = split_series(trans_timer_points, interval_secs)
report.write_line('Interval Details (secs)
')
report.write_line('')
report.write_line('interval | count | rate | min | avg | 80pct | 90pct | 95pct | max | stdev |
')
for i, bucket in enumerate(splat_series):
interval_start = int((i + 1) * interval_secs)
cnt = len(bucket)
if cnt == 0:
report.write_line('%i | 0 | 0 | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
' % (i + 1))
else:
rate = cnt / float(interval_secs)
mn = min(bucket)
avg = average(bucket)
pct_80 = percentile(bucket, 80)
pct_90 = percentile(bucket, 90)
pct_95 = percentile(bucket, 95)
mx = max(bucket)
stdev = standard_dev(bucket)
report.write_line('%i | %i | %.2f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f |
' % (i + 1, cnt, rate, mn, avg, pct_80, pct_90, pct_95, mx, stdev))
avg_resptime_points[interval_start] = avg
percentile_80_resptime_points[interval_start] = pct_80
percentile_90_resptime_points[interval_start] = pct_90
report.write_line('
')
graph.resp_graph(avg_resptime_points, percentile_80_resptime_points, percentile_90_resptime_points, 'All_Transactions_response_times_intervals.png', results_dir)
report.write_line('Graphs
')
report.write_line('Response Time: %s sec time-series
' % ts_interval)
report.write_line('')
report.write_line('Response Time: raw data (all points)
')
report.write_line('')
report.write_line('Throughput: 5 sec time-series
')
report.write_line('')
# all transactions - throughput
throughput_points = {} # {intervalnumber: numberofrequests}
interval_secs = ts_interval
splat_series = split_series(trans_timer_points, interval_secs)
for i, bucket in enumerate(splat_series):
throughput_points[int((i + 1) * interval_secs)] = (len(bucket) / interval_secs)
graph.tp_graph(throughput_points, 'All_Transactions_throughput.png', results_dir)
# custom timers
for timer_name in sorted(results.uniq_timer_names):
custom_timer_vals = []
custom_timer_points = []
for resp_stats in results.resp_stats_list:
try:
val = resp_stats.custom_timers[timer_name]
custom_timer_points.append((resp_stats.elapsed_time, val))
custom_timer_vals.append(val)
except KeyError:
pass
graph.resp_graph_raw(custom_timer_points, timer_name + '_response_times.png', results_dir)
throughput_points = {} # {intervalnumber: numberofrequests}
interval_secs = ts_interval
splat_series = split_series(custom_timer_points, interval_secs)
for i, bucket in enumerate(splat_series):
throughput_points[int((i + 1) * interval_secs)] = (len(bucket) / interval_secs)
graph.tp_graph(throughput_points, timer_name + '_throughput.png', results_dir)
report.write_line('
')
report.write_line('Custom Timer: %s
' % timer_name)
report.write_line('Timer Summary (secs)
')
report.write_line('')
report.write_line('count | min | avg | 80pct | 90pct | 95pct | max | stdev |
')
report.write_line('%i | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f |
' % (
len(custom_timer_vals),
min(custom_timer_vals),
average(custom_timer_vals),
percentile(custom_timer_vals, 80),
percentile(custom_timer_vals, 90),
percentile(custom_timer_vals, 95),
max(custom_timer_vals),
standard_dev(custom_timer_vals)
))
report.write_line('
')
# custom timers - interval details
avg_resptime_points = {} # {intervalnumber: avg_resptime}
percentile_80_resptime_points = {} # {intervalnumber: 80pct_resptime}
percentile_90_resptime_points = {} # {intervalnumber: 90pct_resptime}
interval_secs = ts_interval
splat_series = split_series(custom_timer_points, interval_secs)
report.write_line('Interval Details (secs)
')
report.write_line('')
report.write_line('interval | count | rate | min | avg | 80pct | 90pct | 95pct | max | stdev |
')
for i, bucket in enumerate(splat_series):
interval_start = int((i + 1) * interval_secs)
cnt = len(bucket)
if cnt == 0:
report.write_line('%i | 0 | 0 | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
' % (i + 1))
else:
rate = cnt / float(interval_secs)
mn = min(bucket)
avg = average(bucket)
pct_80 = percentile(bucket, 80)
pct_90 = percentile(bucket, 90)
pct_95 = percentile(bucket, 95)
mx = max(bucket)
stdev = standard_dev(bucket)
report.write_line('%i | %i | %.2f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f | %.3f |
' % (i + 1, cnt, rate, mn, avg, pct_80, pct_90, pct_95, mx, stdev))
avg_resptime_points[interval_start] = avg
percentile_80_resptime_points[interval_start] = pct_80
percentile_90_resptime_points[interval_start] = pct_90
report.write_line('
')
graph.resp_graph(avg_resptime_points, percentile_80_resptime_points, percentile_90_resptime_points, timer_name + '_response_times_intervals.png', results_dir)
report.write_line('Graphs
')
report.write_line('Response Time: %s sec time-series
' % ts_interval)
report.write_line('' % timer_name)
report.write_line('Response Time: raw data (all points)
')
report.write_line('' % timer_name)
report.write_line('Throughput: %s sec time-series
' % ts_interval)
report.write_line('' % timer_name)
## user group times
#for user_group_name in sorted(results.uniq_user_group_names):
# ug_timer_vals = []
# for resp_stats in results.resp_stats_list:
# if resp_stats.user_group_name == user_group_name:
# ug_timer_vals.append(resp_stats.trans_time)
# print user_group_name
# print 'min: %.3f' % min(ug_timer_vals)
# print 'avg: %.3f' % average(ug_timer_vals)
# print '80pct: %.3f' % percentile(ug_timer_vals, 80)
# print '90pct: %.3f' % percentile(ug_timer_vals, 90)
# print '95pct: %.3f' % percentile(ug_timer_vals, 95)
# print 'max: %.3f' % max(ug_timer_vals)
# print ''
report.write_line('
')
report.write_closing_html()
class Results(object):
def __init__(self, results_file_name, run_time):
self.results_file_name = results_file_name
self.run_time = run_time
self.total_transactions = 0
self.total_errors = 0
self.uniq_timer_names = set()
self.uniq_user_group_names = set()
self.resp_stats_list = self.__parse_file()
self.epoch_start = self.resp_stats_list[0].epoch_secs
self.epoch_finish = self.resp_stats_list[-1].epoch_secs
self.start_datetime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.epoch_start))
self.finish_datetime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.epoch_finish))
def __parse_file(self):
f = open(self.results_file_name, 'rb')
resp_stats_list = []
for line in f:
fields = line.strip().split(',')
request_num = int(fields[0])
elapsed_time = float(fields[1])
epoch_secs = int(fields[2])
user_group_name = fields[3]
trans_time = float(fields[4])
error = fields[5]
self.uniq_user_group_names.add(user_group_name)
custom_timers = {}
timers_string = ''.join(fields[6:]).replace('{', '').replace('}', '')
splat = timers_string.split("'")[1:]
timers = []
vals = []
for x in splat:
if ':' in x:
x = float(x.replace(': ', ''))
vals.append(x)
else:
timers.append(x)
self.uniq_timer_names.add(x)
for timer, val in zip(timers, vals):
custom_timers[timer] = val
r = ResponseStats(request_num, elapsed_time, epoch_secs, user_group_name, trans_time, error, custom_timers)
if elapsed_time < self.run_time: # drop all times that appear after the last request was sent (incomplete interval)
resp_stats_list.append(r)
if error != '':
self.total_errors += 1
self.total_transactions += 1
return resp_stats_list
class ResponseStats(object):
def __init__(self, request_num, elapsed_time, epoch_secs, user_group_name, trans_time, error, custom_timers):
self.request_num = request_num
self.elapsed_time = elapsed_time
self.epoch_secs = epoch_secs
self.user_group_name = user_group_name
self.trans_time = trans_time
self.error = error
self.custom_timers = custom_timers
def split_series(points, interval):
offset = points[0][0]
maxval = int((points[-1][0] - offset) // interval)
vals = defaultdict(list)
for key, value in points:
vals[(key - offset) // interval].append(value)
series = [vals[i] for i in xrange(maxval + 1)]
return series
def average(seq):
avg = (float(sum(seq)) / len(seq))
return avg
def standard_dev(seq):
avg = average(seq)
sdsq = sum([(i - avg) ** 2 for i in seq])
try:
stdev = (sdsq / (len(seq) - 1)) ** .5
except ZeroDivisionError:
stdev = 0
return stdev
def percentile(seq, percentile):
i = int(len(seq) * (percentile / 100.0))
seq.sort()
return seq[i]
if __name__ == '__main__':
output_results('./', 'results.csv', 60, 30, 10)