1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-05 18:31:12 +01:00
workload-automation/wa/workloads/apache.py
2018-07-06 14:39:41 +01:00

143 lines
5.3 KiB
Python

# Copyright 2018 ARM Limited
#
# 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.
#
from __future__ import division
import os
# pylint: disable=wrong-import-order,wrong-import-position
from future.standard_library import install_aliases
install_aliases()
from urllib.request import urlopen # pylint: disable=import-error
from wa import Workload, Parameter, Alias, WorkloadError
from wa.utils.exec_control import once
from wa.utils.misc import which, check_output
class ApacheBenchmark(Workload):
name = 'apache'
description = '''
Load-test an apache installation by issueing parallel requests with ab.
Run ab, the Apache benchmark on the host, directed at the target as the
server.
.. note:: It is assumed that Apache is already running on target.
.. note:: Current implmentation only supports a very basic use of the
benchmark.
'''
parameters = [
Parameter('port', kind=int, default=80,
description='''
Port on which Apache is running.
'''),
Parameter('path', default='/',
description='''
Path to request.
'''),
Parameter('parallel_requests', kind=int, default=350,
description='''
The number of parallel requests at a time.
'''),
Parameter('total_requests', kind=int, default=100000,
description='''
The total number of parallel requests.
'''),
]
aliases = [
Alias('ab'),
]
supported_targets = ['linux']
@once
def initialize(self, context):
ab = which('ab')
if not ab:
msg = 'ab not found on host; make sure apache2-utils (or you distro equivalent) package is installed.'
raise WorkloadError(msg)
response = urlopen('http://{}:{}{}'.format(self.target.conn.host, self.port, self.path))
code = response.getcode()
if code != 200:
msg = 'HTTP request failed with status {}; is Apache running on target?'
raise WorkloadError(msg.format(code))
def setup(self, context):
template = 'ab -k -c {} -n {} {}:{}{}'
self.command = template.format(self.parallel_requests,
self.total_requests,
self.target.conn.host,
self.port,
self.path)
self.output = None
def run(self, context):
self.logger.debug(self.command)
self.output, _ = check_output(self.command, timeout=300, shell=True)
def extract_results(self, context):
outfile = os.path.join(context.output_directory, 'ab.output')
with open(outfile, 'w') as wfh:
wfh.write(self.output)
context.add_artifact('ab-output', outfile, kind='raw')
def update_output(self, context): # pylint: disable=too-many-locals
with open(context.get_artifact_path('ab-output')) as fh:
server_software = get_line(fh, 'Server Software').split(':')[1].strip()
context.add_metadata('server-software', server_software)
doc_len_str = get_line(fh, 'Document Length').split(':')[1].strip()
doc_len = int(doc_len_str.split()[0])
context.add_metadata('document-length', doc_len)
completed = int(get_line(fh, 'Complete requests').split(':')[1].strip())
failed = int(get_line(fh, 'Failed requests').split(':')[1].strip())
fail_rate = failed / completed * 100
context.add_metric('failed_request', fail_rate, units='percent',
lower_is_better=True)
rps_str = get_line(fh, 'Requests per second').split(':')[1].strip()
rps = float(rps_str.split('[')[0])
rps_units = rps_str.split('[')[1].split(']')[0]
context.add_metric('requests_per_second', rps, units=rps_units)
tpr_str = get_line(fh, 'Time per request').split(':')[1].strip()
tpr = float(tpr_str.split('[')[0])
tpr_units = tpr_str.split('[')[1].split(']')[0]
context.add_metric('time_per_request', tpr, units=tpr_units)
trate_str = get_line(fh, 'Transfer rate').split(':')[1].strip()
trate = float(trate_str.split('[')[0])
trate_units = trate_str.split('[')[1].split(']')[0]
context.add_metric('transfer_rate', trate, units=trate_units)
pc99 = int(get_line(fh, '99%').split()[1])
context.add_metric('request_99percentile', pc99, 'ms')
pc100 = int(get_line(fh, '100%').split()[1])
context.add_metric('longest_request', pc100, 'ms')
def get_line(fh, text):
for line in fh:
if text in line:
return line