perfkitbenchmarker/linux_benchmarks/cloudsuite_web_serving_benchmark.py (119 lines of code) (raw):
# Copyright 2015 PerfKitBenchmarker Authors. All rights reserved.
#
# 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.
"""Runs the web serving benchmark of Cloudsuite.
More info: http://cloudsuite.ch/webserving/
"""
import re
from absl import flags
from perfkitbenchmarker import background_tasks
from perfkitbenchmarker import configs
from perfkitbenchmarker import sample
from perfkitbenchmarker.linux_packages import docker
flags.DEFINE_integer(
'cloudsuite_web_serving_pm_max_children',
150,
'The maximum number php-fpm pm children.',
lower_bound=8,
)
flags.DEFINE_integer(
'cloudsuite_web_serving_load_scale',
100,
'The maximum number of concurrent users that can be simulated.',
lower_bound=2,
)
FLAGS = flags.FLAGS
BENCHMARK_NAME = 'cloudsuite_web_serving'
BENCHMARK_CONFIG = """
cloudsuite_web_serving:
description: >
Run Cloudsuite web serving benchmark.
vm_groups:
backend:
vm_spec: *default_dual_core
vm_count: 1
frontend:
vm_spec: *default_dual_core
vm_count: 1
client:
vm_spec: *default_dual_core
vm_count: 1
"""
def GetConfig(user_config):
return configs.LoadConfig(BENCHMARK_CONFIG, user_config, BENCHMARK_NAME)
def CheckPrerequisites(benchmark_config):
"""Verifies that the required resources are present.
Raises:
perfkitbenchmarker.data.ResourceNotFound: On missing resource.
"""
if FLAGS['num_vms'].present and FLAGS.num_vms < 3:
raise ValueError('Web Serving requires at least 3 VMs')
def Prepare(benchmark_spec):
"""Install docker. Pull images. Start nginx, mysql, and memcached.
Args:
benchmark_spec: The benchmark specification. Contains all data that is
required to run the benchmark.
"""
frontend = benchmark_spec.vm_groups['frontend'][0]
backend = benchmark_spec.vm_groups['backend'][0]
client = benchmark_spec.vm_groups['client'][0]
def PrepareCommon(vm):
if not docker.IsInstalled(vm):
vm.Install('docker')
vm.RemoteCommand(
"sudo sh -c 'echo %s web_server >>/etc/hosts'" % frontend.internal_ip
)
vm.RemoteCommand(
"sudo sh -c 'echo %s memcache_server >>/etc/hosts'"
% frontend.internal_ip
)
vm.RemoteCommand(
"sudo sh -c 'echo %s mysql_server >>/etc/hosts'" % backend.internal_ip
)
vm.RemoteCommand(
"sudo sh -c 'echo %s faban_client >>/etc/hosts'" % client.internal_ip
)
def PrepareFrontend(vm):
PrepareCommon(vm)
vm.Install('cloudsuite/web-serving:web_server')
vm.Install('cloudsuite/web-serving:memcached_server')
vm.RemoteCommand(
'sudo docker run -dt --net host --name web_server '
'cloudsuite/web-serving:web_server '
'/etc/bootstrap.sh mysql_server memcache_server %s'
% (FLAGS.cloudsuite_web_serving_pm_max_children)
)
vm.RemoteCommand(
'sudo docker run -dt --net host --name memcache_server '
'cloudsuite/web-serving:memcached_server'
)
def PrepareBackend(vm):
PrepareCommon(vm)
vm.Install('cloudsuite/web-serving:db_server')
vm.RemoteCommand(
'sudo docker run -dt --net host --name mysql_server '
'cloudsuite/web-serving:db_server web_server'
)
def PrepareClient(vm):
PrepareCommon(vm)
vm.Install('cloudsuite/web-serving:faban_client')
target_arg_tuples = [
(PrepareFrontend, [frontend], {}),
(PrepareBackend, [backend], {}),
(PrepareClient, [client], {}),
]
background_tasks.RunParallelThreads(target_arg_tuples, len(target_arg_tuples))
def Run(benchmark_spec):
"""Run the web serving benchmark.
Args:
benchmark_spec: The benchmark specification. Contains all data that is
required to run the benchmark.
Returns:
A list of sample.Sample objects.
"""
frontend = benchmark_spec.vm_groups['frontend'][0]
client = benchmark_spec.vm_groups['client'][0]
results = []
cmd = (
'sudo docker run --net host --name faban_client '
'cloudsuite/web-serving:faban_client %s %s'
% (frontend.internal_ip, FLAGS.cloudsuite_web_serving_load_scale)
)
stdout, _ = client.RemoteCommand(cmd)
# The output contains a faban summary xml.
# Example: http://faban.org/1.1/docs/guide/driver/samplesummary_xml.html
match = re.search(
r'\<metric unit="ops/sec"\>(.+)\</metric\>', stdout, re.MULTILINE
)
if match:
results.append(sample.Sample('Throughput', float(match.group(1)), 'ops/s'))
matches = re.findall(r'\<avg\>(.+)\</avg\>', stdout, re.MULTILINE)
if len(matches) > 0:
sum_avg = 0.0
for m in matches:
sum_avg += float(m)
avg_avg = 1000 * sum_avg / len(matches)
results.append(sample.Sample('Average response time', avg_avg, 'ms'))
return results
def Cleanup(benchmark_spec):
"""Stop and remove docker containers. Remove images.
Args:
benchmark_spec: The benchmark specification. Contains all data that is
required to run the benchmark.
"""
frontend = benchmark_spec.vm_groups['frontend'][0]
backend = benchmark_spec.vm_groups['backend'][0]
client = benchmark_spec.vm_groups['client'][0]
def CleanupFrontend(vm):
vm.RemoteCommand('sudo docker stop memcache_server')
vm.RemoteCommand('sudo docker rm memcache_server')
vm.RemoteCommand('sudo docker stop web_server')
vm.RemoteCommand('sudo docker rm web_server')
def CleanupBackend(vm):
vm.RemoteCommand('sudo docker stop mysql_server')
vm.RemoteCommand('sudo docker rm mysql_server')
def CleanupClient(vm):
vm.RemoteCommand('sudo docker rm faban_client')
target_arg_tuples = [
(CleanupFrontend, [frontend], {}),
(CleanupBackend, [backend], {}),
(CleanupClient, [client], {}),
]
background_tasks.RunParallelThreads(target_arg_tuples, len(target_arg_tuples))