yandex-tank/yandextank/plugins/ApacheBenchmark.py
2015-02-03 12:35:48 +03:00

169 lines
5.6 KiB
Python

''' AB load generator '''
from Aggregator import AggregatorPlugin, AbstractReader
from ConsoleOnline import ConsoleOnlinePlugin, AbstractInfoWidget
import os
import subprocess
from yandextank.core import AbstractPlugin
import yandextank.core as tankcore
class ApacheBenchmarkPlugin(AbstractPlugin):
''' Apache Benchmark plugin '''
SECTION = 'ab'
def __init__(self, core):
AbstractPlugin.__init__(self, core)
self.out_file = None
self.process = None
self.concurrency = 0
self.options = None
self.url = None
self.requests = None
@staticmethod
def get_key():
return __file__
def get_available_options(self):
return ["options", "url", "requests", "concurrency"]
def configure(self):
self.options = self.get_option("options", '')
self.url = self.get_option("url", 'http://localhost/')
self.requests = self.get_option("requests", '100')
self.concurrency = self.get_option("concurrency", '1')
self.out_file = self.core.mkstemp('.log', 'ab_')
self.core.add_artifact_file(self.out_file)
def prepare_test(self):
aggregator = None
try:
aggregator = self.core.get_plugin_of_type(AggregatorPlugin)
except Exception, ex:
self.log.warning("No aggregator found: %s", ex)
if aggregator:
aggregator.reader = ABReader(aggregator, self)
try:
console = self.core.get_plugin_of_type(ConsoleOnlinePlugin)
except Exception, ex:
self.log.debug("Console not found: %s", ex)
console = None
if console:
widget = ABInfoWidget(self)
console.add_info_widget(widget)
def start_test(self):
args = ['ab', '-r', '-g', self.out_file,
'-n', self.requests,
'-c', self.concurrency, self.url]
self.log.info("Starting ab with arguments: %s", args)
self.process = subprocess.Popen(args, stderr=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True)
def is_test_finished(self):
retcode = self.process.poll()
if retcode != None:
self.log.debug("%s exit code: %s", self.SECTION, retcode)
return retcode
else:
return -1
def end_test(self, retcode):
if self.process and self.process.poll() is None:
self.log.warn("Terminating ab process with PID %s", self.process.pid)
self.process.terminate()
else:
self.log.info("Seems ab finished OK")
if self.process:
tankcore.log_stdout_stderr(self.log, self.process.stdout, self.process.stderr, self.SECTION)
return retcode
class ABReader(AbstractReader):
'''
Adapter to read AB files
'''
def __init__(self, aggregator, abench):
AbstractReader.__init__(self, aggregator)
self.abench = abench
self.results = None
def check_open_files(self):
if not self.results and os.path.exists(self.abench.out_file):
self.log.debug("Opening ab out file: %s", self.abench.out_file)
self.results = open(self.abench.out_file, 'r')
def close_files(self):
if self.results:
self.results.close()
def get_next_sample(self, force):
if self.results:
read_lines = self.results.readlines()
if read_lines:
read_lines.pop(0) # remove header line
self.log.debug("About to process %s result lines", len(read_lines))
for line in read_lines:
line = line.strip()
if not line:
return None
# Tue Sep 25 14:19:36 2012 1348568376 0 36 36 34
data = line.split("\t")
if len(data) != 6:
self.log.warning("Wrong ab log line, skipped: %s", line)
continue
cur_time = int(data[1])
ctime = int(data[2])
# dtime = int(data[3])
ttime = int(data[4])
wait = int(data[5])
if not cur_time in self.data_buffer.keys():
self.data_queue.append(cur_time)
self.data_buffer[cur_time] = []
# marker, threads, overallRT, httpCode, netCode
data_item = ['', self.abench.concurrency, ttime, 0, 0]
# bytes: sent received
data_item += [0, 0]
# connect send latency receive
data_item += [ctime, 0, wait, ttime - ctime - wait]
# accuracy
data_item += [0]
self.data_buffer[cur_time].append(data_item)
if self.data_queue:
return self.pop_second()
else:
return None
class ABInfoWidget(AbstractInfoWidget):
''' Console widget '''
def __init__(self, abench):
AbstractInfoWidget.__init__(self)
self.abench = abench
self.active_threads = 0
def get_index(self):
return 0
def render(self, screen):
ab_text = " Apache Benchmark Test "
space = screen.right_panel_width - len(ab_text) - 1
left_spaces = space / 2
right_spaces = space / 2
template = screen.markup.BG_BROWN + '~' * left_spaces + ab_text + ' ' + '~' * right_spaces + screen.markup.RESET + "\n"
template += " URL: %s\n"
template += " Concurrency: %s\n"
template += "Total Requests: %s"
data = (self.abench.url, self.abench.concurrency, self.abench.requests)
return template % data