summaryrefslogtreecommitdiff
diff options
authorAdam Israel <adam.israel@gmail.com>2015-05-07 16:38:16 -0400
committerAdam Israel <adam.israel@gmail.com>2015-05-07 16:38:16 -0400
commit565aceb8a25ec7aeba628f5c7673b1b5c82f2119 (patch)
tree20a715cfe5f77dc6e84641f76dbdb5caef8d6eb4
parent826b4feb4fe00bcffc6ccec635d785135902e05d (diff)
Add support for benchmarking via juju actions
-rw-r--r--actions.yaml52
-rwxr-xr-xactions/perf127
-rw-r--r--metadata.yaml2
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