diff options
| author | Adam Israel <adam.israel@gmail.com> | 2015-05-07 16:38:16 -0400 |
|---|---|---|
| committer | Adam Israel <adam.israel@gmail.com> | 2015-05-07 16:38:16 -0400 |
| commit | 565aceb8a25ec7aeba628f5c7673b1b5c82f2119 (patch) | |
| tree | 20a715cfe5f77dc6e84641f76dbdb5caef8d6eb4 | |
| parent | 826b4feb4fe00bcffc6ccec635d785135902e05d (diff) | |
Add support for benchmarking via juju actions
| -rw-r--r-- | actions.yaml | 52 | ||||
| -rwxr-xr-x | actions/perf | 127 | ||||
| -rw-r--r-- | metadata.yaml | 2 |
3 files changed, 181 insertions, 0 deletions
diff --git a/actions.yaml b/actions.yaml new file mode 100644 index 0000000..816ea97 --- /dev/null +++ b/actions.yaml @@ -0,0 +1,52 @@ +# dex: +# description: Index and query analyzer for MongoDB, comparing MongoDB log files and index entries to make index recommendations +# params: +perf: + description: The standard mongoperf benchmark. + params: + runtime: + description: The time, in seconds, to run mongoperf. + type: integer + default: 180 + nthreads: + description: | + Defines the number of threads mongoperf will use in the test. To saturate your system’s storage system you will need multiple threads. Consider setting nThreads to 16. + type: integer + default: 1 + fileSizeMB: + description: Test file size, in megabytes. + type: integer + default: 1 + sleepMicros: + description: | + mongoperf will pause for the number of specified sleepMicros divided by the nThreads between each operation. + type: integer + default: 0 + mmf: + description: | + Set mmf to true to use memory mapped files for the tests. + type: boolean + default: False + r: + description: | + Set r to true to perform reads as part of the tests. + type: boolean + default: False + w: + description: | + Set w to true to perform writes as part of the tests. + type: boolean + default: False + recSizeKB: + description: The size of each write operation, in kilobytes. + type: integer + default: 4 + syncDelay: + description: | + Seconds between disk flushes. mongoperf.syncDelay is similar to --syncdelay for mongod. + + The syncDelay controls how frequently mongoperf performs an asynchronous disk flush of the memory mapped file used for testing. By default, mongod performs this operation every 60 seconds. Use syncDelay to test basic system performance of this type of operation. + + Only use syncDelay in conjunction with mmf set to true. + type: integer + default: 0 diff --git a/actions/perf b/actions/perf new file mode 100755 index 0000000..bae2cdc --- /dev/null +++ b/actions/perf @@ -0,0 +1,127 @@ +#!/usr/bin/env python +import signal +import subprocess +import os +import json +import re +from tempfile import NamedTemporaryFile +from distutils.spawn import find_executable + +try: + from charmhelpers.contrib.benchmark import Benchmark +except ImportError: + subprocess.check_call(['apt-get', 'install', '-y', 'python-pip']) + subprocess.check_call(['pip', 'install', 'charmhelpers']) + from charmhelpers.contrib.benchmark import Benchmark + + +def handler(signum, frame): + raise IOError('Timeout') + + +def action_set(key, val): + action_cmd = ['action-set'] + if isinstance(val, dict): + for k, v in val.iteritems(): + action_set('%s.%s' % (key, k), v) + return + + action_cmd.append('%s=%s' % (key, val)) + subprocess.check_call(action_cmd) + + +def action_get(key): + if find_executable('action-get'): + return subprocess.check_output(['action-get', key]).strip() + return None + + +def main(): + + Benchmark.start() + + """ + mongoperf runs until interupted so we have to use a + signal handler to stop it and gather the results + """ + signal.signal(signal.SIGALRM, handler) + runtime = int(action_get('runtime') or 180) + signal.alarm(runtime) + + js = {} + js['nThreads'] = int(action_get('nthreads')) + js['fileSizeMB'] = int(action_get('fileSizeMB')) + js['sleepMicros'] = int(action_get('sleepMicros')) + js['mmf'] = action_get('mmf') + js['r'] = action_get('r') + js['w'] = action_get('w') + js['recSizeKB'] = int(action_get('recSizeKB')) + js['syncDelay'] = int(action_get('syncDelay')) + + config = NamedTemporaryFile(delete=False) + config.write(json.dumps(js)) + config.close() + config = open(config.name, 'r') + + output = NamedTemporaryFile(delete=False) + + p = None + try: + p = subprocess.Popen( + 'mongoperf', + stdin=config, + stdout=output, + ) + os.waitpid(p.pid, 0) + except subprocess.CalledProcessError as e: + rc = e.returncode + print "Exit with error code %d" % rc + except IOError as e: + signal.alarm(0) + os.kill(p.pid, signal.SIGKILL) + finally: + os.unlink(config.name) + + output.close() + output = open(output.name, 'r') + scores = [] + regex = re.compile(r'(\d+)\sops\/sec') + for line in output: + m = regex.match(line) + if m: + scores.append(int(m.group(1))) + + action_set( + "results.total", + {'value': sum(scores), 'units': 'ops'} + ) + + action_set( + "results.iterations", + {'value': len(scores), 'units': 'iterations'} + ) + + action_set( + "results.average", + {'value': sum(scores) / float(len(scores)), 'units': 'ops/sec'} + ) + action_set( + "results.max", + {'value': max(scores), 'units': 'ops/sec'} + ) + action_set( + "results.min", + {'value': min(scores), 'units': 'ops/sec'} + ) + + Benchmark.set_composite_score( + sum(scores) / float(len(scores)), + 'ops/sec', + 'desc' + ) + + Benchmark.finish() + + +if __name__ == "__main__": + main() diff --git a/metadata.yaml b/metadata.yaml index 9b6c8e0..4a140e4 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -37,6 +37,8 @@ requires: interface: shard mongos: interface: mongodb + benchmark: + interface: benchmark peers: replica-set: interface: mongodb-replica-set |
