├── .gitignore ├── .hgignore ├── .travis.yml ├── FAQ ├── LICENSE ├── Makefile ├── README.org ├── examples ├── 2i.config ├── AroundTheWorldIn80Days.txt ├── README.md ├── basho_bench_ets.config ├── bitcask.config ├── bitcask_expiry.config ├── carbon.config ├── casbench.config ├── cassandra_cql.config ├── cluster.config ├── counters-2.0.config ├── counters.config ├── cs.config.sample ├── cs2.config ├── eleveldb_load.config ├── eleveldb_pop.config ├── hibari.config ├── http.config ├── httpraw.config ├── innostore_test.config ├── kv_backend.config ├── null_err_test.config ├── null_test.config ├── riakc_java.config ├── riakc_mr.config ├── riakc_pb+concat_binary.config ├── riakc_pb.config ├── riakc_pb.devrel.config ├── riakc_pb.search.devrel.config ├── riakc_pb_distributed.config ├── riakc_pb_text.config ├── riakclient.config ├── shortcut.config └── teams-crdt-map.config ├── include └── basho_bench.hrl ├── pkg.vars.config ├── priv ├── common.r ├── compare.r ├── gp_latencies.sh ├── gp_throughput.sh ├── results-browser.py ├── results-browser │ ├── index.html │ └── web │ │ ├── jquery.csv.js │ │ └── jquery.js └── summary.r ├── rebar ├── rebar.config ├── rebar.config.lock ├── rel ├── files │ ├── basho_bench │ ├── install_upgrade.escript │ └── vm.args ├── reltool.config └── vars.config ├── src ├── basho_bench.app.src ├── basho_bench.erl ├── basho_bench_app.erl ├── basho_bench_config.erl ├── basho_bench_driver_2i.erl ├── basho_bench_driver_bitcask.erl ├── basho_bench_driver_carbon.erl ├── basho_bench_driver_cassandra.erl ├── basho_bench_driver_cassandra_cql.erl ├── basho_bench_driver_cluster.erl ├── basho_bench_driver_cs.erl ├── basho_bench_driver_cs2.erl ├── basho_bench_driver_dets.erl ├── basho_bench_driver_eleveldb.erl ├── basho_bench_driver_ets.erl ├── basho_bench_driver_hibari.erl ├── basho_bench_driver_http.erl ├── basho_bench_driver_http_raw.erl ├── basho_bench_driver_innostore.erl ├── basho_bench_driver_kv_backend.erl ├── basho_bench_driver_null.erl ├── basho_bench_driver_nullfile.erl ├── basho_bench_driver_riakc_java.erl ├── basho_bench_driver_riakc_pb.erl ├── basho_bench_driver_riakclient.erl ├── basho_bench_driver_shortcut.erl ├── basho_bench_java_client.erl ├── basho_bench_keygen.erl ├── basho_bench_measurement.erl ├── basho_bench_measurement_erlangvm.erl ├── basho_bench_stats.erl ├── basho_bench_stats_writer.erl ├── basho_bench_stats_writer_csv.erl ├── basho_bench_stats_writer_riemann.erl ├── basho_bench_sup.erl ├── basho_bench_valgen.erl ├── basho_bench_worker.erl ├── basho_uuid.erl └── voxer_gen1.erl └── tests └── .keepme /.gitignore: -------------------------------------------------------------------------------- 1 | ebin/ 2 | deps/ 3 | tests/ 4 | /basho_bench 5 | /rel/basho_bench 6 | package 7 | .rebar 8 | *~ 9 | #*# 10 | 11 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | .beam 2 | tests/.*$ 3 | basho_bench$ 4 | erl_crash.dump$ 5 | deps/.*$ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: erlang 3 | notifications: 4 | webhooks: http://basho-engbot.herokuapp.com/travis?key=480c77ff15f4a07db659862802cc3df9e7a5d5be 5 | email: eng@basho.com 6 | otp_release: 7 | - 17.4 8 | - R16B03-1 9 | - R16B02 10 | - R16B01 11 | # At least one of the deps require min erlang R16. E.g. quickrand 12 | # - R15B03-1 13 | # - R15B01 14 | # - R15B 15 | # - R14B04 16 | # - R14B03 17 | 18 | branches: 19 | only: 20 | - master 21 | - statsbackend 22 | 23 | -------------------------------------------------------------------------------- /FAQ: -------------------------------------------------------------------------------- 1 | Frequently Asked Questions (FAQ) on basho_bench 2 | ------------------------------------------------------------------ 3 | 4 | Contributors: 5 | ------------------------------- 6 | Steve Morin (San Francisco, California, USA) 7 | 8 | Where to find the latest FAQ: 9 | ----------------------------- 10 | This FAQ can be found at: 11 | https://github.com/smorin/basho_bench/blob/master/FAQ 12 | 13 | CONTENTS 14 | ******** 15 | 16 | 1) COMPILING and BUILDING 17 | 1.1) Build Error - Uncaught error in rebar_core: {'EXIT', {undef, [{crypto,start,[]} 18 | 19 | 1) COMPILING and BUILDING 20 | 21 | 1.1) Build Error - Uncaught error in rebar_core: {'EXIT', {undef, [{crypto,start,[]} 22 | 23 | If you get the following error: "Your local Erlang install doesn't include the crypto application. Make sure you have the erlang-crypto and erlang-dev packages installed if you're on Debian, erlang-crypto and erlang-devel on Redhat/Fedora." quoting "seancribbs" The simple mac solution is sudo port install erlang +ssl 24 | $ make all 25 | ./rebar get-deps 26 | Uncaught error in rebar_core: {'EXIT', 27 | {undef, 28 | [{crypto,start,[]}, 29 | {rebar,run_aux,1}, 30 | {rebar,main,1}, 31 | {escript,run,2}, 32 | {escript,start,1}, 33 | {init,start_it,1}, 34 | {init,start_em,1}]}} 35 | make: *** [deps] Error 1 36 | 37 | 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | REPO ?= basho_bench 2 | 3 | PKG_REVISION ?= $(shell git describe --tags) 4 | PKG_VERSION ?= $(shell git describe --tags | tr - .) 5 | PKG_ID = basho-bench-$(PKG_VERSION) 6 | PKG_BUILD = 1 7 | BASE_DIR = $(shell pwd) 8 | ERLANG_BIN = $(shell dirname $(shell which erl)) 9 | REBAR ?= $(BASE_DIR)/rebar 10 | OVERLAY_VARS ?= 11 | 12 | 13 | all: deps compile 14 | $(REBAR) skip_deps=true escriptize 15 | 16 | .PHONY: deps compile rel lock locked-all locked-deps 17 | 18 | rel: deps compile 19 | cd rel && $(REBAR) generate skip_deps=true $(OVERLAY_VARS) 20 | 21 | deps: 22 | $(REBAR) get-deps 23 | 24 | ## 25 | ## Lock Targets 26 | ## 27 | ## see https://github.com/seth/rebar_lock_deps_plugin 28 | lock: deps compile 29 | $(REBAR) lock-deps 30 | 31 | locked-all: locked-deps compile 32 | 33 | locked-deps: 34 | @echo "Using rebar.config.lock file to fetch dependencies" 35 | $(REBAR) -C rebar.config.lock get-deps 36 | 37 | compile: deps 38 | # Temp hack to work around https://github.com/basho/riak-erlang-client/issues/151 39 | (cd deps/riak_pb ; $(REBAR) clean compile deps_dir=..) 40 | @($(REBAR) compile) 41 | 42 | clean: 43 | @$(REBAR) clean 44 | 45 | distclean: clean 46 | @rm -rf basho_bench deps 47 | 48 | results: 49 | Rscript --vanilla priv/summary.r -i tests/current 50 | 51 | ops_sec-results: results 52 | 53 | byte_sec-results: 54 | Rscript --vanilla priv/summary.r --ylabel1stgraph byte/sec -i tests/current 55 | 56 | kb_sec-results: 57 | Rscript --vanilla priv/summary.r --ylabel1stgraph KB/sec -i tests/current 58 | 59 | kib_sec-results: 60 | Rscript --vanilla priv/summary.r --ylabel1stgraph KiB/sec -i tests/current 61 | 62 | mb_sec-results: 63 | Rscript --vanilla priv/summary.r --ylabel1stgraph MB/sec -i tests/current 64 | 65 | mib_sec-results: 66 | Rscript --vanilla priv/summary.r --ylabel1stgraph MiB/sec -i tests/current 67 | 68 | results-browser: 69 | cp -R priv/results-browser/* tests/current && cd tests/current && python -c 'import os, json; print json.dumps(os.listdir("."))' > web/data.json && python ../../priv/results-browser.py 70 | 71 | TARGETS := $(shell ls tests/ | grep -v current) 72 | JOBS := $(addprefix job,${TARGETS}) 73 | .PHONY: all_results ${JOBS} 74 | 75 | all_results: ${JOBS} ; echo "$@ successfully generated." 76 | ${JOBS}: job%: ; Rscript --vanilla priv/summary.r -i tests/$* 77 | 78 | ## 79 | ## Packaging targets 80 | ## 81 | .PHONY: package 82 | export PKG_VERSION PKG_ID PKG_BUILD BASE_DIR ERLANG_BIN REBAR OVERLAY_VARS RELEASE 83 | 84 | package.src: deps 85 | mkdir -p package 86 | rm -rf package/$(PKG_ID) 87 | git archive --format=tar --prefix=$(PKG_ID)/ $(PKG_REVISION)| (cd package && tar -xf -) 88 | ${MAKE} -C package/$(PKG_ID) locked-deps 89 | for dep in package/$(PKG_ID)/deps/*; do \ 90 | echo "Processing dep: $${dep}"; \ 91 | mkdir -p $${dep}/priv; \ 92 | git --git-dir=$${dep}/.git describe --always --tags >$${dep}/priv/vsn.git; \ 93 | done 94 | find package/$(PKG_ID) -depth -name ".git" -exec rm -rf {} \; 95 | tar -C package -czf package/$(PKG_ID).tar.gz $(PKG_ID) 96 | 97 | dist: package.src 98 | cp package/$(PKG_ID).tar.gz . 99 | 100 | package: package.src 101 | ${MAKE} -C package -f $(PKG_ID)/deps/node_package/Makefile 102 | 103 | pkgclean: distclean 104 | rm -rf package 105 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * basho_bench 2 | ** Overview 3 | [[http://travis-ci.org/basho/basho_bench][Travis-CI]] :: [[https://secure.travis-ci.org/basho/basho_bench.png]] 4 | 5 | [[http://docs.basho.com/riak/latest/ops/building/benchmarking/][Additional documentation on docs.basho.com]] 6 | 7 | Basho Bench is a benchmarking tool created to conduct accurate and 8 | repeatable performance tests and stress tests, and produce 9 | performance graphs. 10 | 11 | Originally developed to benchmark Riak, it exposes a pluggable 12 | driver interface and has been extended to serve as a benchmarking 13 | tool across a variety of projects. 14 | 15 | Basho Bench focuses on two metrics of performance: 16 | 17 | - Throughput: number of operations performed in a timeframe, 18 | captured in aggregate across all operation types 19 | - Latency: time to complete single operations, captured in 20 | quantiles per-operation 21 | 22 | ** Quick Start 23 | 24 | You must have [[http://erlang.org/download.html][Erlang/OTP R16]] or later to build and run Basho 25 | Bench, and [[http://www.r-project.org/][R]] to generate graphs of your benchmarks. A sane 26 | GNU-style build system is also required if you want to use =make= 27 | to build the project. 28 | 29 | #+BEGIN_SRC shell 30 | git clone git://github.com/basho/basho_bench.git 31 | cd basho_bench 32 | make all 33 | #+END_SRC 34 | 35 | This will build an executable script, =basho_bench=, which you can 36 | use to run one of the existing benchmark configurations from the 37 | =examples/= directory. You will likely have to make some minor directory 38 | changes to the configs in order to get the examples running (see, e.g., the 39 | source of the bitcask and innostore benchmark config files for direction). 40 | 41 | #+BEGIN_SRC shell 42 | $ ./basho_bench examples/riakc_pb.config 43 | INFO: Est. data size: 95.37 MB 44 | INFO: Using target ip {127,0,0,1} for worker 1 45 | INFO: Starting max worker: <0.55.0> 46 | #+END_SRC 47 | 48 | At the end of the benchmark, results will be available in CSV 49 | format in the =tests/current/= directory. Now you can generate a 50 | graph: 51 | 52 | #+BEGIN_SRC shell 53 | $ make results 54 | priv/summary.r -i tests/current 55 | Loading required package: proto 56 | Loading required package: reshape 57 | Loading required package: plyr 58 | Loading required package: digest 59 | null device 60 | 1 61 | $ open tests/current/summary.png 62 | #+END_SRC 63 | 64 | ** Troubleshooting Graph Generation 65 | 66 | If make results fails with the error =/usr/bin/env: Rscript --vanilla: No such file or directory= 67 | please edit priv/summary.r and replace the first line with the full path to the Rscript binary on your system 68 | 69 | If you receive the error message =Warning: unable to access index for repository http://lib.stat.cmu.edu/R/CRAN/src/contrib= 70 | it means the default R repo for installing additional packages is broken, you can change it as follows: 71 | 72 | #+BEGIN_SRC shell 73 | $ R 74 | > chooseCRANmirror() 75 | Selection: 69 76 | quit() 77 | make results 78 | #+END_SRC 79 | 80 | ** Customizing your Benchmark 81 | Basho Bench has many drivers, each with its own configuration, and 82 | a number of key and value generators that you can use to customize 83 | your benchmark. It is also straightforward -- with less than 200 84 | lines of Erlang code -- to create custom drivers that can exercise 85 | other systems or perform custom operations. These are covered more 86 | in detail in the [[http://docs.basho.com/riak/latest/ops/building/benchmarking/][documentation]]. 87 | 88 | ** Benchmarking with riak-java-client 89 | The [[https://github.com/basho/riak-java-client][riak-java-client]] can be used to benchmark a Riak cluster. There 90 | is an example configuration in =examples/riakc_java.config=. You 91 | will need the [[https://github.com/basho/bench_shim][bench_shim]] project. You will also need to uncomment 92 | and edit the following line in basho_bench's =rebar.config=, adding 93 | your own erlang cookie value: 94 | 95 | #+BEGIN_SRC shell 96 | %% {escript_emu_args, "%%! -name bb@127.0.0.1 -setcookie YOUR_ERLANG_COOKIE\n"}. 97 | #+END_SRC 98 | 99 | ** Alternative Graph Generation by gnuplot 100 | You can generate graphs using gnuplot. 101 | 102 | #+BEGIN_SRC shell 103 | $ ./priv/gp_throughput.sh 104 | #+END_SRC 105 | 106 | #+BEGIN_SRC shell 107 | $ ./priv/gp_latencies.sh 108 | #+END_SRC 109 | 110 | By passing =-h= option to each script, help messages are shown. 111 | 112 | Some of options for these scripts are: 113 | 114 | - =-d TEST_DIR= : comma separated list of directories which include 115 | test result CSV files 116 | - =-t TERMINAL_TYPE= : gnuplot terminal type 117 | - =-P= : just print gnuplot script without drawing graph 118 | 119 | For example, you can draw graphs with ASCII characters 120 | by the option =-t dumb=, which is useful in non-graphical 121 | environment or quick sharing of result in chat. 122 | 123 | Also, you can plot multiple test runs on a single plot by using "-d" switch. 124 | 125 | ** Benchmarking Erlang cluster 126 | 127 | A typical benchmark scenario is that Basho Bench spawn Erlang VM and executes the driver inside. However, there is needs to catch performance metrics from an application executed remotely within dedicated environment (e.g. probe performance from live system; benchmark an application inside C or Java node, etc). Bash Bench implements a generic =basho_bench_driver_cluster= that acts as proxy. It uses Erlang distribution to delegate benchmark responsibility to remote actor, which is randomly selected from configured pool. 128 | 129 | Basho Bench do not define how the actors are spawned within SUT. It only defined a communication protocol. The actor is responsible to handle the message: 130 | 131 | ={pid(), atom(), key(), val()}= 132 | 133 | - =pid()= : request originator, actor shall respond to this process 134 | - =atom()= : id of operation to execute as defined in config file 135 | - =key()= : materialized key value as defined by key generator function 136 | - =val()= : materialized value as defined by value generator function 137 | 138 | The actor executes the request, measures performance and respond to originator process =pid()= with one of the message ={ok, microsecond()}= or ={error, reason()}= 139 | 140 | See cluster.config example for details. Use following command to spawn benchmark 141 | 142 | #+BEGIN_SRC shell 143 | ./basho_bench -C nocookie -N bb@127.0.0.1 -J erlang@127.0.0.1 examples/cluster.config 144 | #+END_SRC 145 | 146 | 147 | ** Contributing 148 | We encourage contributions to Basho Bench from the community. 149 | 150 | 1) Fork the =basho_bench= repository on [[https://github.com/basho/basho_bench][Github]]. 151 | 152 | 2) Clone your fork or add the remote if you already have a clone of 153 | the repository. 154 | 155 | #+BEGIN_SRC shell 156 | git clone git@github.com:yourusername/basho_bench.git 157 | # or 158 | git remote add mine git@github.com:yourusername/basho_bench.git 159 | #+END_SRC 160 | 161 | 3) Create a topic branch for your change. 162 | 163 | #+BEGIN_SRC shell 164 | git checkout -b some-topic-branch 165 | #+END_SRC 166 | 167 | 4) Make your change and commit. Use a clear and descriptive commit 168 | message, spanning multiple lines if detailed explanation is 169 | needed. 170 | 171 | 5) Push to your fork of the repository and then send a pull-request 172 | through Github. 173 | 174 | #+BEGIN_SRC shell 175 | git push mine some-topic-branch 176 | #+END_SRC 177 | 178 | 6) A Basho engineer or community maintainer will review your patch 179 | and merge it into the main repository or send you feedback. 180 | -------------------------------------------------------------------------------- /examples/2i.config: -------------------------------------------------------------------------------- 1 | {driver, 2 | basho_bench_driver_2i}. 3 | 4 | {operations, [ 5 | {get_pb, 1}, 6 | {{put_pb, 5}, 20}, 7 | {{query_http, 10}, 1}, 8 | {{query_mr, 10}, 1}, 9 | {{query_pb, 10}, 1} 10 | ]}. 11 | 12 | {measurement_driver, 13 | basho_bench_measurement_erlangvm}. 14 | 15 | {measurements, [ 16 | {memory, 1000}, 17 | {cpu, 1000}, 18 | {processes, 1000}, 19 | {filehandles, 1000} 20 | ]}. 21 | 22 | %%% LOAD SETTINGS %%% 23 | 24 | {mode, max}. 25 | {duration, 1}. 26 | {concurrent, 3}. 27 | 28 | %%% DATA SHAPE %%% 29 | 30 | {key_generator, {uniform_int, 1000}}. 31 | {value_generator, {fixed_bin, 1000}}. 32 | 33 | {pb_ips, ["127.0.0.1"]}. 34 | {pb_replies, 1}. 35 | 36 | {http_ips, ["127.0.0.1"]}. 37 | {http_port, 8098}. 38 | 39 | %% Timeout units are milliseconds, default = 30000 40 | {pb_timeout_general, 30000}. 41 | {http_timeout_general, 30000}. 42 | 43 | %%It can also be configured for devrel! 44 | %%{pb_ips, [{"127.0.0.1", 8081}, 45 | %% {"127.0.0.1", 8082}, 46 | %% {"127.0.0.1", 8083}, 47 | %% {"127.0.0.1", 8084} 48 | %%]}. 49 | %%{pb_replies, 1}. 50 | %% 51 | %%{http_ips, [{"127.0.0.1", 8091}, 52 | %% {"127.0.0.1", 8092}, 53 | %% {"127.0.0.1", 8093}, 54 | %% {"127.0.0.1", 8094} 55 | %%]}. 56 | 57 | {rng_seed, {1, 2, 3}}. 58 | 59 | %% enforce_keyrange is for use with sequential_int 60 | %% Will error if keys in a range are missing. 61 | %%{enforce_keyrange, 10000}. 62 | 63 | %%% MEASUREMENT SETTINGS %%% 64 | 65 | {nodes, ['riak@127.0.0.1']}. 66 | {cookie, riak}. 67 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | README for examples 2 | =================== 3 | 4 | Please see the source for the innostore and bitcask configuration files to see how to modify these config files to work properly in your 5 | development or testing environment 6 | -------------------------------------------------------------------------------- /examples/basho_bench_ets.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 3}. 4 | 5 | {concurrent, 4}. 6 | 7 | {driver, basho_bench_driver_ets}. 8 | 9 | {operations, [{get,1}, {put,1}]}. 10 | 11 | {key_generator, {int_to_bin_bigendian, {uniform_int, 1000}}}. 12 | 13 | {value_generator, {fixed_bin, 100000}}. 14 | 15 | -------------------------------------------------------------------------------- /examples/bitcask.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | 5 | {concurrent, 1}. 6 | 7 | {driver, basho_bench_driver_bitcask}. 8 | 9 | {key_generator, {int_to_bin_bigendian,{uniform_int, 5000000}}}. 10 | 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | {operations, [{get, 1}, {put, 1}]}. 14 | 15 | %% the second element in the list below (e.g., "../../public/bitcask") must point to 16 | %% the relevant directory of a bitcask installation 17 | {code_paths, ["../../public/bitcask"]}. 18 | 19 | {bitcask_dir, "/tmp/bitcask.bench"}. 20 | 21 | {bitcask_flags, [o_sync]}. 22 | -------------------------------------------------------------------------------- /examples/bitcask_expiry.config: -------------------------------------------------------------------------------- 1 | {mode, {rate, 100}}. 2 | 3 | {duration, 2}. 4 | 5 | {concurrent, 1}. 6 | 7 | {driver, basho_bench_driver_bitcask}. 8 | 9 | {key_generator, uuid_v4}. 10 | 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | {operations, [{put, 9}, {merge, 1}]}. 14 | 15 | {code_paths, ["/Users/dizzyd/src/bitcask"]}. 16 | 17 | {bitcask_dir, "/tmp/bitcask.bench"}. 18 | 19 | {bitcask_flags, [{max_file_size, 5242880}, 20 | {log_needs_merge, true}, 21 | {expiry_secs, 10}]}. 22 | -------------------------------------------------------------------------------- /examples/carbon.config: -------------------------------------------------------------------------------- 1 | {mode, {rate, 1}}. 2 | 3 | {duration, 5}. 4 | 5 | {concurrent, 100}. 6 | 7 | {driver, basho_bench_driver_carbon}. 8 | 9 | {operations, [{set, 1}]}. 10 | 11 | {key_generator, {pareto_int, 100}}. 12 | 13 | {carbon_batch_size, 150}. 14 | {carbon_keep_connect, true}. 15 | -------------------------------------------------------------------------------- /examples/casbench.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 1}. 4 | 5 | {concurrent, 10}. 6 | 7 | {driver, basho_bench_driver_cassandra}. 8 | {cassandra_hosts, ["127.0.0.1"]}. 9 | {cassandra_port, 9160}. 10 | {cassandra_keyspace, "Keyspace1"}. 11 | {cassandra_consistencylevel, 1}. 12 | 13 | 14 | {key_generator, {int_to_str, {uniform_int, 5000000}}}. 15 | 16 | {value_generator, {fixed_bin, 10000}}. 17 | 18 | {operations, [{get, 1}, {put, 1}]}. 19 | 20 | {code_paths, ["./deps/casbench/ebin"]}. 21 | -------------------------------------------------------------------------------- /examples/cassandra_cql.config: -------------------------------------------------------------------------------- 1 | %% Setup notes: 2 | %% 3 | %% Run the following queries in a cqlsh session: 4 | %% CREATE KEYSPACE DEMO WITH strategy_class = SimpleStrategy AND strategy_options:replication_factor = 1; 5 | %% CREATE COLUMNFAMILY test (KEY varchar PRIMARY KEY, val blob); 6 | 7 | %% Cassandra v2.0.1 - adjust replication_factor accordingly 8 | %% DROP KEYSPACE DEMO; 9 | %% CREATE KEYSPACE DEMO WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '3' }; 10 | %% USE DEMO; 11 | %% CREATE COLUMNFAMILY test (KEY varchar PRIMARY KEY, val blob); 12 | 13 | %% For timeseries with composite keys/Cassandra v2.0.1 - adjust replication_factor accordingly 14 | %% DROP KEYSPACE DEMO; 15 | %% CREATE KEYSPACE DEMO WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '3' }; 16 | %% USE DEMO; 17 | %% CREATE TABLE test (partition_key text, row_key timestamp, val blob, PRIMARY KEY (partition_key,row_key)); 18 | 19 | {mode, max}. 20 | 21 | {duration, 1}. 22 | 23 | {concurrent, 5}. 24 | 25 | {driver, basho_bench_driver_cassandra_cql}. 26 | 27 | %% Preload only 28 | %%{key_generator, {int_to_str, {partitioned_sequential_int, 50000}}}. 29 | %% Timeseries tests 30 | {key_generator, {partitioned_sequential_int, 50000, 1000000000}}. 31 | 32 | 33 | %% All other single_value tests 34 | %%{key_generator, {int_to_str, {uniform_int, 50000}}}. 35 | 36 | {value_generator, {fixed_bin, 100}}. 37 | 38 | {cassandra_ips, [{"localhost", 9042}]}. 39 | %%{cassandra_port, 9042}. 40 | 41 | {cassandra_keyspace, "DEMO"}. 42 | {cassandra_columnfamily, "test"}. 43 | {cassandra_column, "val"}. 44 | 45 | %% If using put_composite and query_composite, set these and use the composite key schema. 46 | %% {cassandra_composite_partition_column, "partition_key"}. 47 | %% {cassandra_composite_row_column, "row_key"}. 48 | %% {cassandra_range_query_num_rows, 500}. 49 | 50 | %% Uncomment to set the read and write consistency levels. 51 | %% See deps/cqerl/include/cqerl.hrl for acceptable values. 52 | %% These are the defaults if not provided: 53 | %% {cassandra_read_consistency, 1}. % CQERL_CONSISTENCY_ONE 54 | %% {cassandra_write_consistency, 4}. % CQERL_CONSISTENCY_QUORUM 55 | 56 | 57 | {operations, [{put, 1},{get, 1},{delete, 1}]}. 58 | %%{operations, [{put_composite, 10}, {query_composite, 1}]}. 59 | %%{operations, [{query_composite, 1}]}. 60 | %% NOTE: insert is functionally and perfomance-equivalent to a put. 61 | %% `insert` and `put` now use the same code path - `insert` was preserved 62 | %% only for backward_compatibility 63 | %%{operations, [{insert, 10}]}. 64 | %%{operations, [{put, 1}]}. 65 | %%{operations, [{get, 1}]}. 66 | %%{operations, [{delete, 1}]}. 67 | 68 | {code_paths, ["./deps/cqerl/ebin", "./deps/pooler/ebin", "./deps/uuid/ebin", 69 | "./deps/semver/ebin"]}. 70 | -------------------------------------------------------------------------------- /examples/cluster.config: -------------------------------------------------------------------------------- 1 | %% 2 | %% definition 3 | {log_level, info}. 4 | {report_interval, 1}. 5 | {driver, basho_bench_driver_cluster}. 6 | 7 | %% 8 | %% workload 9 | {mode, max}. 10 | {duration, 1}. 11 | {concurrent, 10}. 12 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 13 | {value_generator, {fixed_bin, 1000}}. 14 | 15 | {operations, [ 16 | {put, 1} 17 | ,{get, 1} 18 | ]}. 19 | 20 | %% 21 | %% config 22 | {cluster_actors, [ 23 | {a, 'erlang@127.0.0.1'} 24 | {b, 'erlang@127.0.0.1'} 25 | {c, 'gnalre@127.0.0.1'} 26 | ]}. 27 | 28 | -------------------------------------------------------------------------------- /examples/counters-2.0.config: -------------------------------------------------------------------------------- 1 | {mode,{rate,max}}. 2 | {duration,1}. 3 | {rng_seed,now}. 4 | 5 | %% This bucket type must be created and set to be datatype, maps. 6 | {riakc_pb_bucket,{<<"counters">>,<<"testbucket">>}}. 7 | 8 | %% Pareto distribution over 7.5 million records. 9 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 10 | {value_generator, {uniform_int, 100}}. 11 | 12 | {concurrent,10}. 13 | 14 | {operations,[{{counter,increment},1}, 15 | {{counter,value},10}]}. 16 | 17 | {riakc_pb_ips,[{"127.0.0.1",8087}]}. 18 | 19 | {riakc_pb_replies,default}. 20 | 21 | {driver,basho_bench_driver_riakc_pb}. 22 | -------------------------------------------------------------------------------- /examples/counters.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 5}. 4 | 5 | {concurrent, 1}. 6 | 7 | {driver, basho_bench_driver_riakc_pb}. 8 | 9 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 10 | 11 | {value_generator, {uniform_int, 50}}. 12 | 13 | {riakc_pb_ips, [{127,0,0,1}]}. 14 | 15 | {riakc_pb_replies, 2}. 16 | 17 | {operations, [{counter_incr, 100}, {counter_val, 1}]}. 18 | 19 | %% Use {auto_reconnect, false} to get "old" behavior (prior to April 2013). 20 | %% See deps/riakc/src/riakc_pb_socket.erl for all valid socket options. 21 | {pb_connect_options, [{auto_reconnect, true}]}. 22 | 23 | %% Overrides for the PB client's default 60 second timeout, on a 24 | %% per-type-of-operation basis. All timeout units are specified in 25 | %% milliseconds. The pb_timeout_general config item provides a 26 | %% default timeout if the read/write/listkeys/mapreduce timeout is not 27 | %% specified. 28 | 29 | {pb_timeout_general, 30000}. 30 | {pb_timeout_read, 5000}. 31 | {pb_timeout_write, 5000}. 32 | {pb_timeout_listkeys, 50000}. 33 | %% The general timeout will be used because this specific item is commented: 34 | %% {pb_timeout_mapreduce, 50000}. 35 | -------------------------------------------------------------------------------- /examples/cs.config.sample: -------------------------------------------------------------------------------- 1 | %% Sample config file for Riak CS basho_bench benchmarking 2 | 3 | %% About rate limiting via the `mode` setting: the `mode` rate is 4 | %% valid for the basho_bench_driver_cs plugin for `get` operations. 5 | %% The `mode` rate does *not* apply to `insert` operations. 6 | %% The driver does *not* support `update` operations 7 | 8 | {mode, max}. 9 | %{mode, {rate,4}}. 10 | {duration, 1}. 11 | {concurrent, 1}. 12 | {report_interval, 1}. 13 | 14 | {driver, basho_bench_driver_cs}. 15 | 16 | %% Two ways of user configuration 17 | %% 1. Set cs_access_key and cs_secret_key for existing user. 18 | %% Replace this with a user you have created. 19 | %% Instructions to create a user are here: 20 | %% http://docs.basho.com/riakcs/latest/cookbooks/Account-Management/#Creating-a-User-Account 21 | {cs_access_key, "ZG7SS3ZPECF-8LZOEBMA"}. 22 | {cs_secret_key, "21HoIRdeO617nJrIbam9mKH2MBxmcsMEwESvmQ=="}. 23 | 24 | %% 2. Let the driver create or retrieve user 25 | %% In this case, you should 26 | %% - setup riak-cs with {admin_auth_enabled, false} and 27 | %% - comment out cs_access_key and cs_secret_key above 28 | %% cs_display_name is used to identify user. 29 | %% {cs_display_name, "test-user"}. 30 | 31 | %% CS Bucket, it will be created if needed 32 | {cs_bucket, "test-bucket"}. 33 | 34 | {cs_disconnect_frequency, 5}. % # ops before disconnecting HTTP socket 35 | {cs_raw_ip, "s3.amazonaws.com"}. % DO NOT CHANGE 36 | {cs_raw_port, 80}. % DO NOT CHANGE 37 | %% Replace these with your HTTP proxy's location (i.e. Riak CS) 38 | {cs_http_proxy_host, [{"localhost", 8080}, {"127.0.0.1", 8080}, {{127,0,0,1}, 8080}]}. 39 | {cs_http_proxy_port, 8080}. 40 | {cs_request_timeout, 999999000}. 41 | % Valid values for cs_measurement_units are ops_sec, byte_sec, kb_sec, 42 | % kib_sec, mb_sec, or mib_sec. 43 | % If using the cs_measurement_units option, you need to change 44 | % any R graph's labels of the Y axis, e.g. basho_bench's Makefile target 45 | % "make mb_sec-results" 46 | {cs_measurement_units, mb_sec}. 47 | 48 | {key_generator, {int_to_str, {partitioned_sequential_int, 1000}}}. 49 | %{key_generator, {int_to_str, {uniform_int, 1000}}}. 50 | %% See comments in source code for bigfile_valgen() function for full 51 | %% explanation of the proplist below. 52 | {value_generator, {function, basho_bench_driver_cs, bigfile_valgen, 53 | [[{file_size, 8001001}, 54 | {ibrowse_chunk_size, 1000000}, 55 | {max_rate_per_chunk, 50}]]}}. 56 | 57 | %% NOTE: It's not a good idea to mix insert & get ops in a single 58 | %% basho_bench instance with this driver. 59 | %% Use separate ones instead! 60 | %% bad idea: {operations, [{insert, 1}, {get, 1}]}. 61 | {operations, [{insert, 1}]}. 62 | %{operations, [{get, 1}]}. 63 | %{operations, [{delete, 1}]}. 64 | -------------------------------------------------------------------------------- /examples/cs2.config: -------------------------------------------------------------------------------- 1 | %% NOTE: 2 | %% This driver requires Riak CS is configured as 3 | %% {admin_auth_enabled, false}, 4 | %% in order to automatically create users and buckets, also list users. 5 | 6 | {mode, max}. 7 | 8 | {report_interval, 1}. 9 | {duration, infinity}. 10 | {concurrent, 16}. 11 | 12 | {driver, basho_bench_driver_cs2}. 13 | 14 | {cs2_host_base, "s3.amazonaws.com"}. 15 | {cs2_port, 8080}. 16 | {cs2_hosts, [{"127.0.0.1", 8080}]}. 17 | 18 | {cs2_user_count, 30}. 19 | 20 | %% For riak_cs_yessir_riak_client, this should be "yessir" 21 | {cs2_user_prefix, "bb-user"}. 22 | 23 | {cs2_bucket_prefix, "bb-bucket"}. 24 | 25 | %% Keys should be integer. 26 | %% It's good idea to make key count be multiple of `cs2_user_count'. 27 | %% 28 | %% Keys are decomposed as "divmod" manner for object keys and user 29 | %% suffix (one added for 1-origin). 30 | %% Assuming `cs2_user_count' is 3, output are as follows. 31 | %% | input | user | object key | 32 | %% | 1 | bb-user1 | 1 | 33 | %% | 2 | bb-user2 | 1 | 34 | %% | 3 | bb-user3 | 1 | 35 | %% | 4 | bb-user1 | 2 | 36 | %% | 5 | bb-user2 | 2 | 37 | {key_generator, {partitioned_sequential_int, 100000}}. 38 | 39 | {value_generator, {fixed_bin, 10}}. 40 | 41 | %% Avaliable operations: 42 | %% - get, get_existing 43 | %% - put, delete, put_delete 44 | %% - noop (for debugging) 45 | {operations, [{put, 1}]}. 46 | -------------------------------------------------------------------------------- /examples/eleveldb_load.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | 5 | {concurrent, 64}. 6 | 7 | {driver, basho_bench_driver_eleveldb}. 8 | 9 | {key_generator, {int_to_bin_bigendian,{uniform_int, 1000000}}}. 10 | 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | {operations, [{get, 5}, {put, 1}]}. 14 | 15 | %% the second element in the list below (e.g., "../../public/eleveldb") must 16 | %% point to the relevant directory of a eleveldb installation 17 | {code_paths, ["/ebin"]}. 18 | 19 | {eleveldb_dir, "/tmp/eleveldb.bench"}. 20 | {eleveldb_num_instances, 32}. 21 | 22 | -------------------------------------------------------------------------------- /examples/eleveldb_pop.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | 5 | {concurrent, 64}. 6 | 7 | {driver, basho_bench_driver_eleveldb}. 8 | 9 | {key_generator, {int_to_bin_bigendian,{partitioned_sequential_int, 10000000}}}. 10 | 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | {operations, [{put, 1}]}. 14 | 15 | %% the second element in the list below (e.g., "../../public/eleveldb") must 16 | %% point to the relevant directory of a eleveldb installation 17 | {code_paths, ["/ebin"]}. 18 | 19 | {eleveldb_dir, "/tmp/eleveldb.bench"}. 20 | {eleveldb_num_instances, 32}. 21 | 22 | -------------------------------------------------------------------------------- /examples/hibari.config: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang -*- 2 | 3 | {mode, max}. 4 | %% Remember: actual rate = mode rate (below) * concurrent (below) 5 | %% 6 | %% SLF: Hrm, this doesn't seem to play very well with Hibari client 7 | %% protocol timeouts?? Or I just need to experiment more with 8 | %% changing both the per-generator rate and the # of concurrent 9 | %% generators? 10 | %{mode, {rate, 8}}. 11 | 12 | {duration, 15}. % 1 minute is very short 13 | 14 | {concurrent, 100}. % 5 is low for Hibari 15 | 16 | {driver, basho_bench_driver_hibari}. 17 | 18 | {code_paths, [ 19 | %% If you have the Hibari source distribution pulled 20 | %% from SourceForge and compiled, then change the prefix 21 | %% for these paths from "/User/fritchie/src/hibari" to 22 | %% the top of your Hibari source. 23 | 24 | "/Users/fritchie/src/hibari/src/erl-apps/cluster-info__HEAD/ebin", 25 | "/Users/fritchie/src/hibari/src/erl-apps/gdss__HEAD/ebin", 26 | "/Users/fritchie/src/hibari/src/erl-apps/gmt-util__HEAD/ebin", 27 | "/Users/fritchie/src/hibari/src/erl-apps/gdss-ubf-proto__HEAD/ebin", 28 | "/Users/fritchie/src/hibari/src/erl-third-party/mochiweb__HEAD/ebin", 29 | "/Users/fritchie/src/hibari/src/erl-tools/ubf-jsonrpc__HEAD/ebin", 30 | "/Users/fritchie/src/hibari/src/erl-tools/ubf-thrift__HEAD/ebin", 31 | "/Users/fritchie/src/hibari/src/erl-tools/ubf__HEAD/ebin" 32 | ]}. 33 | 34 | {key_generator, {int_to_bin_bigendian, {uniform_int, 99000}}}. 35 | 36 | {value_generator, {fixed_bin, 1000}}. 37 | %{value_generator, {fixed_bin, 10000}}. 38 | 39 | %% Default is [{get,4}, {put,4}, {delete, 1}] which means that out of 40 | %% every 9 operations, 'get' will be called four times, 'put' will 41 | %% called four times, and 'delete' will be called once, on average. 42 | 43 | {operations, [{get,4}, {put,4}, {delete, 1}]}. 44 | 45 | %% hibari_table 46 | %% 47 | %% Name of the Hibari table to operate on. Must be an atom. 48 | 49 | {hibari_table, tab1}. 50 | %{hibari_table, tab1_nosync}. 51 | 52 | %% hibari_client_type 53 | %% 54 | %% Type of Hibari client: native, ubf, ebf, jsf, tbf, json_rpc 55 | %% Uncomment only one of the pairs below. 56 | %% 57 | %% hibari_server_tcp_port 58 | %% 59 | %% For use with all Hibari clients other than the native Erlang client. 60 | %% (This attribute is ignored by the native Erlang client.) 61 | %% 62 | %% TCP port number for the target server. Default port numbers: 63 | %% 64 | %% EBF 7580 65 | %% UBF 7581 66 | %% JSF 7582 67 | %% TBF 7599 68 | %% 69 | %% hibari_server_service: undefined, gdss, gdss_stub 70 | %% 71 | %% For use with all Hibari clients other than the native Erlang client. 72 | %% (This attribute is ignored by the native Erlang client.) 73 | %% 74 | %% UBF service for the target server. The service "gdss" is the 75 | %% default service. The service "gdss_stub" can be used to measure 76 | %% the latency (and throughput) of the UBF rpc transport. 77 | %% 78 | 79 | %{hibari_client_type, native}. 80 | %{hibari_server_tcp_port, -1}. % Value is unused but must be present 81 | %{hibari_server_service, undefined}. % Value is unused but must be present 82 | 83 | {hibari_client_type, ebf}. 84 | {hibari_server_tcp_port, 7580}. 85 | {hibari_server_service, gdss}. 86 | %{hibari_server_service, gdss_stub}. 87 | 88 | %{hibari_client_type, ubf}. 89 | %{hibari_server_tcp_port, 7581}. 90 | %{hibari_server_service, gdss}. 91 | %{hibari_server_service, gdss_stub}. 92 | 93 | %% TODO: Hibari's JSF support is broken right now, but I'm not sure? 94 | %{hibari_client_type, jsf}. 95 | %{hibari_server_tcp_port, 7582}. 96 | %{hibari_server_service, gdss}. 97 | %{hibari_server_service, gdss_stub}. 98 | 99 | %{hibari_client_type, tbf}. 100 | %{hibari_server_tcp_port, 7599}. 101 | %{hibari_server_service, gdss}. 102 | %{hibari_server_service, gdss_stub}. 103 | 104 | %% TODO: SLF: Untested! Try testing against bb2e? 105 | %{hibari_client_type, json_rpc}. 106 | %{hibari_server_tcp_port, 22982377582}. 107 | %{hibari_server_service, gdss}. 108 | %{hibari_server_service, gdss_stub}. 109 | 110 | %% hibari_servers 111 | %% 112 | %% For use with all Hibari clients other than the native Erlang 113 | %% client. (This attribute is ignored by the native Erlang client.) 114 | %% 115 | %% Each concurrent load generator will use one server from this list. 116 | %% The assignment is made at plugin initialization time and will not 117 | %% change for the life of the load generator process. 118 | %% 119 | %% This list should include all Hibari servers in the cluster. The 120 | %% list may contain valid DNS hostnames and/or IP addresses, both as 121 | %% Erlang strings. (Don't forget commas between each machine, and 122 | %% don't put a comma after the last item in the list.) 123 | 124 | {hibari_servers, [ 125 | "localhost" 126 | ]}. 127 | 128 | %% hibari_native_1node 129 | %% 130 | %% For the Erlang native client, we need the name of a single Erlang 131 | %% node in the Hibari cluster. After we connect to that node, we'll 132 | %% automatically become aware of all other nodes in the cluster. 133 | 134 | {hibari_native_1node, 'gdss1@localhost'}. 135 | 136 | %% hibari_native_my_sname 137 | %% 138 | %% For the Erlang native client, this is the name of the basho_bench 139 | %% node. Before running the test, it is recommended to register this 140 | %% native Erlang client's nodename for monitoring by the Hibari admin 141 | %% server. Please click on the "Add/Delete a client node monitor." 142 | %% link of the Hibari admin server's webpage for further information. 143 | 144 | {hibari_native_my_sname, 'basho_bench'}. 145 | 146 | %% hibari_native_ticktime 147 | %% 148 | %% For the Erlang native client, this value must match the value of 149 | %% 'cluster_timeout' in Hibari's "etc/central.conf" file. The default 150 | %% is 20. 151 | 152 | {hibari_native_ticktime, 20}. 153 | 154 | %% hibari_native_cookie 155 | %% 156 | %% For the Erlang native client, this value specifies the "cookie" 157 | %% used by the Hibari server cluster. See ~hibariuser/.erlang.cookie 158 | %% on one of the Hibari server nodes. The cookie must be an atom, so 159 | %% be sure to use single quotes. 160 | 161 | {hibari_native_cookie, 'SKHZSZEOIVIYDXBZQHOB'}. 162 | -------------------------------------------------------------------------------- /examples/http.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 1}. 4 | 5 | {concurrent, 1}. 6 | 7 | {driver, basho_bench_driver_http}. 8 | 9 | %% Default generators, reference by the atoms key_generator and value_generator 10 | {key_generator, {int_to_str, {partitioned_sequential_int, 50000}}}. 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | %%% Generators: {Name, KeyGen | ValGen} 14 | % Name: atom() 15 | % KeyGen: User or Basho Bench defined key generator 16 | % ValGen: User or Basho Bench defined value generator 17 | {generators, [ 18 | {string_g, {key_generator, {int_to_str, {uniform_int, 50000}}}}, 19 | {binstring_g, {value_generator, {fixed_bin, 100}}} 20 | ]}. 21 | 22 | %%% Values: {Name, Value} 23 | %%% {Name, {FormattedValue, Generators}} 24 | % Name: atom() 25 | % Value: string() | atom() - named generator, can be key_generator or value_generator for default 26 | % FormattedValue: string() - formatted with io_lib:format 27 | % Generators: list() - list of generators, can be key_generator or value_generator for default 28 | {values, [ 29 | {json_v, {"{\"this\":\"is_json_~s\"}", [string_g]}}, 30 | {xml_v, {"~s", [binstring_g]}}, 31 | {plainstring_v, "hello"}, 32 | {smallbin_v, binstring_g}, 33 | {largebin_v, value_generator} 34 | ]}. 35 | 36 | %%% Headers: {Name, Headers} 37 | % Name: atom() 38 | % Headers: proplist() 39 | {headers, [ 40 | {json_h, [{'Content-Type', 'application/json'}, {'Accept', 'application/json'}]}, 41 | {xml_h, [{'Content-Type', 'application/xml'}]}, 42 | {binary_h, [{'Content-Type', 'application/octet-stream'}]}, 43 | {empty_h, []} 44 | ]}. 45 | 46 | %%% Targets: {Name, {Host, Port, Path}} 47 | %%% {Name, [{Host1, Port1, Path1},{Host2, Port2, Path2},...]} 48 | %%% {Name, {Host, Port, {FormattedPath, Generators}}} 49 | %%% {Name, [{Host1, Port1, {FormattedPath1, Generators1}},{Host2, Port2, {FormattedPath2, Generators2}},...]} 50 | % Name: atom() 51 | % Host: string() 52 | % Port: integer() 53 | % Path: string() 54 | % FormattedPath: string() - formatted with io_lib:format 55 | % Generators: list() - list of generators, can be key_generator or value_generator for default 56 | {targets, [ 57 | {base_uri_t, {"localhost", 4567, "/"}}, 58 | {multi_base_uri_t, [{"localhost", 4567, "/"},{"localhost", 4568, "/"}]}, 59 | {with_key_t, {"localhost", 4567, {"/~s", [key_generator]}}}, 60 | {multi_with_key_t, [{"localhost", 4567, {"/~s", [key_generator]}},{"localhost", 4568, {"/~s", [key_generator]}}]}, 61 | {with_another_key_t, {"localhost", 4567, {"/another/~s", [string_g]}}}, 62 | {smallbin_t, {"localhost", 4567, {"/smallbin/~s", [key_generator]}}}, 63 | {upload_t, {"localhost", 4567, {"/upload/~s", [key_generator]}}} 64 | ]}. 65 | 66 | %%% Operations: {{get|delete, Target}, Weight} 67 | %%% {{get|delete, Target, Header}, Weight} 68 | %%% {{put|post, Target, Value}, Weight} 69 | %%% {{put|post, Target, Value, Header}, Weight} 70 | % Target: atom() - defined target 71 | % Header: atom() - defined header 72 | % Value: atom() - defined value 73 | % Weight: integer() - ratio of this operation to the rest (ThisWeight / TotalWeightSum = % of this Operation) 74 | 75 | {operations, [ 76 | %% Get without a key 77 | {{get, base_uri_t}, 1}, 78 | %% Get without a key on multiple targets 79 | {{get, multi_base_uri_t}, 1}, 80 | %% Get with a key and headers 81 | {{get, with_key_t, json_h}, 1}, 82 | %% Get with a key and headers on multiple targets 83 | {{get, multi_with_key_t, json_h}, 1}, 84 | %% Put with a json object 85 | {{put, base_uri_t, json_v, json_h}, 1}, 86 | %% Post with an xml object and value 87 | {{post, with_key_t, xml_v, xml_h}, 1}, 88 | %% Alternate keygen with plaintext 89 | {{post, with_another_key_t, plainstring_v, empth_h}, 1}, 90 | %% Binary value 91 | {{post, smallbin_t, smallbin_v, binary_h}, 1}, 92 | %% Large binary value using default value gen 93 | {{post, upload_t, largebin_v, binary_h}, 1}, 94 | %% Delete with a key 95 | {{delete, with_key_t}, 1} 96 | ]}. 97 | -------------------------------------------------------------------------------- /examples/httpraw.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 1}. 4 | 5 | {concurrent, 3}. 6 | 7 | {driver, basho_bench_driver_http_raw}. 8 | 9 | %% Example custom headers. Beware using headers that may cause collisions 10 | %% with automatically generated headers used by other parts of the driver. 11 | %% {http_raw_append_headers, [{"Authorization", "Basic dXNlcm5hbWU6cGFzc3dvcmQ="}]}. 12 | 13 | %% Example syntax (mykeygen_seq is not defined) 14 | %% {key_generator, {function, test, mykeygen_seq, [10000, 10, 10, 100]}}. 15 | 16 | {value_generator, {fixed_bin, 10000}}. 17 | 18 | %% Example syntax (mysearchgen is not defined) 19 | %% {http_search_generator, {function, test, mysearchgen, []}}. 20 | 21 | {http_raw_port, 8098}. 22 | 23 | {operations, [{update, 1}]}. 24 | 25 | {source_dir, "foo"}. 26 | -------------------------------------------------------------------------------- /examples/innostore_test.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | 5 | {concurrent, 1}. 6 | 7 | {driver, basho_bench_driver_innostore}. 8 | 9 | 10 | %% the second element in the list below (e.g., "../innostore") must point to 11 | %% the relevant directory of an innostore installation 12 | {code_paths, ["../innostore"]}. 13 | 14 | {key_generator, {int_to_bin_bigendian, {uniform_int, 500000}}}. 15 | 16 | {value_generator, {fixed_bin, 10000}}. 17 | 18 | {innostore_config, [ 19 | {data_home_dir, "/tmp/innodb"}, 20 | {log_group_home_dir, "/tmp/innodb"}, 21 | {buffer_pool_size, 1073741824}, %% 1G of Buffer 22 | {log_files_in_group, 4}, 23 | {log_file_size, 134217728} %% 128 MB log files 24 | ]}. 25 | 26 | {operations, [{put, 1}]}. 27 | -------------------------------------------------------------------------------- /examples/kv_backend.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 1}. 4 | {report_interval, 1}. 5 | 6 | {concurrent, 16}. 7 | 8 | {driver, basho_bench_driver_kv_backend}. 9 | {code_paths, [ 10 | "/Users/fritchie/b/src/riak_kv/ebin", 11 | "/Users/fritchie/b/src/riak_core/ebin" 12 | ]}. 13 | 14 | {key_generator, {int_to_bin_bigendian, {uniform_int, 5000}}}. 15 | {disable_sequential_int_progress_report, true}. 16 | {value_generator, {fixed_bin, 102480}}. 17 | 18 | %{be_disable_uses_r_object, true}. 19 | {be_backend_mod, riak_kv_yessir_backend}. 20 | {be_config, [ 21 | {yessir_return_same_r_obj, true}, % fastest & dumbest method 22 | {yessir_default_size, 102480} % coordinate with value_generator! 23 | ]}. 24 | 25 | %{be_backend_mod, riak_kv_memory_backend}. 26 | %{be_config, [ ]}. 27 | 28 | %{operations, [{get, 10}]}. 29 | {operations, [{get, 10}, {put, 10}]}. 30 | %{operations, [{put, 10}]}. 31 | -------------------------------------------------------------------------------- /examples/null_err_test.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 1}. 4 | {report_interval, 1}. 5 | 6 | {concurrent, 8}. 7 | 8 | {driver, basho_bench_driver_null}. 9 | 10 | {key_generator, {partitioned_sequential_int, 5000000}}. 11 | {disable_sequential_int_progress_report, true}. 12 | {value_generator, {fixed_bin, 10248}}. 13 | 14 | %% Our ops: 70% of 'absolutely_nothing' 15 | %% 10% of 'an_error' 16 | %% 20% of 'do_something_else' 17 | {operations, [{do_something, 7}, {an_error, 1}, {another_error, 2}]}. 18 | -------------------------------------------------------------------------------- /examples/null_test.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 5}. 4 | {report_interval, 1}. 5 | 6 | {concurrent, 8}. 7 | 8 | {driver, basho_bench_driver_null}. 9 | 10 | %% Simple key generator: generate a sequential integer (that is unique 11 | %% across concurrent worker processes), then convert it to a binary blob 12 | %% of 32 bits, big endian-style. This will create binary keys that are in 13 | %% lexigraphic sorting order. 14 | %{key_generator, {int_to_bin_bigendian, {partitioned_sequential_int, 5000000}}}. 15 | 16 | %% More complex key generator: 17 | %% * Generate a randon number between 1 and 40000000 (40 million) 18 | %% * Convert it to a binary blob of 32 bits, big endian-style 19 | %% * Prepend <<"seed1">> 20 | %% * Hash the result with MD5, resulting in a 16 byte binary. 21 | {key_generator, {{crypto_hash, md5}, {concat_binary, <<"seed1">>, {int_to_bin_bigendian, {partitioned_sequential_int, 40000000}}}}}. 22 | 23 | {disable_sequential_int_progress_report, true}. 24 | {value_generator, {fixed_bin, 10248}}. 25 | 26 | %% Our ops: 75% of 'absolutely_nothing' 27 | %% 15% of 'do_something' 28 | %% 10% of 'do_something_else' 29 | {operations, [{absolutely_nothing, 15}, 30 | {do_something, 3}, 31 | {do_something_else, 2}]}. 32 | -------------------------------------------------------------------------------- /examples/riakc_java.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 1}. 4 | 5 | {concurrent, 3}. 6 | 7 | {driver, basho_bench_driver_riakc_java}. 8 | 9 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 10 | 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | %% The list of remote Java client nodes you want to bench. 14 | %% Each entry is a tupple of the format 15 | %% {node(), inet:ip4_address(), inet:port_number()} 16 | %% Were host is the Jinterface node and 17 | %% ip and port form the address of the 18 | %% Riak interface that Java client should call 19 | 20 | {riakc_java_nodes, [{'java@127.0.0.1', {127,0,0,1}, 8087}]}. 21 | 22 | %% The transport you want the java client to use 23 | %% ether pb (for protocol buffers) or http. 24 | 25 | {riakc_java_transport, pb}. 26 | 27 | %% The size for the protocol buffers client 28 | %% socket buffers, in kb. 29 | 30 | {riakc_java_pbc_buffer, 16}. 31 | 32 | {riakc_java_replies, 1}. 33 | 34 | {operations, [{get, 1}, {update, 1}]}. 35 | 36 | -------------------------------------------------------------------------------- /examples/riakc_mr.config: -------------------------------------------------------------------------------- 1 | % -*- mode: erlang -*- 2 | {driver, basho_bench_driver_riakc_pb}. 3 | 4 | {riakc_pb_ips, [{127,0,0,1}]}. 5 | 6 | {riakc_pb_replies, 1}. 7 | 8 | {riakc_pb_bucket, <<"bryanitbs">>}. 9 | 10 | %% load 11 | 12 | %% {mode, max}. 13 | %% {duration, 10000}. 14 | %% {concurrent, 1}. 15 | %% {operations, [{put, 1}]}. 16 | %% {key_generator, {int_to_str, {partitioned_sequential_int, 10000}}}. 17 | %% {value_generator, 18 | %% {function, basho_bench_driver_riakc_pb, mapred_ordered_valgen, []}}. 19 | 20 | %% test 21 | 22 | %% for computing expected bucket sum 23 | {riakc_pb_preloaded_keys, 10000}. 24 | 25 | {mode, max}. 26 | {duration, 1}. 27 | {concurrent, 1}. 28 | {operations, [{mr_bucket_js, 1}]}. 29 | {key_generator, {int_to_str, {uniform_int, 9999}}}. 30 | {value_generator, {fixed_bin, 1}}. 31 | {riakc_pb_keylist_length, 1000}. 32 | -------------------------------------------------------------------------------- /examples/riakc_pb+concat_binary.config: -------------------------------------------------------------------------------- 1 | %% 1st phase: Pre-populate keys so that get operations will fetch something 2 | %% Use partitioned_sequential_int key gen to guarantee entire 3 | %% key space is pre-populated. 4 | %% 2nd phase: Use actual model test workload, using desired 'duration' time 5 | %% and key generator. 6 | 7 | {mode, max}. 8 | {duration, 9999}. % 1st phase: will stop when all key generators are done 9 | %{duration, 10}. % 2nd phase: run for this many minutes 10 | 11 | {concurrent, 1}. % Change for best fit for each phase 12 | 13 | {driver, basho_bench_driver_riakc_pb}. 14 | {test_dir, "./tests"}. % default output dir 15 | 16 | {riakc_pb_ips, [ 17 | %% If more than one, separate each 2-tuple with a comma! 18 | {"localhost", 8087} 19 | ]}. 20 | 21 | {riakc_pb_bucket, <<"test-demo-bucket2">>}. 22 | %% Note: Using only 99 keys is silly, don't do this for real tests. 23 | {key_generator, 24 | {concat_binary, 25 | {base64, 26 | {int_to_bin_bigendian, 27 | {partitioned_sequential_int, 99} 28 | } 29 | }, 30 | <<"Filler bytes go here.... -------------------------------------------">> 31 | } 32 | }. % 1st phase 33 | %{key_generator, {int_to_bin_bigendian, {pareto_int, 99}}}. % 2nd phase 34 | {value_generator, {fixed_bin, 10000}}. 35 | 36 | {riakc_pb_replies, 1}. % 1st phase 37 | %{riakc_pb_replies, quorum}. % 2nd phase 38 | 39 | {operations, [{put, 1}]}. % 1st phase 40 | %{operations, [{get, 9}, {put, 1}]}. % 2nd phase 41 | -------------------------------------------------------------------------------- /examples/riakc_pb.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | {report_interval,1}. 5 | 6 | {concurrent, 10}. 7 | 8 | {driver, basho_bench_driver_riakc_pb}. 9 | 10 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 11 | 12 | {value_generator, {fixed_bin, 10000}}. 13 | 14 | {riakc_pb_ips, [{127,0,0,1}]}. 15 | 16 | {riakc_pb_replies, 1}. 17 | 18 | %%% {operations, [{get, 1}]}. 19 | {operations, [{get, 1}, {update, 1}]}. 20 | 21 | %% Use {auto_reconnect, false} to get "old" behavior (prior to April 2013). 22 | %% See deps/riakc/src/riakc_pb_socket.erl for all valid socket options. 23 | {pb_connect_options, [{auto_reconnect, true}]}. 24 | 25 | %% Overrides for the PB client's default 60 second timeout, on a 26 | %% per-type-of-operation basis. All timeout units are specified in 27 | %% milliseconds. The pb_timeout_general config item provides a 28 | %% default timeout if the read/write/listkeys/mapreduce timeout is not 29 | %% specified. 30 | 31 | {pb_timeout_general, 30000}. 32 | {pb_timeout_read, 5000}. 33 | {pb_timeout_write, 5000}. 34 | {pb_timeout_listkeys, 50000}. 35 | %% The general timeout will be used because this specific item is commented: 36 | %% {pb_timeout_mapreduce, 50000}. 37 | -------------------------------------------------------------------------------- /examples/riakc_pb.devrel.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | 5 | {concurrent, 3}. 6 | 7 | {driver, basho_bench_driver_riakc_pb}. 8 | 9 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 10 | 11 | {value_generator, {fixed_bin, 10000}}. 12 | 13 | {riakc_pb_ips, [ 14 | {{127,0,0,1}, 10017}, %% {Ip, Port} 15 | {{127,0,0,1}, 10027}, %% {Ip, Port} 16 | {{127,0,0,1}, [10037, 10047]} %% {Ip, Ports} 17 | ]}. 18 | 19 | {riakc_pb_replies, 1}. 20 | 21 | {operations, [{get, 1}, {update, 1}]}. 22 | 23 | -------------------------------------------------------------------------------- /examples/riakc_pb.search.devrel.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | 5 | {concurrent, 3}. 6 | 7 | {driver, basho_bench_driver_riakc_pb}. 8 | 9 | %%{key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 10 | %%{value_generator, {fixed_bin, 10000}}. 11 | 12 | {riakc_pb_ips, [ 13 | {{127,0,0,1}, 10017}, %% {Ip, Port} 14 | {{127,0,0,1}, 10027}, %% {Ip, Port} 15 | {{127,0,0,1}, [10037, 10047]} %% {Ip, Ports} 16 | ]}. 17 | 18 | {riakc_pb_search_queries, [{<<"index">>, "query", [{rows,10}]}]}. %% last element of the tuple is a list of Search options/params. 19 | 20 | {operations, [{search, 1}]}. 21 | 22 | %% {query_step_interval, 60}. %% time in seconds to run each query before switching to the next one in the list, default is 60 seconds. 23 | %% {operations, [{search_interval, 1}]}. 24 | 25 | -------------------------------------------------------------------------------- /examples/riakc_pb_distributed.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 10}. 4 | {report_interval,1}. 5 | 6 | {concurrent, 50}. 7 | 8 | {driver, basho_bench_driver_riakc_pb}. 9 | 10 | {key_generator, {int_to_bin_bigendian, {uniform_int, 10000}}}. 11 | 12 | {value_generator, {fixed_bin, 10000}}. 13 | 14 | {riakc_pb_ips, [{127,0,0,1}]}. 15 | 16 | {riakc_pb_replies, 1}. 17 | 18 | %%% {operations, [{get, 1}]}. 19 | {operations, [{get, 1}, {update, 1}]}. 20 | 21 | %% Use {auto_reconnect, false} to get "old" behavior (prior to April 2013). 22 | %% See deps/riakc/src/riakc_pb_socket.erl for all valid socket options. 23 | {pb_connect_options, [{auto_reconnect, true}]}. 24 | 25 | %% Overrides for the PB client's default 60 second timeout, on a 26 | %% per-type-of-operation basis. All timeout units are specified in 27 | %% milliseconds. The pb_timeout_general config item provides a 28 | %% default timeout if the read/write/listkeys/mapreduce timeout is not 29 | %% specified. 30 | 31 | {pb_timeout_general, 30000}. 32 | {pb_timeout_read, 5000}. 33 | {pb_timeout_write, 5000}. 34 | {pb_timeout_listkeys, 50000}. 35 | %% The general timeout will be used because this specific item is commented: 36 | %% {pb_timeout_mapreduce, 50000}. 37 | 38 | 39 | %% Remote_nodes must be in the format of [{fqdn, nodename}] 40 | %% basho_bench / distributed Erlang use longnames 41 | {remote_nodes, [{'3c075477e55e-2.local', 'bb25'}]}. 42 | {distribute_work, true}. 43 | -------------------------------------------------------------------------------- /examples/riakc_pb_text.config: -------------------------------------------------------------------------------- 1 | %% This configuration can be used to generate text data that can be indexed by Riak Search and/or Yokozuna 2 | {mode, max}. 3 | 4 | {duration, 1}. 5 | 6 | {concurrent, 3}. 7 | 8 | {driver, basho_bench_driver_riakc_pb}. 9 | 10 | {key_generator, {int_to_str, {uniform_int, 1000}}}. 11 | 12 | {value_generator, {fixed_bin, 1000}}. 13 | 14 | {riakc_pb_content_type, "text/plain"}. 15 | 16 | %% This parameter specifies the file that binary values will be extracted from. As 17 | %% the example file contains only text this will be indexable and match the content type. 18 | %% Note that the path will need to be adjusted to fit the environment. 19 | %% This example text file was downloaded from http://www.textfiles.com/etext/FICTION/ 20 | {value_generator_blob_file, "/AroundTheWorldIn80Days.txt"}. 21 | 22 | {riakc_pb_ips, [{127,0,0,1}]}. 23 | 24 | %% Use default quorom settings 25 | %%{riakc_pb_replies, 1}. 26 | 27 | {operations, [{put, 1},{get, 1},{update, 1}]}. 28 | 29 | %% Use {auto_reconnect, false} to get "old" behavior (prior to April 2013). 30 | %% See deps/riakc/src/riakc_pb_socket.erl for all valid socket options. 31 | {pb_connect_options, [{auto_reconnect, true}]}. 32 | 33 | %% Overrides for the PB client's default 60 second timeout, on a 34 | %% per-type-of-operation basis. All timeout units are specified in 35 | %% milliseconds. The pb_timeout_general config item provides a 36 | %% default timeout if the read/write/listkeys/mapreduce timeout is not 37 | %% specified. 38 | 39 | {pb_timeout_general, 30000}. 40 | {pb_timeout_read, 5000}. 41 | {pb_timeout_write, 5000}. 42 | {pb_timeout_listkeys, 50000}. 43 | %% The general timeout will be used because this specific item is commented: 44 | %% {pb_timeout_mapreduce, 50000}. 45 | -------------------------------------------------------------------------------- /examples/riakclient.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | 3 | {duration, 15}. 4 | 5 | {concurrent, 5}. 6 | 7 | {driver, basho_bench_driver_riakclient}. 8 | 9 | {code_paths, ["/Users/jmeredith/basho/riak/apps/riak_kv", 10 | "/Users/jmeredith/basho/riak/apps/riak_core"]}. 11 | 12 | {key_generator, {int_to_bin_bigendian, {uniform_int, 35000}}}. 13 | 14 | {value_generator, {fixed_bin, 10000}}. 15 | 16 | {riakclient_nodes, ['riak@127.0.0.1']}. 17 | 18 | {riakclient_mynode, ['riak_bench@127.0.0.1', longnames]}. 19 | 20 | {riakclient_replies, 1}. 21 | -------------------------------------------------------------------------------- /examples/shortcut.config: -------------------------------------------------------------------------------- 1 | {mode, max}. 2 | {duration, infinity}. 3 | {concurrent, 8}. 4 | {driver, basho_bench_driver_shortcut}. 5 | {key_generator, {int_to_bin_bigendian,{partitioned_sequential_int, 50000}}}. 6 | 7 | {value_generator, {fixed_bin, 100}}. 8 | 9 | {operations, [{put, 1}]}. 10 | 11 | %% The second element in the list below (e.g., "../../public/bitcask") 12 | %% must point to the relevant directory of a bitcask installation. 13 | %% We must also have a correct path to the riak_core app. 14 | {code_paths, [%% "../../public/bitcask", 15 | "/Users/fritchie/b/src/riak_core", 16 | "/Users/fritchie/b/src/riak_kv", 17 | "/Users/fritchie/b/src/riak/deps/sext", 18 | "/Users/fritchie/b/src/eleveldb", 19 | "/Users/fritchie/b/src/hanoidb", 20 | "/Users/fritchie/b/src/hanoidb/deps/plain_fsm", 21 | "/Users/fritchie/b/src/hanoidb/deps/ebloom", 22 | "/Users/fritchie/b/src/riak/deps/bitcask"]}. 23 | 24 | %% Mandatory shortcut driver configuration items 25 | 26 | %% Supported drivers: eleveldb, bitcask, hanoidb 27 | %{shortcut_backend, eleveldb}. 28 | %{shortcut_backend, bitcask}. 29 | {shortcut_backend, hanoidb}. 30 | 31 | %% Flags for opening backend instances 32 | %{shortcut_backend_flags, [{compression, false}]}. % eleveldb 33 | %{shortcut_backend_flags, []}. % bitcask 34 | {shortcut_backend_flags, [{compress, none}, {merge_strategy, fast}]}. % hanoidb 35 | 36 | %% Path to the data dir ... for the adventurous, make this path the 37 | %% same as your Riak data dir. 38 | %{shortcut_data_dir, "/Users/fritchie/b/src/riak/rel/riak/data/leveldb"}. 39 | %{shortcut_data_dir, "/Users/fritchie/b/src/riak/rel/riak/data/bitcask"}. 40 | {shortcut_data_dir, "/Users/fritchie/b/src/riak.hanoidb/rel/riak/data/hanoidb"}. 41 | 42 | %% Use the same ring size as Riak's riak_core app's ring_creation_size. 43 | {shortcut_ring_creation_size, 64}. 44 | 45 | %% Typical n_val = 3 46 | {shortcut_n_val, 3}. 47 | 48 | %% Name of the Riak KV bucket that this driver will be storing keys for. 49 | %% Must match driver-specific config options used in later basho_bench runs! 50 | {shortcut_bucket, <<"b1">>}. 51 | 52 | %% If you're not interested in using the output of the shortcut driver 53 | %% to pre-populate Riak KV application backend data stores, then set 54 | %% this value to false. When false, the values stored will be exact 55 | %% as generated by the basho_bench value generator. 56 | {shortcut_store_riak_object, true}. % If false, store generated value as-is. 57 | -------------------------------------------------------------------------------- /examples/teams-crdt-map.config: -------------------------------------------------------------------------------- 1 | {mode,{rate,max}}. 2 | {duration,10}. 3 | {concurrent,150}. 4 | {rng_seed,now}. 5 | 6 | %% This bucket type must be created and set to be datatype, maps. 7 | {riakc_pb_bucket,{<<"maps">>,<<"testbucket">>}}. 8 | 9 | {key_generator, {uniform_int, 100}}. 10 | {value_generator, {uniform_int, 1000}}. 11 | 12 | {operations,[{{game,completed},10}, 13 | {{team,player,addition},3}, 14 | {{team,player,removal},3}, 15 | {{team,read},100}, 16 | {{team,write},1}]}. 17 | 18 | {riakc_pb_ips,[{"riak101.aws",10017}, 19 | {"riak102.aws",10017}, 20 | {"riak103.aws",10017}, 21 | {"riak104.aws",10017}, 22 | {"riak105.aws",10017}]}. 23 | 24 | {riakc_pb_replies,default}. 25 | 26 | {driver,basho_bench_driver_riakc_pb}. 27 | -------------------------------------------------------------------------------- /include/basho_bench.hrl: -------------------------------------------------------------------------------- 1 | 2 | -define(FAIL_MSG(Str, Args), ?ERROR(Str, Args), basho_bench_app:stop_or_kill()). 3 | -define(STD_ERR(Str, Args), io:format(standard_error, Str, Args)). 4 | 5 | -define(CONSOLE(Str, Args), lager:info(Str, Args)). 6 | 7 | -define(DEBUG(Str, Args), lager:debug(Str, Args)). 8 | -define(INFO(Str, Args), lager:info(Str, Args)). 9 | -define(WARN(Str, Args), lager:warning(Str, Args)). 10 | -define(ERROR(Str, Args), lager:error(Str, Args)). 11 | 12 | -define(FMT(Str, Args), lists:flatten(io_lib:format(Str, Args))). 13 | 14 | -define(VAL_GEN_BLOB_CFG, value_generator_blob_file). 15 | -define(VAL_GEN_SRC_SIZE, value_generator_source_size). 16 | -------------------------------------------------------------------------------- /pkg.vars.config: -------------------------------------------------------------------------------- 1 | %% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ts=4 sw=4 et 3 | 4 | %% 5 | %% Packaging 6 | %% 7 | {package_name, "basho-bench"}. 8 | {package_install_name, "basho_bench"}. 9 | {package_install_user, "basho-bench"}. 10 | {package_install_group, "basho-bench"}. 11 | {package_install_user_desc, "Basho-bench user"}. 12 | {package_shortdesc, "Basho benchmarking tool"}. 13 | {package_desc, "Benchmarking tool"}. 14 | {package_commands, {list, [[{name, "basho_bench"}]]}}. 15 | {package_patch_dir, "basho-patches"}. 16 | {bin_or_sbin, "bin"}. 17 | {license_type, "OSS"}. 18 | {copyright, "2014 Basho Technologies, Inc"}. 19 | {vendor_name, "Basho Technologies, Inc"}. 20 | {vendor_url, "http://basho.com"}. 21 | {vendor_contact_name, "Basho Package Maintainer"}. 22 | {vendor_contact_email, "packaging@basho.com"}. 23 | {license_full_text, "This software is provided under license from Basho Technologies."}. 24 | {solaris_pkgname, "BASHObasho-bench"}. 25 | -------------------------------------------------------------------------------- /priv/common.r: -------------------------------------------------------------------------------- 1 | # Load all the necessary packages, installing missing ones when necessary 2 | packages.to.install <- c("plyr", "grid", "getopt", "proto", "ggplot2") 3 | 4 | for(p in packages.to.install) 5 | { 6 | print(p) 7 | if (suppressWarnings(!require(p, character.only = TRUE))) { 8 | install.packages(p, repos = "http://lib.stat.cmu.edu/R/CRAN") 9 | library(p, character.only=TRUE) 10 | } 11 | } 12 | 13 | # Load a latency file and ensure that it is appropriately tagged 14 | load_latency_frame <- function(File) 15 | { 16 | op <- gsub("_latencies.csv", "", basename(File)) 17 | frame <- read.csv(File) 18 | frame$op = rep(op, nrow(frame)) 19 | return (frame) 20 | } 21 | 22 | # Load summary and latency information for a given directory 23 | load_benchmark <- function(Dir, Tstart, Tend) 24 | { 25 | ## Load up summary data 26 | summary <- read.csv(sprintf("%s/%s", Dir, "summary.csv"), 27 | colClasses=rep("numeric", 5)) 28 | 29 | ## Get a list of latency files 30 | latencies <- lapply(list.files(path = Dir, pattern = "_latencies.csv", 31 | full.names = TRUE), 32 | load_latency_frame) 33 | latencies <- do.call('rbind', latencies) 34 | 35 | ## Convert timing information in latencies from usecs -> msecs 36 | latencies[4:10] <- latencies[4:10] / 1000 37 | 38 | ## Trim values off that are outside our range of times 39 | if (is.null(Tstart)) { Tstart = 0 } 40 | if (is.null(Tend)) { Tend = max(summary$elapsed) } 41 | 42 | print(Tstart) 43 | print(Tend) 44 | 45 | return (list(summary = summary[summary$elapsed >= Tstart & summary$elapsed <= Tend,], 46 | latencies = latencies[latencies$elapsed >= Tstart & latencies$elapsed <= Tend,])) 47 | } 48 | 49 | -------------------------------------------------------------------------------- /priv/compare.r: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env Rscript 2 | 3 | # Parse the --file= argument out of command line args and 4 | # determine where base directory is so that we can source 5 | # our common sub-routines 6 | arg0 <- sub("--file=(.*)", "\\1", grep("--file=", commandArgs(), value = TRUE)) 7 | dir0 <- dirname(arg0) 8 | source(file.path(dir0, "common.r")) 9 | 10 | # Setup parameters for the script 11 | params = matrix(c( 12 | 'width', 'w', 2, "integer", 13 | 'height', 'h', 2, "integer", 14 | 'outfile', 'o', 2, "character", 15 | 'dir1', 'i', 1, "character", 16 | 'tag1', 'j', 1, "character", 17 | 'dir2', 'k', 1, "character", 18 | 'tag2', 'l', 1, "character" 19 | ), ncol=4, byrow=TRUE) 20 | 21 | # Parse the parameters 22 | opt = getopt(params) 23 | 24 | # Initialize defaults for opt 25 | if (is.null(opt$width)) { opt$width = 1440 } 26 | if (is.null(opt$height)) { opt$height = 900 } 27 | if (is.null(opt$outfile)) { opt$outfile = "compare.png" } 28 | 29 | # Load the benchmark data for each directory 30 | b1 = load_benchmark(opt$dir1, NULL, NULL) 31 | b2 = load_benchmark(opt$dir2, NULL, NULL) 32 | 33 | # If there is no actual data available, bail 34 | if (nrow(b1$latencies) == 0) 35 | { 36 | stop("No latency information available to analyze in ", opt$indir) 37 | } 38 | 39 | if (nrow(b2$latencies) == 0) 40 | { 41 | stop("No latency information available to analyze in ", opt$indir) 42 | } 43 | 44 | png(file = opt$outfile, width = opt$width, height = opt$height) 45 | 46 | # Tag the summary frames for each benchmark so that we can distinguish 47 | # between them in the legend. 48 | b1$summary$tag <- opt$tag1 49 | b2$summary$tag <- opt$tag2 50 | 51 | # Compare the req/sec between the two datasets 52 | plot1 <- qplot(elapsed, total / window, 53 | data = b1$summary, 54 | color = tag, 55 | geom = "smooth", 56 | xlab = "Elapsed Secs", 57 | ylab = "Req/sec", 58 | main = "Throughput") + geom_smooth(data = b2$summary) 59 | 60 | # Calculate the % difference in throughput 61 | baseline <- b1$summary$total / b1$summary$window 62 | delta <- (b2$summary$total / b2$summary$window) / baseline 63 | plot2 <- qplot(elapsed, delta, 64 | data = b1$summary, 65 | geom="smooth", 66 | xlab = "Elapsed Secs", 67 | ylab = "% of Baseline", 68 | main = "Throughput %") 69 | 70 | # Tag the latencies frames for each benchmark 71 | b1$latencies$tag <- opt$tag1 72 | b2$latencies$tag <- opt$tag2 73 | 74 | plot3 <- qplot(elapsed, X95th, 75 | color = tag, 76 | geom = "smooth", 77 | data = b1$latencies, 78 | xlab = "Elapsed Secs", 79 | ylab = "95th latency", 80 | main = "Latency") + 81 | facet_grid(. ~ op) + 82 | geom_smooth(data = b2$latencies) 83 | 84 | plot4 <- qplot(elapsed, b2$latencies$X95th / b1$latencies$X95th, 85 | color = tag, 86 | geom = "smooth", 87 | data = b1$latencies, 88 | xlab = "Elapsed Secs", 89 | ylab = "% of Baseline", 90 | main = "95th Latency %") + 91 | facet_grid(. ~ op) 92 | 93 | 94 | grid.newpage() 95 | 96 | pushViewport(viewport(layout = grid.layout(4, 1))) 97 | 98 | vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y) 99 | 100 | print(plot1, vp = vplayout(1,1)) 101 | print(plot2, vp = vplayout(2,1)) 102 | print(plot3, vp = vplayout(3,1)) 103 | print(plot4, vp = vplayout(4,1)) 104 | dev.off() 105 | 106 | -------------------------------------------------------------------------------- /priv/gp_latencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function Usage { 4 | echo "Usage: gp_latencies.sh [-d TEST_DIR] [-o OPERATIONS] [-k STATS_KINDS]" >&2 5 | echo " [-t TERMINAL_TYPE] [-s PLOT_STYLE] [-p PRE_COMMAD]" >&2 6 | echo " [-P] [-E EXEC_COMMAND] [-h]" >&2 7 | echo "" >&2 8 | echo " -d TEST_DIR: comma separated test directories with *-latencies.csv" >&2 9 | echo " default: \"tests/current\"" >&2 10 | echo " -o OPERATIONS: operation prefixes of *-latencies.csv" >&2 11 | echo " in comma separated list" >&2 12 | echo " default: all operations under TEST_DIR" >&2 13 | echo " -k STATS_KINDS: statistics kinds in comma separated list" >&2 14 | echo " default: \"99th,mean\"" >&2 15 | echo " -t TERMINAL_TYPE: terminal type of gnuplot (e.g. dumb, x11, aqua)" >&2 16 | echo " default: nothing" >&2 17 | echo " -s PLOT_STYLE: plot style for points and lines, etc" >&2 18 | echo " default: \"linespoints pointsize 2 linewidth 1\"" >&2 19 | echo " -p PRE_COMMAND: any command to be executed before plot" >&2 20 | echo " default: nothing" >&2 21 | echo " -E EXEC_COMMAND: command to be executed" >&2 22 | echo " default: \"gnuplot -persist\"" >&2 23 | echo " -P: print gnuplot script to stdout" >&2 24 | echo " -h: print this usage" >&2 25 | exit 1 26 | } 27 | 28 | TEST_DIR="tests/current" 29 | OPERATIONS= 30 | STATS_KINDS="99th,mean" 31 | TERMINAL_COMMAND= 32 | PLOT_STYLE="linespoints pointsize 2 linewidth 1" 33 | PRE_COMMAD= 34 | EXEC_COMMAND="gnuplot -persist" 35 | 36 | while getopts ":d:o:k:t:s:p:PE:h" opt; do 37 | case $opt in 38 | d) 39 | TEST_DIR=${OPTARG} ;; 40 | o) 41 | OPERATIONS=${OPTARG} ;; 42 | k) 43 | STATS_KINDS=${OPTARG} ;; 44 | t) 45 | TERMINAL_COMMAND="set terminal ${OPTARG}" ;; 46 | s) 47 | PLOT_STYLE=${OPTARG} ;; 48 | p) 49 | PRE_COMMAD=${OPTARG} ;; 50 | P) 51 | EXEC_COMMAND="cat" ;; 52 | E) 53 | EXEC_COMMAND=${OPTARG} ;; 54 | h) 55 | Usage ;; 56 | \?) 57 | echo "Invalid option: -${OPTARG}" >&2 58 | Usage ;; 59 | :) 60 | echo "Option -${OPTARG} requires an argument." >&2 61 | Usage ;; 62 | esac 63 | done 64 | 65 | function plot_command(){ 66 | echo "plot \\" 67 | for THIS_TEST_DIR in ${TEST_DIR//,/ } 68 | do 69 | if [ -z "${OPERATIONS}" ]; then 70 | for f in `ls ${THIS_TEST_DIR}/*_latencies.csv` 71 | do 72 | OPERATION=`basename $f _latencies.csv` 73 | plot_per_op ${OPERATION} 74 | done 75 | else 76 | for OPERATION in ${OPERATIONS//,/ } 77 | do 78 | plot_per_op ${OPERATION} 79 | done 80 | fi 81 | done 82 | echo " 1/0 notitle # dummy" 83 | } 84 | 85 | function plot_per_op(){ 86 | OPERATION=$1 87 | LATENCY_FILE="${THIS_TEST_DIR}/${OPERATION}_latencies.csv" 88 | for KIND in ${STATS_KINDS//,/ } 89 | do 90 | plot_per_op_kind ${OPERATION} ${LATENCY_FILE} ${KIND} 91 | done 92 | } 93 | 94 | function plot_per_op_kind() { 95 | OPERATION=$1 96 | FILE=$2 97 | KIND=$3 98 | DISPLAY_SCALE=1000 99 | case "${KIND}" in 100 | "min") COL_POS=4 ;; 101 | "mean") COL_POS=5 ;; 102 | "medean") COL_POS=6 ;; 103 | "95th") COL_POS=7 ;; 104 | "99th") COL_POS=8 ;; 105 | "99.9th") COL_POS=9 ;; 106 | "max") COL_POS=10 ;; 107 | "errors") 108 | # This column is count, not time duration. 109 | # Be Careful about / Don't get fooled by vertical axis label. 110 | # It may be useful to use options "-k errors" to dispaly 111 | # this column only and "-p" to set the label. 112 | COL_POS=11 113 | DISPLAY_SCALE=1 ;; 114 | *) Usage ;; 115 | esac 116 | echo " \"${FILE}\" using 1:(\$${COL_POS}/${DISPLAY_SCALE}) with \\" 117 | echo " ${PLOT_STYLE} \\" 118 | # If plotting only 1 directory, do not add its name 119 | if [ "${TEST_DIR}" == "${THIS_TEST_DIR}" ]; then 120 | echo " title \"${OPERATION}:${KIND}\" \\" 121 | else 122 | echo " title \"${THIS_TEST_DIR##*/} - ${OPERATION}:${KIND}\" \\" 123 | fi 124 | echo " ,\\" 125 | } 126 | 127 | PLOT_COMMAND=`plot_command` 128 | 129 | ${EXEC_COMMAND} << EOF 130 | 131 | ## Use terminal definition as you like (via -t option) 132 | # set terminal dumb # character terminal 133 | # set terminal dumb 79 49 enhanced # character terminal portrait 134 | # set terminal x11 # X-Window 135 | # set terminal x11 persist # X-Window, remain alive after gnuplot exits 136 | # set terminal aqua # AquaTerm 137 | ${TERMINAL_COMMAND} 138 | 139 | ## title, key and axis 140 | set title "Latency [msec]" 141 | set autoscale 142 | set yrange [0:] 143 | set grid 144 | set xlabel "Elapsed [sec]" 145 | set ylabel "Latency [msec]" 146 | set key inside bottom 147 | 148 | ## data file 149 | set datafile separator ',' 150 | 151 | ${PRE_COMMAD} 152 | 153 | ## plot 154 | ${PLOT_COMMAND} 155 | 156 | EOF 157 | -------------------------------------------------------------------------------- /priv/gp_throughput.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function Usage { 4 | echo "Usage: gp_throughput.sh [-d TEST_DIR] [-k SUMMARY_KINDS] [-u UNIT]" >&2 5 | echo " [-t TERMINAL_TYPE] [-s PLOT_STYLE] [-p PRE_COMMAD]" >&2 6 | echo " [-P] [-E EXEC_COMMAND] [-h]" >&2 7 | echo "" >&2 8 | echo " -d TEST_DIR: comma separated test directories with summary.csv" >&2 9 | echo " default: \"tests/current\"" >&2 10 | echo " -k SUMMARY_KINDS: summary kinds in comma separated list" >&2 11 | echo " default: \"total,failed\"" >&2 12 | echo " -u UNIT: unit of measurement" >&2 13 | echo " default: \"ops/sec\"" >&2 14 | echo " -t TERMINAL_TYPE: terminal type of gnuplot (e.g. dumb, x11, aqua)" >&2 15 | echo " default: nothing" >&2 16 | echo " -s PLOT_STYLE: plot style for points and lines, etc" >&2 17 | echo " default: \"linespoints pointsize 2 linewidth 1\"" >&2 18 | echo " -p PRE_COMMAND: any command to be executed before plot" >&2 19 | echo " default: nothing" >&2 20 | echo " -P: print gnuplot script to stdout" >&2 21 | echo " -E EXEC_COMMAND: command to be executed" >&2 22 | echo " default: \"gnuplot -persist\"" >&2 23 | echo " -h: print this usage" >&2 24 | exit 1 25 | } 26 | 27 | TEST_DIR=tests/current 28 | SUMMARY_KINDS="total,failed" 29 | TERMINAL_COMMAND= 30 | PLOT_STYLE="linespoints pointsize 2 linewidth 1" 31 | PRE_COMMAD= 32 | EXEC_COMMAND="gnuplot -persist" 33 | UNIT="ops/sec" 34 | 35 | while getopts ":d:k:u:t:s:p:PE:h" opt; do 36 | case $opt in 37 | d) 38 | TEST_DIR=${OPTARG} ;; 39 | k) 40 | SUMMARY_KINDS=${OPTARG} ;; 41 | u) 42 | UNIT="${OPTARG}" ;; 43 | t) 44 | TERMINAL_COMMAND="set terminal ${OPTARG}" ;; 45 | s) 46 | PLOT_STYLE=${OPTARG} ;; 47 | p) 48 | PRE_COMMAD=${OPTARG} ;; 49 | P) 50 | EXEC_COMMAND="cat" ;; 51 | h) 52 | Usage ;; 53 | \?) 54 | echo "Invalid option: -${OPTARG}" >&2 55 | Usage ;; 56 | :) 57 | echo "Option -${OPTARG} requires an argument." >&2 58 | Usage ;; 59 | esac 60 | done 61 | 62 | function plot_command(){ 63 | echo "plot \\" 64 | for THIS_TEST_DIR in ${TEST_DIR//,/ } 65 | do 66 | for KIND in ${SUMMARY_KINDS//,/ } 67 | do 68 | plot_per_kind ${KIND} 69 | done 70 | done 71 | echo " 1/0 notitle # dummy" 72 | } 73 | 74 | function plot_per_kind() { 75 | FILE=${THIS_TEST_DIR}/summary.csv 76 | case "${KIND}" in 77 | "total") COL_POS=3 ;; 78 | "successful") COL_POS=4 ;; 79 | "failed") COL_POS=5 ;; 80 | *) Usage ;; 81 | esac 82 | echo " \"${FILE}\" using 1:(\$${COL_POS}/\$2) with \\" 83 | echo " ${PLOT_STYLE} \\" 84 | 85 | # If plotting only 1 directory, do not add its name 86 | if [ "${THIS_DIR}" == "${THIS_TEST_DIR}" ]; then 87 | echo " title \"${KIND}\" \\" 88 | else 89 | echo " title \"${THIS_TEST_DIR##*/} - ${KIND}\" \\" 90 | fi 91 | echo " ,\\" 92 | } 93 | 94 | PLOT_COMMAND=`plot_command` 95 | 96 | ${EXEC_COMMAND} << EOF 97 | 98 | ## Use terminal definition as you like (via -t option) 99 | # set terminal dumb # character terminal 100 | # set terminal dumb 79 49 enhanced # character terminal portrait 101 | # set terminal x11 # X-Window 102 | # set terminal x11 persist # X-Window, remain alive after gnuplot exits 103 | # set terminal aqua # AquaTerm 104 | ${TERMINAL_COMMAND} 105 | 106 | ## title, key and axis 107 | set title "Throughput ${UNIT}" 108 | set autoscale 109 | set yrange [0:] 110 | set grid 111 | set xlabel "Elapsed [sec]" 112 | set ylabel "${UNIT}" 113 | set key inside bottom 114 | 115 | ## data file 116 | set datafile separator ',' 117 | 118 | ${PRE_COMMAD} 119 | 120 | ## plot 121 | ${PLOT_COMMAND} 122 | 123 | EOF 124 | -------------------------------------------------------------------------------- /priv/results-browser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import SimpleHTTPServer 4 | import SocketServer 5 | import logging 6 | import cgi 7 | import base64 8 | import argparse 9 | import os 10 | 11 | class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 12 | def do_GET(self): 13 | logging.warning("======= GET STARTED =======") 14 | logging.warning(self.headers) 15 | SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) 16 | 17 | def do_POST(self): 18 | logging.warning("======= POST STARTED =======") 19 | length = self.headers['content-length'] 20 | data = self.rfile.read(int(length)) 21 | 22 | with open(os.path.join("." , "summary.png"), 'w') as fh: 23 | fh.write(base64.b64decode(data.decode())) 24 | 25 | self.send_response(200) 26 | 27 | 28 | def startServer(host, port): 29 | httpd = SocketServer.TCPServer((host, port), ServerHandler) 30 | print 'Serving at: http://{host}:{port}'.format(host=host, port=port) 31 | httpd.serve_forever() 32 | 33 | if __name__ == '__main__': 34 | parser = argparse.ArgumentParser(description='Results generator') 35 | parser.add_argument('--port', '-p', type=int, help='Port for results generator to bind to', default=8080, required=False) 36 | parser.add_argument('--host', type=str, help='Host for results generator to bind to', default='localhost', required=False) 37 | args = parser.parse_args() 38 | startServer(args.host, args.port) -------------------------------------------------------------------------------- /priv/results-browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | 14 | 198 | 199 | 200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /priv/summary.r: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env Rscript 2 | 3 | # Parse the --file= argument out of command line args and 4 | # determine where base directory is so that we can source 5 | # our common sub-routines 6 | arg0 <- sub("--file=(.*)", "\\1", grep("--file=", commandArgs(), value = TRUE)) 7 | dir0 <- dirname(arg0) 8 | source(file.path(dir0, "common.r")) 9 | 10 | theme_set(theme_grey(base_size = 17)) 11 | 12 | # Setup parameters for the script 13 | params = matrix(c( 14 | 'help', 'h', 0, "logical", 15 | 'width', 'x', 2, "integer", 16 | 'height', 'y', 2, "integer", 17 | 'outfile', 'o', 2, "character", 18 | 'indir', 'i', 2, "character", 19 | 'tstart', '1', 2, "integer", 20 | 'tend', '2', 2, "integer", 21 | 'ylabel1stgraph', 'Y', 2, "character", 22 | 'title', 't', 2, "character" 23 | ), ncol=4, byrow=TRUE) 24 | 25 | # Parse the parameters 26 | opt = getopt(params) 27 | 28 | if (!is.null(opt$help)) 29 | { 30 | cat(paste(getopt(params, command = basename(arg0), usage = TRUE))) 31 | q(status=1) 32 | } 33 | 34 | # Initialize defaults for opt 35 | if (is.null(opt$width)) { opt$width = 1280 } 36 | if (is.null(opt$height)) { opt$height = 960 } 37 | if (is.null(opt$indir)) { opt$indir = "current"} 38 | if (is.null(opt$outfile)) { opt$outfile = file.path(opt$indir, "summary.png") } 39 | if (is.null(opt$ylabel1stgraph)) { opt$ylabel1stgraph = "Ops/sec" } 40 | if (is.null(opt$title)) { opt$title = "Throughput" } 41 | 42 | # Load the benchmark data, passing the time-index range we're interested in 43 | b = load_benchmark(opt$indir, opt$tstart, opt$tend) 44 | 45 | # If there is no actual data available, bail 46 | if (nrow(b$latencies) == 0) 47 | { 48 | stop("No latency information available to analyze in ", opt$indir) 49 | } 50 | 51 | png(file = opt$outfile, width = opt$width, height = opt$height) 52 | 53 | # First plot req/sec from summary 54 | plot1 <- qplot(elapsed, successful / window, data = b$summary, 55 | geom = c("smooth", "point"), 56 | xlab = "Elapsed Secs", ylab = opt$ylabel1stgraph, 57 | main = opt$title) + 58 | 59 | geom_smooth(aes(y = successful / window, colour = "ok"), size=0.5) + 60 | geom_point(aes(y = successful / window, colour = "ok"), size=2.0) + 61 | 62 | geom_smooth(aes(y = failed / window, colour = "error"), size=0.5) + 63 | geom_point(aes(y = failed / window, colour = "error"), size=2.0) + 64 | 65 | scale_colour_manual("Response", values = c("#FF665F", "#188125")) 66 | 67 | 68 | # Setup common elements of the latency plots 69 | latency_plot <- ggplot(b$latencies, aes(x = elapsed)) + 70 | facet_grid(. ~ op) + 71 | labs(x = "Elapsed Secs", y = "Latency (ms)") 72 | 73 | # Plot median, mean and 95th percentiles 74 | plot2 <- latency_plot + labs(title = "Mean, Median, and 95th Percentile Latency") + 75 | geom_smooth(aes(y = median, color = "median"), size=0.5) + 76 | geom_point(aes(y = median, color = "median"), size=2.0) + 77 | 78 | geom_smooth(aes(y = mean, color = "mean"), size=0.5) + 79 | geom_point(aes(y = mean, color = "mean"), size=2.0) + 80 | 81 | geom_smooth(aes(y = X95th, color = "95th"), size=0.5) + 82 | geom_point(aes(y = X95th, color = "95th"), size=2.0) + 83 | 84 | scale_colour_manual("Percentile", values = c("#FF665F", "#009D91", "#FFA700")) 85 | # scale_color_hue("Percentile", 86 | # breaks = c("X95th", "mean", "median"), 87 | # labels = c("95th", "Mean", "Median")) 88 | 89 | # Plot 99th percentile 90 | plot3 <- latency_plot + labs(title = "99th Percentile Latency") + 91 | geom_smooth(aes(y = X99th, color = "99th"), size=0.5) + 92 | geom_point(aes(y = X99th, color = "99th"), size=2.0) + 93 | scale_colour_manual("Percentile", values = c("#FF665F", "#009D91")) 94 | # scale_color_hue("Percentile", 95 | # breaks = c("X99_9th","X99th" ), 96 | # labels = c("99.9th", "99th")) 97 | 98 | # Plot 99.9th percentile 99 | plot4 <- latency_plot + labs(title = "99.9th Percentile Latency") + 100 | geom_smooth(aes(y = X99_9th, color = "99.9th"), size=0.5) + 101 | geom_point(aes(y = X99_9th, color = "99.9th"), size=2.0) + 102 | scale_colour_manual("Percentile", values = c("#FF665F", "#009D91", "#FFA700")) 103 | 104 | # Plot 100th percentile 105 | plot5 <- latency_plot + labs(title = "Maximum Latency") + 106 | geom_smooth(aes(y = max, color = "max"), size=0.5) + 107 | geom_point(aes(y = max, color = "max"), size=2.0) + 108 | scale_colour_manual("Percentile", values = c("#FF665F", "#009D91", "#FFA700")) 109 | 110 | grid.newpage() 111 | 112 | pushViewport(viewport(layout = grid.layout(5, 1))) 113 | 114 | vplayout <- function(x,y) viewport(layout.pos.row = x, layout.pos.col = y) 115 | 116 | print(plot1, vp = vplayout(1,1)) 117 | print(plot2, vp = vplayout(2,1)) 118 | print(plot3, vp = vplayout(3,1)) 119 | print(plot4, vp = vplayout(4,1)) 120 | print(plot5, vp = vplayout(5,1)) 121 | 122 | dev.off() 123 | -------------------------------------------------------------------------------- /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basho/basho_bench/aa66398bb6a91645dbb97e91a236f3cdcd1f188f/rebar -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | %% Known library limitations that make support for Erlang/OTP 2 | %% versions R15 or earlier difficult: 3 | %% 4 | %% katja: Defines a function `query()`, which is a reserved word in R15 5 | %% uuid: Dep on quickrand 6 | %% quickrand: Bogus (IMHO) inability to adapt to R15 environment. 7 | {require_otp_vsn, "R16|17|18"}. 8 | 9 | {deps, 10 | [ 11 | %% NOTE: some basho_bench drivers make use of pre-folsom stats 12 | %% that permitted float type counter increments. Thus 13 | %% we currently rely on a custom branch of folsom that 14 | %% has a useful-but-icky hack that allows fractional 15 | %% increments. If someone wants to take advantage of a 16 | %% new folsom feature, that desire + float incr must be 17 | %% weighed. 18 | {node_package, "2.0.*", {git, "git://github.com/basho/node_package", {tag, "2.0.0"}}}, 19 | {folsom, ".*", {git, "git://github.com/basho/folsom.git", {branch, "boundary-0.7.1+basho-bench-float"}}}, 20 | {lager, "2.*", {git, "git://github.com/basho/lager", {tag, "2.1.0"}}}, 21 | {ibrowse, ".*", 22 | {git, "git://github.com/cmullaparthi/ibrowse.git", {tag, "v4.0.2"}}}, 23 | {riakc, ".*", 24 | {git, "git://github.com/basho/riak-erlang-client", {branch, "master"}}}, 25 | {mochiweb, "2.9.*", 26 | {git, "git://github.com/basho/mochiweb", {tag, "v2.9.0"}}}, 27 | {getopt, ".*", 28 | {git, "git://github.com/jcomellas/getopt", {tag, "v0.8.2"}}}, 29 | 30 | {casbench, "0.1", 31 | {git, "git://github.com/basho/casbench", 32 | "95ed55b494551577870984aeb1e0f683631a326f"}}, 33 | %% A commit to the cqerl repo in 2015-02 added a dependency on a package 34 | %% called 're2', which causes additional compilation dependencies for 35 | %% the entire basho_bench package. Use a commit that's most recent 36 | %% but prior to the introduction of 're2'. 37 | {cqerl, ".*", 38 | {git, "git://github.com/matehat/cqerl.git", 39 | "16021593c866ca314acd0ba6858194ed44a362b3"}}, 40 | {katja, ".*", 41 | {git, "git://github.com/nifoc/katja.git", 42 | {branch, "master"}}}, 43 | {rebar_lock_deps_plugin, ".*", {git, "git://github.com/seth/rebar_lock_deps_plugin.git", {tag, "3.1.0"}}} 44 | ]}. 45 | 46 | {erl_opts, [{src_dirs, [src]}, 47 | {parse_transform, lager_transform}]}. 48 | 49 | {plugins, [rebar_lock_deps_plugin]}. 50 | 51 | {escript_incl_apps, [ 52 | bear, 53 | casbench, 54 | cqerl, 55 | folsom, 56 | getopt, 57 | goldrush, 58 | ibrowse, 59 | katja, 60 | lager, 61 | lz4, 62 | %% meck, 63 | mochiweb, 64 | node_package, 65 | %% proper, 66 | protobuffs, 67 | riak_pb, 68 | riakc, 69 | snappy 70 | ]}. 71 | 72 | %% When using the Java client bench driver, please use the -N and -C 73 | %% command line options to set the distributed Erlang node name 74 | %% and node cookie for the basho_bench VM. 75 | %% It isn't necessary to set the node name and cookie here. 76 | %% 77 | %% If you have any need to run basho_bench in an interactive way with 78 | %% the Erlang CLI, then remove the -noshell and -noinput flags. 79 | %% 80 | %% The value of +Q here is for 1.2 million ports, but the process 81 | %% won't be able to open that many ports without also adjusting the 82 | %% OS process's file descriptor limit, e.g., using "ulimit -n". 83 | 84 | {escript_emu_args, "%%! +K true -rsh ssh -noshell -noinput +P 1222333 +Q 1222333 +zdbbl 32768\n"}. 85 | -------------------------------------------------------------------------------- /rebar.config.lock: -------------------------------------------------------------------------------- 1 | %% THIS FILE IS GENERATED. DO NOT EDIT IT MANUALLY %% 2 | 3 | {require_otp_vsn,"R15|R16|17"}. 4 | {deps,[{node_package,".*", 5 | {git,"git://github.com/basho/node_package", 6 | "a56fe9b021e3543a24fdfc98f1c16704b41e62c6"}}, 7 | {bear,".*", 8 | {git,"git://github.com/boundary/bear.git", 9 | "b1882d7ee88e775d961a2678e4fafecef7f77705"}}, 10 | {meck,".*", 11 | {git,"git://github.com/eproxus/meck", 12 | "b7024d3ddbca329c9fe51f4bc5c4f891b13b4522"}}, 13 | {folsom,".*", 14 | {git,"git://github.com/basho/folsom.git", 15 | "fc0401798a3e6a412856d1768c89c46d4c4e5231"}}, 16 | {goldrush,".*", 17 | {git,"git://github.com/DeadZen/goldrush.git", 18 | "71e63212f12c25827e0c1b4198d37d5d018a7fec"}}, 19 | {lager,".*", 20 | {git,"git://github.com/basho/lager", 21 | "840acab51ebfb731de0137d9c6d41e7db4a12793"}}, 22 | {ibrowse,".*", 23 | {git,"git://github.com/cmullaparthi/ibrowse.git", 24 | "e8ae353c16d4f0897abb9f80025b52925b974dd1"}}, 25 | {protobuffs,".*", 26 | {git,"git://github.com/basho/erlang_protobuffs.git", 27 | "f88fc3c6881687432ddd5546b3c7b08009dfb26f"}}, 28 | {riak_pb,".*", 29 | {git,"git://github.com/basho/riak_pb", 30 | "620bc7001dc788e5530078aa8be53c9d15d4fdb4"}}, 31 | {riakc,".*", 32 | {git,"git://github.com/basho/riak-erlang-client", 33 | "1c75e31fd50e065aeebe787d608ce9b7ddeddb38"}}, 34 | {mochiweb,".*", 35 | {git,"git://github.com/basho/mochiweb", 36 | "9090c7942f9dcde4ddbf9f78429e289ff5600c18"}}, 37 | {getopt,".*", 38 | {git,"git://github.com/jcomellas/getopt", 39 | "388dc95caa7fb97ec7db8cfc39246a36aba61bd8"}}, 40 | {casbench,".*", 41 | {git,"git://github.com/basho/casbench", 42 | "95ed55b494551577870984aeb1e0f683631a326f"}}, 43 | {snappy,".*", 44 | {git,"https://github.com/fdmanana/snappy-erlang-nif.git", 45 | "ec2061113147af20916e9765ae9d63a18114825a"}}, 46 | {lz4,".*", 47 | {git,"https://github.com/szktty/erlang-lz4.git", 48 | "0572b0ea2aab83ec8cdd1526aaa5e7622fd6aee5"}}, 49 | {semver,".*", 50 | {git,"https://github.com/nebularis/semver.git", 51 | "c7d509f38298ec6594be4efdcd8a8f2322760039"}}, 52 | {quickrand,".*", 53 | {git,"https://github.com/okeuday/quickrand.git", 54 | "3eadabe05bddbffe9e3d5cf17a9384319d8756a1"}}, 55 | {uuid,".*", 56 | {git,"https://github.com/okeuday/uuid.git", 57 | "04a3037c492d2331dd7193c465868c1d71b28363"}}, 58 | {pooler,".*", 59 | {git,"https://github.com/seth/pooler.git", 60 | "6a12e4419c8fe504c77cd6393bcc11cb8993aa24"}}, 61 | {cqerl,".*", 62 | {git,"git://github.com/matehat/cqerl.git", 63 | "16021593c866ca314acd0ba6858194ed44a362b3"}}, 64 | {katja,".*", 65 | {git,"git://github.com/nifoc/katja.git", 66 | "ec7f78b85ec36570e528d21ed54038d74141f1ea"}}, 67 | {rebar_lock_deps_plugin,".*", 68 | {git,"git://github.com/seth/rebar_lock_deps_plugin.git", 69 | "9711549b8a84b065eb2edc22f8eb6ff85e3c94e8"}}]}. 70 | {erl_opts,[{src_dirs,[src]},{parse_transform,lager_transform}]}. 71 | {plugins,[rebar_lock_deps_plugin]}. 72 | {escript_incl_apps,[bear,casbench,cqerl,folsom,getopt,goldrush,ibrowse,katja, 73 | lager,lz4,mochiweb,node_package,protobuffs,riak_pb,riakc, 74 | snappy]}. 75 | {escript_emu_args,"%%! +K true -rsh ssh -noshell -noinput +P 1222333 +Q 1222333 +zdbbl 32768\n"}. 76 | 77 | -------------------------------------------------------------------------------- /rel/files/basho_bench: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Pull environment for this install 4 | . "{{runner_base_dir}}/lib/env.sh" 5 | 6 | # Make sure CWD is set to runner run dir 7 | cd $RUNNER_BASE_DIR/lib/basho_bench*/ebin 8 | 9 | ERL_LIBS=$RUNNER_BASE_DIR $ERTS_PATH/escript basho_bench.beam "$@" 10 | -------------------------------------------------------------------------------- /rel/files/install_upgrade.escript: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env escript 2 | %%! -noshell -noinput 3 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 4 | %% ex: ft=erlang ts=4 sw=4 et 5 | 6 | -define(TIMEOUT, 60000). 7 | -define(INFO(Fmt,Args), io:format(Fmt,Args)). 8 | 9 | main([NodeName, Cookie, ReleasePackage]) -> 10 | TargetNode = start_distribution(NodeName, Cookie), 11 | {ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release, 12 | [ReleasePackage], ?TIMEOUT), 13 | ?INFO("Unpacked Release ~p~n", [Vsn]), 14 | {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler, 15 | check_install_release, [Vsn], ?TIMEOUT), 16 | {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler, 17 | install_release, [Vsn], ?TIMEOUT), 18 | ?INFO("Installed Release ~p~n", [Vsn]), 19 | ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT), 20 | ?INFO("Made Release ~p Permanent~n", [Vsn]); 21 | main(_) -> 22 | init:stop(1). 23 | 24 | start_distribution(NodeName, Cookie) -> 25 | MyNode = make_script_node(NodeName), 26 | {ok, _Pid} = net_kernel:start([MyNode, shortnames]), 27 | erlang:set_cookie(node(), list_to_atom(Cookie)), 28 | TargetNode = make_target_node(NodeName), 29 | case {net_kernel:hidden_connect_node(TargetNode), 30 | net_adm:ping(TargetNode)} of 31 | {true, pong} -> 32 | ok; 33 | {_, pang} -> 34 | io:format("Node ~p not responding to pings.\n", [TargetNode]), 35 | init:stop(1) 36 | end, 37 | TargetNode. 38 | 39 | make_target_node(Node) -> 40 | [_, Host] = string:tokens(atom_to_list(node()), "@"), 41 | list_to_atom(lists:concat([Node, "@", Host])). 42 | 43 | make_script_node(Node) -> 44 | list_to_atom(lists:concat([Node, "_upgrader_", os:getpid()])). 45 | -------------------------------------------------------------------------------- /rel/files/vm.args: -------------------------------------------------------------------------------- 1 | ## Name of the node 2 | -name bb@127.0.0.1 3 | 4 | ## Cookie for distributed erlang 5 | -setcookie bb 6 | 7 | ## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive 8 | ## (Disabled by default..use with caution!) 9 | ##-heart 10 | 11 | ## Enable kernel poll and a few async threads 12 | ##+K true 13 | ##+A 5 14 | 15 | ## Increase number of concurrent ports/sockets 16 | ##-env ERL_MAX_PORTS 4096 17 | 18 | ## Tweak GC to run more often 19 | ##-env ERL_FULLSWEEP_AFTER 10 20 | -------------------------------------------------------------------------------- /rel/reltool.config: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang -*- 2 | %% ex: ft=erlang 3 | {sys, [ 4 | {lib_dirs, ["../deps"]}, 5 | {erts, [{mod_cond, derived}, {app_file, strip}]}, 6 | {app_file, strip}, 7 | {rel, "basho_bench", "0.10.0", 8 | [ 9 | kernel, 10 | stdlib, 11 | bear, 12 | lager, 13 | folsom, 14 | goldrush, 15 | riakc, 16 | ibrowse, 17 | mochiweb 18 | ]}, 19 | {rel, "start_clean", "", 20 | [ 21 | kernel, 22 | stdlib 23 | ]}, 24 | {boot_rel, "basho_bench"}, 25 | {profile, embedded}, 26 | {incl_cond, derived}, 27 | {excl_archive_filters, [".*"]}, %% Do not archive built libs 28 | {excl_sys_filters, ["^bin/(?!start_clean.boot)", 29 | "^erts.*/bin/(dialyzer|typer)", 30 | "^erts.*/(doc|info|include|lib|man|src)"]}, 31 | {excl_app_filters, ["\.gitignore"]}, 32 | {app, basho_bench, [{mod_cond, app}, {incl_cond, include}, {lib_dir, ".."}]}, 33 | {app, hipe, [{incl_cond, exclude}]} 34 | ]}. 35 | 36 | {target_dir, "basho_bench"}. 37 | {overlay_vars, "vars.config"}. 38 | 39 | {overlay, [ 40 | {template, "../deps/node_package/priv/base/env.sh", 41 | "lib/env.sh"}, 42 | {mkdir, "data/b_b"}, 43 | 44 | %% Copy base files for starting and interacting w/ node 45 | {copy, "../deps/node_package/priv/base/erl", 46 | "{{erts_vsn}}/bin/erl"}, 47 | {copy, "../deps/node_package/priv/base/nodetool", 48 | "{{erts_vsn}}/bin/nodetool"}, 49 | {template, "../deps/node_package/priv/base/env.sh", 50 | "lib/env.sh"}, 51 | {copy, "files/vm.args", "etc/vm.args"}, 52 | 53 | {template, "files/basho_bench", "bin/basho_bench"}, 54 | 55 | {copy, "../examples/cs.config.sample", "etc/cs.config"}, 56 | {copy, "../examples/riakc_pb.config", "etc/riakc_pb.config"}, 57 | {copy, "../examples/httpraw.config", "etc/httpraw.config"}, 58 | {copy, "../examples/http.config", "etc/http.config"}, 59 | {copy, "../examples/null_test.config", "etc/null_test.config"} 60 | 61 | %%{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"}, 62 | 63 | ]}. 64 | -------------------------------------------------------------------------------- /rel/vars.config: -------------------------------------------------------------------------------- 1 | %% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ts=4 sw=4 et 3 | 4 | %% Platform-specific installation paths 5 | {platform_bin_dir, "./bin"}. 6 | {platform_data_dir, "./data"}. 7 | {platform_etc_dir, "./etc"}. 8 | {platform_lib_dir, "./lib"}. 9 | {platform_log_dir, "./log"}. 10 | 11 | %% 12 | {data_dir, "{{target_dir}}/data"}. 13 | {runner_script_dir, "\`cd \\`dirname $0\\` && /bin/pwd\`"}. 14 | {runner_base_dir, "{{runner_script_dir}}/.."}. 15 | {runner_etc_dir, "$RUNNER_BASE_DIR/etc"}. 16 | {runner_log_dir, "$RUNNER_BASE_DIR/log"}. 17 | {runner_lib_dir, "$RUNNER_BASE_DIR/lib"}. 18 | {runner_patch_dir, "$RUNNER_BASE_DIR/lib/basho-patches"}. 19 | {pipe_dir, "/tmp/$RUNNER_BASE_DIR/"}. 20 | {runner_user, ""}. 21 | -------------------------------------------------------------------------------- /src/basho_bench.app.src: -------------------------------------------------------------------------------- 1 | {application, basho_bench, 2 | [{description, "Riak Benchmarking Suite"}, 3 | {vsn, git}, 4 | {modules, []}, 5 | {registered, [ basho_bench_sup ]}, 6 | {applications, [kernel, 7 | stdlib, 8 | lager, 9 | sasl]}, 10 | {mod, {basho_bench_app, []}}, 11 | {env, [ 12 | %% Run mode: How should basho_bench started as a separate node, or part of an 13 | %% other node. The default is standalone, other option is included. 14 | {app_run_mode, standalone}, 15 | 16 | %% 17 | %% Mode of load generation: 18 | %% max - Generate as many requests as possible per worker 19 | %% {rate, Rate} - Exp. distributed Mean reqs/sec 20 | %% 21 | {mode, {rate, 5}}, 22 | 23 | %% 24 | %% Default log level 25 | %% 26 | {log_level, debug}, 27 | 28 | %% 29 | %% Base test output directory 30 | %% 31 | {test_dir, "tests"}, 32 | 33 | %% 34 | %% Test duration (minutes) 35 | %% 36 | {duration, 5}, 37 | 38 | %% 39 | %% Number of concurrent workers 40 | %% 41 | {concurrent, 3}, 42 | 43 | %% 44 | %% Driver module for the current test 45 | %% 46 | {driver, basho_bench_driver_http_raw}, 47 | 48 | %% 49 | %% Stats Sink Driver module for the current test 50 | %% By default: 51 | %% csv - csv file 52 | %% riemann - riemann server 53 | %% {stats, {csv}}, 54 | %% 55 | %% Operations (and associated mix). Note that 56 | %% the driver may not implement every operation. 57 | %% 58 | {operations, [{get, 4}, 59 | {put, 4}, 60 | {delete, 1}]}, 61 | 62 | %% 63 | %% Interval on which to report latencies and status (seconds) 64 | %% 65 | {report_interval, 10}, 66 | 67 | %% 68 | %% Key generators 69 | %% 70 | %% {uniform_int, N} - Choose a uniformly distributed integer between 0 and N 71 | %% 72 | {key_generator, {uniform_int, 100000}}, 73 | 74 | %% 75 | %% Value generators 76 | %% 77 | %% {fixed_bin, N} - Fixed size binary blob of N bytes 78 | %% 79 | {value_generator, {fixed_bin, 100}} 80 | ]} 81 | ]}. 82 | -------------------------------------------------------------------------------- /src/basho_bench_app.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_app). 23 | 24 | -behaviour(application). 25 | 26 | %% API 27 | -export([start/0, 28 | stop/0, 29 | is_running/0, 30 | stop_or_kill/0]). 31 | 32 | %% Application callbacks 33 | -export([start/2, stop/1]). 34 | 35 | 36 | %% =================================================================== 37 | %% API 38 | %%=================================================================== 39 | 40 | start() -> 41 | %% Redirect all SASL logging into a text file 42 | case application:get_env(basho_bench,app_run_mode) of 43 | {ok, included} -> 44 | %%Make sure sasl and crypto is available 45 | true=lists:keymember(sasl,1,application:which_applications()), 46 | true=lists:keymember(crypto,1,application:which_applications()), 47 | 48 | %% Start up our application 49 | application:start(basho_bench); 50 | NotInc when NotInc == {ok, standalone} orelse NotInc == undefined -> 51 | application:load(sasl), 52 | application:set_env(sasl, sasl_error_logger, {file, "log.sasl.txt"}), 53 | %% Make sure crypto is available 54 | ensure_started([sasl, crypto]), 55 | 56 | %% Start up our application -- mark it as permanent so that the node 57 | %% will be killed if we go down 58 | application:start(basho_bench, permanent) 59 | end. 60 | 61 | stop() -> 62 | application:stop(basho_bench). 63 | 64 | is_running() -> 65 | application:get_env(basho_bench_app, is_running) == {ok, true}. 66 | 67 | stop_or_kill() -> 68 | %% If running standalone, halt and kill node. Otherwise, just 69 | %% kill top supervisor. 70 | case application:get_env(basho_bench,app_run_mode) of 71 | {ok, included} -> 72 | exit(whereis(basho_bench_sup),kill); 73 | _ -> 74 | init:stop(1) 75 | end. 76 | 77 | %% =================================================================== 78 | %% Application callbacks 79 | %%=================================================================== 80 | 81 | start(_StartType, _StartArgs) -> 82 | %% TODO: Move into a proper supervision tree, janky for now 83 | basho_bench_config:start_link(), 84 | {ok, Pid} = basho_bench_sup:start_link(), 85 | application:set_env(basho_bench_app, is_running, true), 86 | ok = basho_bench_stats:run(), 87 | ok = basho_bench_measurement:run(), 88 | ok = basho_bench_worker:run(basho_bench_sup:workers()), 89 | {ok, Pid}. 90 | 91 | 92 | stop(_State) -> 93 | %% intentionally left in to show where worker profiling start/stop calls go. 94 | %% eprof:stop_profiling(), 95 | %% eprof:analyze(total), 96 | %% eprof:log("bb.eprof"), 97 | ok. 98 | 99 | %% =================================================================== 100 | %% Internal functions 101 | %% =================================================================== 102 | 103 | ensure_started(Applications) when is_list(Applications) -> 104 | [ensure_started(Application) || Application <- Applications]; 105 | 106 | ensure_started(Application) -> 107 | case application:start(Application) of 108 | ok -> 109 | ok; 110 | {error, {already_started, Application}} -> 111 | ok; 112 | Error -> 113 | throw(Error) 114 | end. 115 | -------------------------------------------------------------------------------- /src/basho_bench_config.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_config). 23 | -behaviour(gen_server). 24 | 25 | 26 | -ifdef(TEST). 27 | -include_lib("eunit/include/eunit.hrl"). 28 | -compile(export_all). 29 | -endif. 30 | 31 | -export([load/1, 32 | normalize_ips/2, 33 | set/2, 34 | get/1, get/2]). 35 | 36 | -export([start_link/0]). 37 | 38 | % Gen server callbacks 39 | -export([code_change/3, init/1, terminate/2, handle_call/3, handle_cast/2, handle_info/2]). 40 | 41 | -include("basho_bench.hrl"). 42 | 43 | -record(basho_bench_config_state, {}). 44 | 45 | -type state() :: #basho_bench_config_state{}. 46 | %% =================================================================== 47 | %% Public API 48 | %% =================================================================== 49 | 50 | %% Todo: ensure_started before calling on any gen_server APIs. 51 | ensure_started() -> 52 | start_link(). 53 | 54 | start_link() -> 55 | gen_server:start_link({global, ?MODULE}, ?MODULE, [], []). 56 | 57 | 58 | load(Files) -> 59 | ensure_started(), 60 | gen_server:call({global, ?MODULE}, {load_files, Files}). 61 | 62 | set(Key, Value) -> 63 | gen_server:call({global, ?MODULE}, {set, Key, Value}). 64 | 65 | get(Key) -> 66 | case gen_server:call({global, ?MODULE}, {get, Key}) of 67 | {ok, Value} -> 68 | Value; 69 | undefined -> 70 | erlang:error("Missing configuration key", [Key]) 71 | end. 72 | 73 | get(Key, Default) -> 74 | case gen_server:call({global, ?MODULE}, {get, Key}) of 75 | {ok, Value} -> 76 | Value; 77 | undefined -> 78 | Default 79 | end. 80 | 81 | %% @doc Normalize the list of IPs and Ports. 82 | %% 83 | %% E.g. 84 | %% 85 | %% ["127.0.0.1", {"127.0.0.1", 8091}, {"127.0.0.1", [8092,8093]}] 86 | %% 87 | %% => [{"127.0.0.1", DefaultPort}, 88 | %% {"127.0.0.1", 8091}, 89 | %% {"127.0.0.1", 8092}, 90 | %% {"127.0.0.1", 8093}] 91 | normalize_ips(IPs, DefultPort) -> 92 | F = fun(Entry, Acc) -> 93 | normalize_ip_entry(Entry, Acc, DefultPort) 94 | end, 95 | lists:foldl(F, [], IPs). 96 | 97 | 98 | 99 | 100 | 101 | %% =================================================================== 102 | %% Internal functions 103 | %% =================================================================== 104 | 105 | 106 | normalize_ip_entry({IP, Ports}, Normalized, _) when is_list(Ports) -> 107 | [{IP, Port} || Port <- Ports] ++ Normalized; 108 | normalize_ip_entry({IP, Port}, Normalized, _) -> 109 | [{IP, Port}|Normalized]; 110 | normalize_ip_entry(IP, Normalized, DefaultPort) -> 111 | [{IP, DefaultPort}|Normalized]. 112 | 113 | 114 | %% === 115 | %% Gen_server Functions 116 | %% === 117 | 118 | -spec init(term()) -> {ok, state()}. 119 | init(_Args) -> 120 | State = #basho_bench_config_state{}, 121 | {ok, State}. 122 | 123 | -spec code_change(term(), state(), term()) -> {ok, state()}. 124 | code_change(_OldVsn, State, _Extra) -> 125 | {ok, State}. 126 | 127 | -spec terminate(term(), state()) -> 'ok'. 128 | terminate(_Reason, _State) -> 129 | ok. 130 | 131 | handle_call({load_files, FileNames}, _From, State) -> 132 | set_keys_from_files(FileNames), 133 | {reply, ok, State}; 134 | 135 | handle_call({set, Key, Value}, _From, State) -> 136 | application:set_env(basho_bench, Key, Value), 137 | {reply, ok, State}; 138 | handle_call({get, Key}, _From, State) -> 139 | Value = application:get_env(basho_bench, Key), 140 | {reply, Value, State}. 141 | 142 | handle_cast(_Cast, State) -> 143 | {noreply, State}. 144 | 145 | handle_info(_Info, State) -> 146 | {noreply, State}. 147 | 148 | set_keys_from_files(Files) -> 149 | KVs = [ 150 | case file:consult(File) of 151 | {ok, Terms} -> 152 | Terms; 153 | {error, Reason} -> 154 | ?FAIL_MSG("Failed to parse config file ~s: ~p\n", [File, Reason]), 155 | throw(invalid_config), 156 | notokay 157 | end || File <- Files ], 158 | FlatKVs = lists:flatten(KVs), 159 | [application:set_env(basho_bench, Key, Value) || {Key, Value} <- FlatKVs]. 160 | 161 | -------------------------------------------------------------------------------- /src/basho_bench_driver_bitcask.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_bitcask). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | -record(state, { file, 30 | filename, 31 | flags, 32 | sync_interval, 33 | last_sync }). 34 | 35 | %% ==================================================================== 36 | %% API 37 | %% ==================================================================== 38 | 39 | new(_Id) -> 40 | %% Make sure bitcask is available 41 | case code:which(bitcask) of 42 | non_existing -> 43 | ?FAIL_MSG("~s requires bitcask to be available on code path.\n", 44 | [?MODULE]); 45 | _ -> 46 | ok 47 | end, 48 | 49 | %% Get the target directory 50 | Dir = basho_bench_config:get(bitcask_dir, "."), 51 | Filename = filename:join(Dir, "test.bitcask"), 52 | 53 | %% Look for sync interval config 54 | case basho_bench_config:get(bitcask_sync_interval, infinity) of 55 | Value when is_integer(Value) -> 56 | SyncInterval = Value; 57 | infinity -> 58 | SyncInterval = infinity 59 | end, 60 | 61 | %% Get any bitcask flags 62 | Flags = basho_bench_config:get(bitcask_flags, []), 63 | case bitcask:open(Filename, [read_write] ++ Flags) of 64 | {error, Reason} -> 65 | ?FAIL_MSG("Failed to open bitcask in ~s: ~p\n", [Filename, Reason]); 66 | File -> 67 | %% Try to start the merge worker 68 | bitcask_merge_worker:start_link(), 69 | {ok, #state { file = File, 70 | filename = Filename, 71 | flags = Flags, 72 | sync_interval = SyncInterval, 73 | last_sync = os:timestamp() }} 74 | end. 75 | 76 | 77 | 78 | run(get, KeyGen, _ValueGen, State) -> 79 | State1 = maybe_sync(State), 80 | case bitcask:get(State1#state.file, KeyGen()) of 81 | {ok, _Value} -> 82 | {ok, State1}; 83 | not_found -> 84 | {ok, State1}; 85 | {error, Reason} -> 86 | {error, Reason} 87 | end; 88 | run(put, KeyGen, ValueGen, State) -> 89 | State1 = maybe_sync(State), 90 | case bitcask:put(State1#state.file, KeyGen(), ValueGen()) of 91 | ok -> 92 | {ok, State1}; 93 | {error, Reason} -> 94 | {error, Reason} 95 | end; 96 | run(merge, _KeyGen, _ValueGen, State) -> 97 | case bitcask:needs_merge(State#state.file) of 98 | {true, Files} -> 99 | case bitcask_merge_worker:merge(State#state.filename, State#state.flags, 100 | Files) of 101 | ok -> 102 | {ok, State}; 103 | Other -> 104 | {error, {merge_failed, Other}} 105 | end; 106 | false -> 107 | {ok, State} 108 | end. 109 | 110 | 111 | 112 | maybe_sync(#state { sync_interval = infinity } = State) -> 113 | State; 114 | maybe_sync(#state { sync_interval = SyncInterval } = State) -> 115 | Now = os:timestamp(), 116 | case timer:now_diff(Now, State#state.last_sync) / 1000000 of 117 | Value when Value >= SyncInterval -> 118 | bitcask:sync(State#state.file), 119 | State#state { last_sync = Now }; 120 | _ -> 121 | State 122 | end. 123 | 124 | -------------------------------------------------------------------------------- /src/basho_bench_driver_carbon.erl: -------------------------------------------------------------------------------- 1 | -module(basho_bench_driver_carbon). 2 | 3 | -export([new/1, run/4]). 4 | 5 | -include("basho_bench.hrl"). 6 | 7 | -record(state, { 8 | host, 9 | port, 10 | keep_connect, 11 | batch_size, 12 | socket 13 | }). 14 | 15 | new(_Id) -> 16 | Host = basho_bench_config:get(carbon_server, "127.0.0.1"), 17 | Port = basho_bench_config:get(carbon_port, 2003), 18 | KeepConnect = basho_bench_config:get(carbon_keep_connect, false), 19 | BatchSize = basho_bench_config:get(carbon_batch_size, 100), 20 | {ok, #state{ 21 | host=Host, 22 | port=Port, 23 | keep_connect=KeepConnect, 24 | batch_size=BatchSize, 25 | socket=nil}}. 26 | 27 | carbon(State = #state{host=Host, port=Port, socket=nil}, Message) -> 28 | case gen_tcp:connect(Host, Port, [list, {packet, 0}]) of 29 | {ok, Sock} -> 30 | carbon(State#state{socket=Sock}, Message); 31 | Error -> 32 | Error 33 | end; 34 | 35 | carbon(State = #state{socket=Socket, keep_connect=KeepConnect}, Message) -> 36 | case gen_tcp:send(Socket, Message) of 37 | ok -> 38 | case KeepConnect of 39 | true -> 40 | {ok, State}; 41 | _ -> 42 | ok = gen_tcp:close(Socket), 43 | {ok, State#state{socket=nil}} 44 | end; 45 | Error -> 46 | Error % let it crash 47 | end. 48 | 49 | concat(0, _Keygen, _Ts, List) -> 50 | List; 51 | 52 | concat(Size, KeyGen, Ts, List) -> 53 | Msg = io_lib:format("pim.pam.poum.~p ~p ~p~n", [KeyGen(), Ts, random:uniform(1000)]), 54 | concat(Size -1, KeyGen, Ts, [Msg | List]). 55 | 56 | run(set, KeyGen, _ValueGen, State = #state{batch_size=BatchSize}) -> 57 | {Mega, Sec, _Micro} = now(), 58 | Msg = concat(BatchSize, KeyGen, Mega * 1000 + Sec, []), 59 | 60 | case carbon(State, Msg) of 61 | {error, E} -> 62 | {error, E, State}; 63 | OK -> 64 | OK 65 | end. 66 | 67 | -------------------------------------------------------------------------------- /src/basho_bench_driver_cassandra.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_cassandra). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | -include_lib("casbench/include/cassandra_thrift.hrl"). 29 | 30 | -record(state, { client, 31 | keyspace, 32 | colpath, 33 | conlevel 34 | }). 35 | 36 | 37 | %% ==================================================================== 38 | %% API 39 | %% ==================================================================== 40 | 41 | new(Id) -> 42 | %% Make sure the path is setup such that we can get at riak_client 43 | case code:which(cassandra_thrift) of 44 | non_existing -> 45 | ?FAIL_MSG("~s requires cassandra_thrift module to be available on code path.\n", 46 | [?MODULE]); 47 | _ -> 48 | ok 49 | end, 50 | 51 | Hosts = basho_bench_config:get(cassandra_hosts, ["localhost"]), 52 | Port = basho_bench_config:get(cassandra_port, 9160), 53 | Keyspace = basho_bench_config:get(cassandra_keyspace, "Keyspace1"), 54 | ColPath = #columnPath { column_family = "Standard1", column = "col1" }, 55 | ConLevel = basho_bench_config:get(cassandra_consistencylevel, 1), 56 | 57 | %% Choose the node using our ID as a modulus 58 | TargetHost = lists:nth((Id rem length(Hosts)+1), Hosts), 59 | ?INFO("Using target ~s:~p for worker ~p\n", [TargetHost, Port, Id]), 60 | 61 | case thrift_client:start_link(TargetHost, Port, cassandra_thrift) of 62 | {ok, Client} -> 63 | {ok, #state { client = Client, 64 | keyspace = Keyspace, 65 | colpath = ColPath, 66 | conlevel = ConLevel }}; 67 | {error, Reason} -> 68 | ?FAIL_MSG("Failed to get a thrift_client for ~p: ~p\n", [TargetHost, Reason]) 69 | end. 70 | 71 | call(State, Op, Args) -> 72 | (catch thrift_client:call(State#state.client, Op, Args)). 73 | 74 | tstamp() -> 75 | {Mega, Sec, _Micro} = now(), 76 | (Mega * 1000000) + Sec. 77 | 78 | 79 | run(get, KeyGen, _ValueGen, 80 | #state{keyspace=KeySpace, colpath=ColPath, conlevel=ConLevel}=State) -> 81 | Key = KeyGen(), 82 | Args = [KeySpace, Key, ColPath, ConLevel], 83 | case call(State, get, Args) of 84 | {ok, _} -> 85 | {ok, State}; 86 | {notFoundException} -> 87 | %% DEBUG io:format("g(~p)",[Key]), 88 | io:format("g"), 89 | {ok, State}; 90 | {'EXIT', {timeout, _}} -> 91 | {error, timeout, State}; 92 | Error -> 93 | {error, Error, State} 94 | end; 95 | run(put, KeyGen, ValueGen, 96 | #state{keyspace=KeySpace, colpath=ColPath, conlevel=ConLevel}=State) -> 97 | Key = KeyGen(), 98 | Val = ValueGen(), 99 | TS = tstamp(), 100 | Args = [KeySpace, Key, ColPath, Val, TS, ConLevel], 101 | case call(State, insert, Args) of 102 | {ok, ok} -> 103 | {ok, State}; 104 | {'EXIT', {timeout, _}} -> 105 | {error, timeout, State}; 106 | Error -> 107 | {error, Error, State} 108 | end; 109 | run(delete, KeyGen, _ValueGen, 110 | #state{keyspace=KeySpace, colpath=ColPath, conlevel=ConLevel}=State) -> 111 | Key = KeyGen(), 112 | TS = 0, %% TBD: cannot specify a "known" timestamp value? 113 | Args = [KeySpace, Key, ColPath, TS, ConLevel], 114 | case call(State, remove, Args) of 115 | {ok, _} -> 116 | {ok, State}; 117 | {notFoundException} -> 118 | %% DEBUG io:format("d(~p)",[Key]), 119 | io:format("d"), 120 | {ok, State}; 121 | {'EXIT', {timeout, _}} -> 122 | {error, timeout, State}; 123 | Error -> 124 | {error, Error, State} 125 | end. 126 | -------------------------------------------------------------------------------- /src/basho_bench_driver_cassandra_cql.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2012 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_cassandra_cql). 23 | -compile({inline, [run_put/3]}). 24 | 25 | -export([new/1, 26 | run/4]). 27 | 28 | -include("basho_bench.hrl"). 29 | -include_lib("cqerl/include/cqerl.hrl"). 30 | 31 | -record(state, { client, 32 | keyspace, 33 | columnfamily, 34 | column, 35 | partition_key, 36 | get_query, 37 | put_query, 38 | delete_query, 39 | put_composite_query, 40 | get_composite_query, 41 | last_row_key = 0, 42 | range_query_num_rows 43 | }). 44 | 45 | 46 | %% ==================================================================== 47 | %% API 48 | %% ==================================================================== 49 | 50 | new(Id) -> 51 | Ips = basho_bench_config:get(cassandra_ips, [{"localhost", 9042}]), 52 | Port = basho_bench_config:get(cassandra_port, 9042), 53 | Keyspace = basho_bench_config:get(cassandra_keyspace, "Keyspace1"), 54 | ColumnFamily = basho_bench_config:get(cassandra_columnfamily, "ColumnFamily1"), 55 | ValueColumn = basho_bench_config:get(cassandra_column, "Column"), 56 | CompositePartitionColumn = basho_bench_config:get(cassandra_composite_partition_column, "PartitionKey"), 57 | CompositeRowColumn = basho_bench_config:get(cassandra_composite_row_column, "RowKey"), 58 | ReadConsistency = basho_bench_config:get(cassandra_read_consistency, ?CQERL_CONSISTENCY_ONE), 59 | WriteConsistency = basho_bench_config:get(cassandra_write_consistency, ?CQERL_CONSISTENCY_QUORUM), 60 | %% connect to client 61 | %% Choose the target node using our ID as a modulus 62 | Targets = basho_bench_config:normalize_ips(Ips, Port), 63 | {TargetIp, TargetPort} = lists:nth((Id rem length(Targets)+1), Targets), 64 | ?INFO("Using target ~p:~p for worker ~p\n", [TargetIp, TargetPort, Id]), 65 | application:ensure_all_started(cqerl), 66 | {ok, C} = cqerl:new_client({TargetIp, TargetPort}), 67 | 68 | case ksbarrier(C, Keyspace) of 69 | ok -> 70 | %% Build parameterized, reusable queries as we assume a typical 71 | %% high-volume Cassandra application would. 72 | GetQueryText = iolist_to_binary(["SELECT ", ValueColumn," FROM ", ColumnFamily ," where KEY = :key"]), 73 | GetQuery = #cql_query{statement = GetQueryText, consistency = ReadConsistency}, 74 | PutQueryText = iolist_to_binary(["UPDATE ", ColumnFamily, 75 | " SET ", ValueColumn, " = :val WHERE KEY = :key;"]), 76 | PutQuery = #cql_query{statement = PutQueryText, consistency = WriteConsistency}, 77 | DeleteQueryText = ["DELETE FROM ", ColumnFamily ," WHERE KEY = :key;"], 78 | DeleteQuery = #cql_query{statement = DeleteQueryText, consistency = WriteConsistency}, 79 | GetCompositeQueryText = iolist_to_binary(["SELECT ", ValueColumn," FROM ", ColumnFamily ," WHERE ", 80 | CompositePartitionColumn, " = :partition_key AND ", 81 | CompositeRowColumn, " > :min_row_key AND ", 82 | CompositeRowColumn, " < :max_row_key;"]), 83 | GetCompositeQuery = #cql_query{statement = GetCompositeQueryText, consistency = ReadConsistency}, 84 | PutCompositeQueryText = iolist_to_binary(["UPDATE ", ColumnFamily, 85 | " SET ", ValueColumn, " = :val WHERE ", CompositePartitionColumn, 86 | " = :partition_key AND ", CompositeRowColumn ," = :row_key;"]), 87 | PutCompositeQuery = #cql_query{statement=PutCompositeQueryText, consistency = WriteConsistency}, 88 | RangeQueryNumRows = basho_bench_config:get(cassandra_range_query_num_rows, 500), 89 | 90 | {ok, #state { client = C, 91 | partition_key = io_lib:format("~p - ~p", [node(), Id]), 92 | get_query = GetQuery, 93 | put_query = PutQuery, 94 | put_composite_query = PutCompositeQuery, 95 | get_composite_query = GetCompositeQuery, 96 | delete_query = DeleteQuery, 97 | range_query_num_rows = RangeQueryNumRows}}; 98 | {error, Reason} -> 99 | error_logger:error_msg("Failed to get a cqerl client for ~p: ~p\n", 100 | [TargetIp, Reason]) 101 | end. 102 | 103 | 104 | ksbarrier(C, Keyspace) -> 105 | case cqerl:run_query(C, lists:concat(["USE ", Keyspace, ";"])) of 106 | {ok, _KSBin} -> ok; 107 | {error, not_ready} -> 108 | %% Not ready yet, try again 109 | timer:sleep(100), 110 | ksbarrier(C, Keyspace); 111 | {error, _} = Error -> 112 | Error 113 | end. 114 | 115 | run(get, KeyGen, _ValueGen, 116 | #state{client=C, get_query=CqlQuery}=State) -> 117 | Key = KeyGen(), 118 | ParameterizedQuery = CqlQuery#cql_query{values = [{key, Key}]}, 119 | case cqerl:run_query(C, ParameterizedQuery) of 120 | {ok, #cql_result{cql_query=ParameterizedQuery} = _Result} -> 121 | {ok, State}; 122 | Error -> 123 | {error, Error, State} 124 | end; 125 | run(delete, KeyGen, _ValueGen, 126 | #state{client=C, delete_query=DeleteQuery}=State) -> 127 | Key = KeyGen(), 128 | ParameterizedQuery = DeleteQuery#cql_query{values = [{key, Key}]}, 129 | case cqerl:run_query(C, ParameterizedQuery) of 130 | {ok,void} -> 131 | {ok, State}; 132 | Error -> 133 | {error, Error, State} 134 | end; 135 | run(put_composite, KeyGen, ValueGen, 136 | #state{client=C, put_composite_query = Query, partition_key = PartitionKey}=State) -> 137 | RowKey = KeyGen(), 138 | Val = ValueGen(), 139 | ParameterizedQuery = Query#cql_query{values = [{partition_key, PartitionKey}, {row_key, RowKey}, {val, Val}]}, 140 | case cqerl:run_query(C, ParameterizedQuery) of 141 | {ok, void} -> 142 | {ok, State#state{last_row_key = RowKey}}; 143 | Error -> 144 | {error, Error, State} 145 | end; 146 | run(query_composite, KeyGen, _ValueGen, 147 | #state{client=C, get_composite_query = RangeQuery, partition_key = PartitionKey, 148 | last_row_key = LastRowKey0, range_query_num_rows = NumRows}=State) -> 149 | LastRowKey = case LastRowKey0 of 150 | 0 -> KeyGen(); 151 | _ -> LastRowKey0 152 | end, 153 | ParameterizedQuery = RangeQuery#cql_query{values = [{partition_key, PartitionKey}, 154 | {min_row_key, LastRowKey - NumRows}, 155 | {max_row_key, LastRowKey}]}, 156 | case cqerl:run_query(C, ParameterizedQuery) of 157 | {ok, _Result} -> 158 | {ok, State}; 159 | Error -> 160 | {error, Error, State} 161 | end; 162 | 163 | 164 | %% `insert` and `put` are functinally and performance-wise equivalent to Cassandra 165 | %% Keeping both in order to retain backward-compatibility with other people's test cases 166 | %% run_put is inlined. 167 | run(insert, KeyGen, ValueGen, State) -> 168 | run_put(KeyGen, ValueGen, State); 169 | run(put, KeyGen, ValueGen, State) -> 170 | run_put(KeyGen, ValueGen, State). 171 | 172 | run_put(KeyGen, ValueGen,#state{client=C, put_query = PutQuery}=State) -> 173 | Key = KeyGen(), 174 | Val = ValueGen(), 175 | ParameterizedQuery = PutQuery#cql_query{values = [{key, Key}, {val, Val}]}, 176 | case cqerl:run_query(C, ParameterizedQuery) of 177 | {ok, void} -> 178 | {ok, State}; 179 | Error -> 180 | {error, Error, State} 181 | end. 182 | -------------------------------------------------------------------------------- /src/basho_bench_driver_cluster.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: benchmark service on any within Erlang cluster 4 | %% using distribution protocol 5 | %% 6 | %% Copyright (c) 2015 Dmitry Kolesnikov 7 | %% 8 | %% This file is provided to you under the Apache License, 9 | %% Version 2.0 (the "License"); you may not use this file 10 | %% except in compliance with the License. You may obtain 11 | %% a copy of the License at 12 | %% 13 | %% http://www.apache.org/licenses/LICENSE-2.0 14 | %% 15 | %% Unless required by applicable law or agreed to in writing, 16 | %% software distributed under the License is distributed on an 17 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 | %% KIND, either express or implied. See the License for the 19 | %% specific language governing permissions and limitations 20 | %% under the License. 21 | %% 22 | %% ------------------------------------------------------------------- 23 | -module(basho_bench_driver_cluster). 24 | 25 | -export([ 26 | new/1, 27 | run/4 28 | ]). 29 | 30 | -record(state, {actor}). 31 | 32 | %% ==================================================================== 33 | %% API 34 | %% ==================================================================== 35 | 36 | new(Id) -> 37 | Actors = basho_bench_config:get(cluster_actors, []), 38 | Nth = (Id - 1) rem length(Actors) + 1, 39 | {Name, Node} = Actor = lists:nth(Nth, Actors), 40 | case net_adm:ping(Node) of 41 | pang -> 42 | lager:error("~s is not available", [Node]), 43 | {ok, #state{actor = undefined}}; 44 | 45 | pong -> 46 | lager:info("worker ~b is bound to ~s on ~s", [Id, Name, Node]), 47 | {ok, #state{actor = Actor}} 48 | end. 49 | 50 | run(Run, KeyGen, ValGen, #state{actor = Actor}=State) -> 51 | Key = KeyGen(), 52 | Val = ValGen(), 53 | erlang:send(Actor, {self(), Run, Key, Val}), 54 | receive 55 | {ok, ElapsedT} -> 56 | {ok, ElapsedT, State}; 57 | 58 | {error, Reason} -> 59 | {error, Reason} 60 | end. 61 | -------------------------------------------------------------------------------- /src/basho_bench_driver_dets.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_dets). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | %% ==================================================================== 30 | %% API 31 | %% ==================================================================== 32 | 33 | new(_Id) -> 34 | File = basho_bench_config:get(dets_file, ?MODULE), 35 | {ok, _} = dets:open_file(?MODULE, [{file, File}, 36 | {min_no_slots, 8192}, 37 | {max_no_slots, 16777216}]), 38 | {ok, undefined}. 39 | 40 | run(get, KeyGen, _ValueGen, State) -> 41 | Key = KeyGen(), 42 | case dets:lookup(?MODULE, Key) of 43 | [] -> 44 | {ok, State}; 45 | [{Key, _}] -> 46 | {ok, State}; 47 | {error, Reason} -> 48 | {error, Reason, State} 49 | end; 50 | run(put, KeyGen, ValueGen, State) -> 51 | ok = dets:insert(?MODULE, {KeyGen(), ValueGen()}), 52 | {ok, State}; 53 | run(delete, KeyGen, _ValueGen, State) -> 54 | ok = dets:delete(?MODULE, KeyGen()), 55 | {ok, State}. 56 | 57 | -------------------------------------------------------------------------------- /src/basho_bench_driver_eleveldb.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% Copyright (c) 2015 Basho Techonologies 4 | %% 5 | %% This file is provided to you under the Apache License, 6 | %% Version 2.0 (the "License"); you may not use this file 7 | %% except in compliance with the License. You may obtain 8 | %% a copy of the License at 9 | %% 10 | %% http://www.apache.org/licenses/LICENSE-2.0 11 | %% 12 | %% Unless required by applicable law or agreed to in writing, 13 | %% software distributed under the License is distributed on an 14 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | %% KIND, either express or implied. See the License for the 16 | %% specific language governing permissions and limitations 17 | %% under the License. 18 | %% 19 | %% ------------------------------------------------------------------- 20 | 21 | %% Raw eleveldb driver. It opens a number of eleveldb instances and assigns 22 | %% one to each created worker in round robin fashion. So, for example, creating 23 | %% 32 instances and 64 concurrent workers would bind a pair of workers to 24 | %% each instance for all operations. 25 | -module(basho_bench_driver_eleveldb). 26 | 27 | -export([new/1, 28 | run/4]). 29 | 30 | -include("basho_bench.hrl"). 31 | 32 | -record(state, { 33 | instance 34 | }). 35 | 36 | get_instances() -> 37 | case basho_bench_config:get(eleveldb_instances, undefined) of 38 | undefined -> 39 | Instances = start_instances(), 40 | basho_bench_config:set(eleveldb_instances, Instances), 41 | Instances; 42 | Instances -> 43 | Instances 44 | end. 45 | 46 | 47 | start_instances() -> 48 | case code:which(eleveldb) of 49 | non_existing -> 50 | ?FAIL_MSG("~s requires eleveldb to be avaiable on code path.\n", 51 | [?MODULE]); 52 | _ -> 53 | ok 54 | end, 55 | BaseDir = basho_bench_config:get(eleveldb_dir, "."), 56 | Num = basho_bench_config:get(eleveldb_num_instances, 1), 57 | Config = basho_bench_config:get(eleveldb_config, [{create_if_missing, true}]), 58 | ?INFO("Starting up ~p eleveldb instances under ~s with config ~p.\n", 59 | [Num, BaseDir, Config]), 60 | Refs = [begin 61 | Dir = filename:join(BaseDir, "instance." ++ integer_to_list(N)), 62 | ?INFO("Opening eleveldb instance in ~s\n", [Dir]), 63 | {ok, Ref} = eleveldb:open(Dir, Config), 64 | Ref 65 | end || N <- lists:seq(1, Num)], 66 | list_to_tuple(Refs). 67 | 68 | new(Id) -> 69 | Instances = get_instances(), 70 | Count = size(Instances), 71 | Idx = ((Id - 1) rem Count) + 1, 72 | ?INFO("Worker ~p using instance ~p.\n", [Id, Idx]), 73 | State = #state{instance = element(Idx, Instances)}, 74 | {ok, State}. 75 | 76 | 77 | run(get, KeyGen, _ValueGen, State = #state{instance = Ref}) -> 78 | Key = KeyGen(), 79 | case eleveldb:get(Ref, Key, []) of 80 | {ok, _Value} -> 81 | {ok, State}; 82 | not_found -> 83 | {ok, State}; 84 | {error, Reason} -> 85 | {error, Reason} 86 | end; 87 | run(put, KeyGen, ValGen, State = #state{instance = Ref}) -> 88 | Key = KeyGen(), 89 | Value = ValGen(), 90 | case eleveldb:put(Ref, Key, Value, []) of 91 | ok -> 92 | {ok, State}; 93 | {error, Reason} -> 94 | {error, Reason} 95 | end. 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/basho_bench_driver_ets.erl: -------------------------------------------------------------------------------- 1 | -module(basho_bench_driver_ets). 2 | 3 | -export([new/1, 4 | run/4]). 5 | 6 | new(_Id) -> 7 | EtsTable = ets:new(basho_bench, [ordered_set]), 8 | {ok, EtsTable}. 9 | 10 | run(get, KeyGen, _ValueGen, EtsTable) -> 11 | Start = KeyGen(), 12 | case ets:lookup(EtsTable, Start) of 13 | [] -> 14 | {ok, EtsTable}; 15 | [{_Key, _Val}] -> 16 | {ok, EtsTable}; 17 | Error -> 18 | {error, Error, EtsTable} 19 | end; 20 | 21 | run(put, KeyGen, ValueGen, EtsTable) -> 22 | Object = {KeyGen(), ValueGen()}, 23 | ets:insert(EtsTable, Object), 24 | {ok, EtsTable}; 25 | 26 | run(delete, KeyGen, _ValueGen, EtsTable) -> 27 | Start = KeyGen(), 28 | ets:delete(EtsTable, Start), 29 | {ok, EtsTable}. 30 | -------------------------------------------------------------------------------- /src/basho_bench_driver_innostore.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_innostore). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | %% ==================================================================== 30 | %% API 31 | %% ==================================================================== 32 | 33 | new(_Id) -> 34 | %% Make sure innostore app is available 35 | case code:which(innostore) of 36 | non_existing -> 37 | ?FAIL_MSG("~s requires innostore to be available on code path.\n", 38 | [?MODULE]); 39 | _ -> 40 | ok 41 | end, 42 | 43 | %% Pull the innodb_config key which has all the key/value pairs for the innostore 44 | %% engine -- stuff everything into the innostore application namespace 45 | %% so that starting innostore will pull it in. 46 | application:load(innostore), 47 | InnoConfig = basho_bench_config:get(innostore_config, []), 48 | [ok = application:set_env(innostore, K, V) || {K, V} <- InnoConfig], 49 | 50 | Bucket = basho_bench_config:get(innostore_bucket, <<"test">>), 51 | {ok, Port} = innostore:connect(), 52 | case innostore:open_keystore(Bucket, Port) of 53 | {ok, Store} -> 54 | {ok, Store}; 55 | {error, Reason} -> 56 | ?FAIL_MSG("Failed to open keystore ~p: ~p\n", [Bucket, Reason]) 57 | end. 58 | 59 | 60 | run(get, KeyGen, _ValueGen, State) -> 61 | case innostore:get(KeyGen(), State) of 62 | {ok, not_found} -> 63 | {ok, State}; 64 | {ok, _Value} -> 65 | {ok, State}; 66 | {error, Reason} -> 67 | {error, Reason, State} 68 | end; 69 | run(put, KeyGen, ValueGen, State) -> 70 | case innostore:put(KeyGen(), ValueGen(), State) of 71 | ok -> 72 | {ok, State}; 73 | {error, Reason} -> 74 | {error, State, Reason} 75 | end; 76 | run(delete, KeyGen, _ValueGen, State) -> 77 | case innostore:delete(KeyGen(), State) of 78 | ok -> 79 | {ok, State}; 80 | {error, Reason} -> 81 | {error, Reason, State} 82 | end. 83 | -------------------------------------------------------------------------------- /src/basho_bench_driver_kv_backend.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_kv_backend). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | -record(state, { 30 | backend :: atom(), 31 | bucket :: binary(), 32 | uses_r_object :: boolean(), 33 | be_state :: term() 34 | }). 35 | 36 | %% ==================================================================== 37 | %% API 38 | %% ==================================================================== 39 | 40 | %% @doc new 41 | %% 42 | %% Config items: 43 | %% - be_backend_mod :: atom() 44 | %% - be_disable_uses_r_object :: boolean() 45 | %% - be_config :: proplist(), passed to start/2 46 | 47 | new(_Id) -> 48 | Backend = basho_bench_config:get(be_backend_mod, riak_kv_yessir_backend), 49 | io:format("DBG ~p\n", [Backend]), 50 | Bucket = <<"Oh, shouldn't matter much">>, 51 | {ok, Caps} = Backend:capabilities(x), 52 | UsesRObj = proplists:get_value(uses_r_object, Caps, false), 53 | RObjDisabled = basho_bench_config:get(be_disable_uses_r_object, false), 54 | Use = UsesRObj andalso not RObjDisabled, 55 | {ok, BE} = Backend:start(0, basho_bench_config:get(be_config, [])), 56 | 57 | {ok, #state{backend=Backend, bucket=Bucket, uses_r_object=Use, 58 | be_state=BE}}. 59 | 60 | run(get, KeyGen, _ValueGen, 61 | #state{backend=Backend, bucket=Bucket, uses_r_object=RObjP, 62 | be_state=BE} = State) -> 63 | Key = KeyGen(), 64 | if RObjP -> 65 | {_ok_err, _, NewBE} = Backend:get_object(Bucket, Key, false, BE), 66 | {ok, State#state{be_state = NewBE}}; 67 | true -> 68 | {_ok_err, _, NewBE} = Backend:get(Bucket, Key, BE), 69 | {ok, State#state{be_state = NewBE}} 70 | end; 71 | run(put, KeyGen, ValueGen, 72 | #state{backend=Backend, bucket=Bucket, be_state=BE} = State) -> 73 | Key = KeyGen(), 74 | Val = ValueGen(), 75 | {ok, NewBE} = Backend:put(Bucket, Key, [], Val, BE), 76 | {ok, State#state{be_state = NewBE}}; 77 | run(do_something_else, KeyGen, ValueGen, State) -> 78 | _Key = KeyGen(), 79 | ValueGen(), 80 | {ok, State}; 81 | run(an_error, KeyGen, _ValueGen, State) -> 82 | _Key = KeyGen(), 83 | {error, went_wrong, State}; 84 | run(another_error, KeyGen, _ValueGen, State) -> 85 | _Key = KeyGen(), 86 | {error, {bad, things, happened}, State}. 87 | 88 | -------------------------------------------------------------------------------- /src/basho_bench_driver_null.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_null). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | %% ==================================================================== 30 | %% API 31 | %% ==================================================================== 32 | 33 | new(_Id) -> 34 | {ok, undefined}. 35 | 36 | run(absolutely_nothing, _KeyGen, _ValueGen, State) -> 37 | {ok, State}; 38 | run(do_something, KeyGen, _ValueGen, State) -> 39 | _Key = KeyGen(), 40 | {ok, State}; 41 | run(do_something_else, KeyGen, ValueGen, State) -> 42 | _Key = KeyGen(), 43 | ValueGen(), 44 | {ok, State}; 45 | run(an_error, KeyGen, _ValueGen, State) -> 46 | _Key = KeyGen(), 47 | {error, went_wrong, State}; 48 | run(another_error, KeyGen, _ValueGen, State) -> 49 | _Key = KeyGen(), 50 | {error, {bad, things, happened}, State}; 51 | run(print_key, KeyGen, _ValueGen, State) -> 52 | Key = KeyGen(), 53 | io:format(user, "~p\n", [Key]), 54 | {ok, State}; 55 | run(print_value, _KeyGen, ValueGen, State) -> 56 | Value = ValueGen(), 57 | io:format(user, "~p\n", [Value]), 58 | {ok, State}; 59 | run({print_value, PrintDepth}, _KeyGen, ValueGen, State) -> 60 | Value = ValueGen(), 61 | io:format(user, "~P\n", [Value, PrintDepth]), 62 | {ok, State}; 63 | run(print_key_and_value, KeyGen, ValueGen, State) -> 64 | Key = KeyGen(), 65 | Value = ValueGen(), 66 | io:format(user, "~p ~p\n", [Key, Value]), 67 | {ok, State}; 68 | run({print_key_and_value, KeyPrintDepth, ValuePrintDepth}, KeyGen, ValueGen, State) -> 69 | Key = KeyGen(), 70 | Value = ValueGen(), 71 | io:format(user, "~P ~P\n", [Key, KeyPrintDepth, 72 | Value, ValuePrintDepth]), 73 | {ok, State}. 74 | -------------------------------------------------------------------------------- /src/basho_bench_driver_nullfile.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_nullfile). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | %% ==================================================================== 30 | %% API 31 | %% ==================================================================== 32 | 33 | new(_Id) -> 34 | {ok, FH} = file:open("/tmp/null/" ++ integer_to_list(_Id), [write]), 35 | {ok, FH}. 36 | 37 | run(get, KeyGen, _ValueGen, State) -> 38 | _Key = KeyGen(), 39 | io:format(State, "~p ", [_Key]), 40 | {ok, State}; 41 | run(put, KeyGen, ValueGen, State) -> 42 | _Key = KeyGen(), 43 | ValueGen(), 44 | io:format(State, "~p ", [_Key]), 45 | {ok, State}; 46 | run(delete, KeyGen, _ValueGen, State) -> 47 | _Key = KeyGen(), 48 | io:format(State, "~p ", [_Key]), 49 | {ok, State}; 50 | run(an_error, KeyGen, _ValueGen, State) -> 51 | _Key = KeyGen(), 52 | io:format(State, "~p ", [_Key]), 53 | {error, went_wrong, State}; 54 | run(another_error, KeyGen, _ValueGen, State) -> 55 | _Key = KeyGen(), 56 | io:format(State, "~p ", [_Key]), 57 | {error, {bad, things, happened}, State}. 58 | 59 | -------------------------------------------------------------------------------- /src/basho_bench_driver_riakc_java.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench_driver_riakc_java: Driver for riak java client 4 | %% 5 | %% Copyright (c) 2011 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_riakc_java). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | -record(state, { pid, 30 | bucket, 31 | r, 32 | w, 33 | dw, 34 | rw}). 35 | 36 | %% ==================================================================== 37 | %% API 38 | %% ==================================================================== 39 | 40 | new(Id) -> 41 | Nodes = basho_bench_config:get(riakc_java_nodes, [[{'java@127.0.0.1',{127,0,0,1}, 8087}]]), 42 | %% riakc_pb_replies sets defaults for R, W, DW and RW. 43 | %% Each can be overridden separately 44 | Replies = basho_bench_config:get(riakc_java_replies, 2), 45 | R = basho_bench_config:get(riakc_java_r, Replies), 46 | W = basho_bench_config:get(riakc_java_w, Replies), 47 | DW = basho_bench_config:get(riakc_java_dw, Replies), 48 | RW = basho_bench_config:get(riakc_java_rw, Replies), 49 | Bucket = basho_bench_config:get(riakc_java_bucket, <<"test">>), 50 | Transport = basho_bench_config:get(riakc_java_transport, pb), 51 | PBBuffer = basho_bench_config:get(riakc_java_pbc_buffer, 16), 52 | 53 | %% Choose the node using our ID as a modulus 54 | {TargetNode, Ip, Port} = lists:nth((Id rem length(Nodes)+1), Nodes), 55 | ?INFO("Using target node ~p for worker ~p\n", [TargetNode, Id]), 56 | 57 | %% Check that we can at least talk to the jinterface riak java client node 58 | case net_adm:ping(TargetNode) of 59 | pang -> 60 | ?FAIL_MSG("~s requires that you run a java client jinterface node.\n", 61 | [?MODULE]); 62 | _ -> 63 | ok 64 | end, 65 | 66 | case basho_bench_java_client:new(TargetNode, Ip, Port, PBBuffer, Transport) of 67 | {ok, Pid} -> 68 | {ok, #state { pid = Pid, 69 | bucket = Bucket, 70 | r = R, 71 | w = W, 72 | dw = DW, 73 | rw = RW 74 | }}; 75 | {error, Reason2} -> 76 | ?FAIL_MSG("Failed to connect java jinterface node ~p on ip ~p to ~p port ~p: ~p\n", 77 | [TargetNode, Ip, Port, Reason2]) 78 | end. 79 | 80 | run(get, KeyGen, _ValueGen, State) -> 81 | Key = KeyGen(), 82 | case basho_bench_java_client:get(State#state.pid, State#state.bucket, Key, State#state.r) of 83 | {ok, _} -> 84 | {ok, State}; 85 | {error, Reason} -> 86 | {error, Reason, State} 87 | end; 88 | run(get_existing, KeyGen, _ValueGen, State) -> 89 | Key = KeyGen(), 90 | case basho_bench_java_client:get(State#state.pid, State#state.bucket, Key, State#state.r) of 91 | {ok, found} -> 92 | {ok, State}; 93 | {ok, notfound} -> 94 | {error, {not_found, Key}, State}; 95 | {error, Reason} -> 96 | {error, Reason, State} 97 | end; 98 | run(put, KeyGen, ValueGen, State) -> 99 | Key = KeyGen(), 100 | Value =ValueGen(), 101 | case basho_bench_java_client:put(State#state.pid, State#state.bucket, Key, Value, State#state.w, State#state.dw) of 102 | ok -> 103 | {ok, State}; 104 | {error, Reason} -> 105 | {error, Reason, State} 106 | end; 107 | run(update, KeyGen, ValueGen, State) -> 108 | Key = KeyGen(), 109 | Value = ValueGen(), 110 | case basho_bench_java_client:create_update(State#state.pid, State#state.bucket, 111 | Key, Value, State#state.r, State#state.w, State#state.dw) of 112 | 113 | ok -> 114 | {ok, State}; 115 | {error, Reason} -> 116 | {error, Reason, State} 117 | end; 118 | run(update_existing, KeyGen, ValueGen, State) -> 119 | Key = KeyGen(), 120 | Value = ValueGen(), 121 | case basho_bench_java_client:update(State#state.pid, State#state.bucket, 122 | Key, Value, State#state.r, State#state.w, State#state.dw) of 123 | ok -> 124 | {ok, State}; 125 | {error, notfound} -> 126 | {error, {not_found, Key}, State}; 127 | {error, Reason} -> 128 | {error, Reason, State} 129 | end; 130 | run(delete, KeyGen, _ValueGen, State) -> 131 | %% Pass on rw 132 | case basho_bench_java_client:delete(State#state.pid, State#state.bucket, KeyGen(), State#state.rw) of 133 | ok -> 134 | {ok, State}; 135 | {error, Reason} -> 136 | {error, Reason, State} 137 | end. 138 | 139 | 140 | %% ==================================================================== 141 | %% Internal functions 142 | %% ==================================================================== 143 | 144 | -------------------------------------------------------------------------------- /src/basho_bench_driver_riakclient.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_riakclient). 23 | 24 | -export([new/1, 25 | run/4]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | -record(state, { client, 30 | bucket, 31 | replies }). 32 | 33 | %% ==================================================================== 34 | %% API 35 | %% ==================================================================== 36 | 37 | new(Id) -> 38 | %% Make sure the path is setup such that we can get at riak_client 39 | case code:which(riak_client) of 40 | non_existing -> 41 | ?FAIL_MSG("~s requires riak_client module to be available on code path.\n", 42 | [?MODULE]); 43 | _ -> 44 | ok 45 | end, 46 | 47 | Nodes = basho_bench_config:get(riakclient_nodes), 48 | Cookie = basho_bench_config:get(riakclient_cookie, 'riak'), 49 | MyNode = basho_bench_config:get(riakclient_mynode, [basho_bench, longnames]), 50 | Replies = basho_bench_config:get(riakclient_replies, 2), 51 | Bucket = basho_bench_config:get(riakclient_bucket, <<"test">>), 52 | 53 | %% Try to spin up net_kernel 54 | case net_kernel:start(MyNode) of 55 | {ok, _} -> 56 | ?INFO("Net kernel started as ~p\n", [node()]); 57 | {error, {already_started, _}} -> 58 | ok; 59 | {error, Reason} -> 60 | ?FAIL_MSG("Failed to start net_kernel for ~p: ~p\n", [?MODULE, Reason]) 61 | end, 62 | 63 | %% Initialize cookie for each of the nodes 64 | [true = erlang:set_cookie(N, Cookie) || N <- Nodes], 65 | 66 | %% Try to ping each of the nodes 67 | ping_each(Nodes), 68 | 69 | %% Choose the node using our ID as a modulus 70 | TargetNode = lists:nth((Id rem length(Nodes)+1), Nodes), 71 | ?INFO("Using target node ~p for worker ~p\n", [TargetNode, Id]), 72 | 73 | case riak:client_connect(TargetNode) of 74 | {ok, Client} -> 75 | {ok, #state { client = Client, 76 | bucket = Bucket, 77 | replies = Replies }}; 78 | {error, Reason2} -> 79 | ?FAIL_MSG("Failed get a riak:client_connect to ~p: ~p\n", [TargetNode, Reason2]) 80 | end. 81 | 82 | run(get, KeyGen, _ValueGen, State) -> 83 | Key = KeyGen(), 84 | case (State#state.client):get(State#state.bucket, Key, State#state.replies) of 85 | {ok, _} -> 86 | {ok, State}; 87 | {error, notfound} -> 88 | {ok, State}; 89 | {error, Reason} -> 90 | {error, Reason, State} 91 | end; 92 | run(put, KeyGen, ValueGen, State) -> 93 | Robj = riak_object:new(State#state.bucket, KeyGen(), ValueGen()), 94 | case (State#state.client):put(Robj, State#state.replies) of 95 | ok -> 96 | {ok, State}; 97 | {error, Reason} -> 98 | {error, Reason, State} 99 | end; 100 | run(update, KeyGen, ValueGen, State) -> 101 | Key = KeyGen(), 102 | case (State#state.client):get(State#state.bucket, Key, State#state.replies) of 103 | {ok, Robj} -> 104 | Robj2 = riak_object:update_value(Robj, ValueGen()), 105 | case (State#state.client):put(Robj2, State#state.replies) of 106 | ok -> 107 | {ok, State}; 108 | {error, Reason} -> 109 | {error, Reason, State} 110 | end; 111 | {error, notfound} -> 112 | Robj = riak_object:new(State#state.bucket, Key, ValueGen()), 113 | case (State#state.client):put(Robj, State#state.replies) of 114 | ok -> 115 | {ok, State}; 116 | {error, Reason} -> 117 | {error, Reason, State} 118 | end 119 | end; 120 | run(delete, KeyGen, _ValueGen, State) -> 121 | case (State#state.client):delete(State#state.bucket, KeyGen(), State#state.replies) of 122 | ok -> 123 | {ok, State}; 124 | {error, notfound} -> 125 | {ok, State}; 126 | {error, Reason} -> 127 | {error, Reason, State} 128 | end. 129 | 130 | 131 | %% ==================================================================== 132 | %% Internal functions 133 | %% ==================================================================== 134 | 135 | ping_each([]) -> 136 | ok; 137 | ping_each([Node | Rest]) -> 138 | case net_adm:ping(Node) of 139 | pong -> 140 | ping_each(Rest); 141 | pang -> 142 | ?FAIL_MSG("Failed to ping node ~p\n", [Node]) 143 | end. 144 | -------------------------------------------------------------------------------- /src/basho_bench_driver_shortcut.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2012 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_driver_shortcut). 23 | 24 | -export([new/1, 25 | run/4]). 26 | -export([count_eleveldb_keys/1, calc_bkey_to_prefidxes/4]). 27 | 28 | -include("basho_bench.hrl"). 29 | 30 | -record(state, { id :: integer(), 31 | backend :: 'bitcask' | 'eleveldb' | 'hanoidb', 32 | backend_flags :: list(), 33 | data_dir :: string(), 34 | n_val :: integer(), 35 | ring :: term(), 36 | bucket :: binary(), 37 | store_riak_obj :: boolean(), 38 | idxes_to_do :: list(integer()), 39 | idx :: integer(), 40 | handle :: term()}). 41 | 42 | %% ==================================================================== 43 | %% API 44 | %% ==================================================================== 45 | 46 | new(Id) -> 47 | Backend = basho_bench_config:get(shortcut_backend), 48 | BackendFlags = basho_bench_config:get(shortcut_backend_flags), 49 | DataDir = basho_bench_config:get(shortcut_data_dir), 50 | os:cmd("mkdir -p " ++ DataDir), 51 | RingSize = basho_bench_config:get(shortcut_ring_creation_size), 52 | N = basho_bench_config:get(shortcut_n_val), 53 | Ring = riak_core_ring:fresh(RingSize, nonode), 54 | Bucket = basho_bench_config:get(shortcut_bucket), 55 | StoreObj = basho_bench_config:get(shortcut_store_riak_object, false), 56 | Idxes = [Idx || {Idx, _} <- riak_core_ring:all_owners(Ring)], 57 | Concurrent = basho_bench_config:get(concurrent), 58 | IdxParts = partition_work(Idxes, Concurrent), 59 | %% Id starts counting at 1 60 | MyIdxes = lists:nth(Id, IdxParts), 61 | 62 | {ok, rotate_idx(#state{id = Id, 63 | backend = Backend, 64 | backend_flags = BackendFlags, 65 | data_dir = DataDir, 66 | n_val = N, 67 | ring = Ring, 68 | bucket = Bucket, 69 | store_riak_obj = StoreObj, 70 | idxes_to_do = MyIdxes})}. 71 | 72 | run(put, KeyGen, ValueGen, S) -> 73 | try 74 | Key = filter_key_gen(KeyGen, S), 75 | Value = ValueGen(), 76 | do_put(Key, Value, S) 77 | catch 78 | throw:{stop, empty_keygen} -> 79 | ?DEBUG("Empty keygen\n", []), 80 | NewS = rotate_idx(S), 81 | do_put(filter_key_gen(KeyGen, NewS), ValueGen(), NewS) 82 | end. 83 | 84 | %% Private functions 85 | 86 | partition_work(L, Num) -> 87 | partition_work2(L, lists:duplicate(Num, [])). 88 | 89 | partition_work2([], Acc) -> 90 | [lists:reverse(L) || L <- Acc]; 91 | partition_work2([H|T], [First|Rest] = _Res) -> 92 | partition_work2(T, Rest ++ [[H|First]]). 93 | 94 | filter_key_gen(KeyGen, #state{ring = Ring, n_val = N, bucket = Bucket, 95 | idx = Idx} = S) -> 96 | Key = KeyGen(), 97 | %% case KeyGen() of 98 | %% {sext_pair, SextBKey, PlainKey} -> 99 | %% HashKey = PlainKey, 100 | %% Key = SextBKey, PlainKey; 101 | %% Plain -> 102 | %% HashKey = Key = Plain 103 | %% end, 104 | PrefIdxes = calc_bkey_to_prefidxes(Bucket, Key, Ring, N), 105 | case lists:member(Idx, PrefIdxes) of 106 | true -> 107 | Key; 108 | false -> 109 | filter_key_gen(KeyGen, S) 110 | end. 111 | 112 | rotate_idx(#state{idxes_to_do = []} = S) -> 113 | %% Borrow a trick from the key generator: we are really, really done now. 114 | stop_idx(S), 115 | throw({stop, empty_keygen}); 116 | rotate_idx(#state{backend = Backend, 117 | backend_flags = BackendFlags, 118 | data_dir = DataDir, 119 | idxes_to_do = [Idx|Idxes]} = S0) -> 120 | S1 = stop_idx(S0), 121 | basho_bench_keygen:reset_sequential_int_state(), 122 | Handle = start_idx(Backend, BackendFlags, DataDir, Idx), 123 | S1#state{idxes_to_do = Idxes, 124 | idx = Idx, 125 | handle = Handle}. 126 | 127 | stop_idx(#state{backend = Backend, handle = Handle} = S) -> 128 | try 129 | stop_backend(Backend, Handle) 130 | catch 131 | X:Y -> 132 | ?ERROR("Stopping Id ~p's handle ~p -> ~p ~p: ~p\n", 133 | [S#state.id, Handle, X, Y, erlang:get_stacktrace()]) 134 | end, 135 | S#state{handle = undefined}. 136 | 137 | start_idx(eleveldb, Flags0, DataDir, Idx) -> 138 | Flags = [{create_if_missing, true}|Flags0], 139 | {ok, Handle} = eleveldb:open(DataDir ++ "/" ++ integer_to_list(Idx), Flags), 140 | Handle; 141 | start_idx(bitcask, Flags0, DataDir, Idx) -> 142 | Flags = [read_write|Flags0], 143 | bitcask:open(DataDir ++ "/" ++ integer_to_list(Idx), Flags); 144 | start_idx(hanoidb, Flags, DataDir, Idx) -> 145 | {ok, Handle} = hanoidb:open(DataDir ++ "/" ++ integer_to_list(Idx), Flags), 146 | Handle. 147 | 148 | do_put(Key0, Value0, #state{backend = eleveldb, handle = Handle, 149 | bucket = Bucket} = S) -> 150 | {Key, Value} = make_riak_object_maybe(Bucket, Key0, Value0, S), 151 | %% TODO: add an option for put options? 152 | case eleveldb:put(Handle, Key, Value, []) of 153 | ok -> 154 | {ok, S}; 155 | {error, Reason} -> 156 | {error, Reason, S} 157 | end; 158 | do_put(Key0, Value0, #state{backend = bitcask, handle = Handle, 159 | bucket = Bucket} = S) -> 160 | {Key, Value} = make_riak_object_maybe(Bucket, Key0, Value0, S), 161 | case bitcask:put(Handle, Key, Value) of 162 | ok -> 163 | {ok, S}; 164 | {error, Reason} -> 165 | {error, Reason, S} 166 | end; 167 | do_put(Key0, Value0, #state{backend = hanoidb, handle = Handle, 168 | bucket = Bucket} = S) -> 169 | {Key, Value} = make_riak_object_maybe(Bucket, Key0, Value0, S), 170 | case hanoidb:put(Handle, Key, Value) of 171 | ok -> 172 | {ok, S}; 173 | {error, Reason} -> 174 | {error, Reason, S} 175 | end. 176 | 177 | stop_backend(_, undefined) -> 178 | ok; 179 | stop_backend(eleveldb, _Handle) -> 180 | %% Key = <<66:2048>>, 181 | %% ok = eleveldb:put(Handle, Key, <<>>, []), 182 | %% ok = eleveldb:delete(Handle, Key, [{sync, true}]), 183 | ok; 184 | stop_backend(bitcask, Handle) -> 185 | ok = bitcask:close(Handle); 186 | stop_backend(hanoidb, Handle) -> 187 | ok = hanoidb:close(Handle). 188 | 189 | count_eleveldb_keys(Dir) -> 190 | [{File, begin 191 | {ok, L1} = eleveldb:open(Dir ++ "/" ++ File, []), 192 | eleveldb:fold_keys(L1, fun(_, Acc) -> Acc + 1 end, 0, []) 193 | end} || File <- filelib:wildcard("*", Dir)]. 194 | 195 | make_riak_object_maybe(_Bucket, Key, Value, #state{store_riak_obj = false}) -> 196 | {Key, Value}; 197 | make_riak_object_maybe(Bucket, Key, Value, #state{store_riak_obj = true, 198 | backend = eleveldb}) -> 199 | new_object(sext:encode({o, Bucket, Key}), Bucket, Key, Value); 200 | make_riak_object_maybe(Bucket, Key, Value, #state{store_riak_obj = true, 201 | backend = bitcask}) -> 202 | new_object(term_to_binary({Bucket, Key}), Bucket, Key, Value); 203 | make_riak_object_maybe(Bucket, Key, Value, #state{store_riak_obj = true, 204 | backend = hanoidb}) -> 205 | new_object(sext:encode({o, Bucket, Key}), Bucket, Key, Value). 206 | 207 | new_object(EncodedKey, Bucket, Key, Value) -> 208 | %% MD stuff stolen from riak_kv_put_fsm.erl 209 | Now = erlang:now(), 210 | <> = basho_bench:md5(term_to_binary({node(), Now})), 211 | VT = riak_core_util:integer_to_list(HashAsNum,62), 212 | NewMD = dict:store(<<"X-Riak-VTag">>, VT, 213 | dict:store(<<"X-Riak-Last-Modified">>, Now, dict:new())), 214 | {EncodedKey, 215 | term_to_binary( 216 | riak_object:increment_vclock(riak_object:new(Bucket, Key, Value, 217 | NewMD), 218 | <<42:32/big>>))}. 219 | 220 | calc_bkey_to_prefidxes(Bucket, Key, RingSize, N) when is_integer(RingSize) -> 221 | calc_bkey_to_prefidxes(Bucket, Key, riak_core_ring:fresh(RingSize, nonode), 222 | N); 223 | calc_bkey_to_prefidxes(Bucket, Key, Ring, N) -> 224 | DocIdx = riak_core_util:chash_std_keyfun({Bucket, Key}), 225 | Preflist = lists:sublist(riak_core_ring:preflist(DocIdx, Ring), N), 226 | [I || {I, _} <- Preflist]. 227 | -------------------------------------------------------------------------------- /src/basho_bench_java_client.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench_java_client: Local API to remote Java client 4 | %% 5 | %% Copyright (c) 2011 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_java_client). 23 | 24 | -export([new/5, get/4, put/6, create_update/7, update/7, delete/4]). 25 | 26 | -define(TIMEOUT, 60*1000). 27 | 28 | %%% Ask the java node to create a new process, and link to it 29 | new(Node, Ip, Port, PBBuffer, Transport) -> 30 | erlang:send({factory, Node}, {self(), {Ip, Port, PBBuffer, Transport}}), 31 | 32 | receive 33 | Pid when is_pid(Pid) -> 34 | link(Pid), 35 | {ok, Pid} 36 | after ?TIMEOUT -> 37 | {error, timeout} 38 | end. 39 | 40 | get(Pid, Bucket, Key, R) -> 41 | Pid ! {self(), {get, [{bucket, Bucket}, {key, Key}, {r, R}]}}, 42 | receive 43 | {Pid, Res} -> 44 | ok 45 | end, 46 | Res. 47 | 48 | put(Pid, Bucket, Key, Value, W, DW) -> 49 | Pid ! {self(), {put, [{bucket, Bucket}, {key, Key}, {value, Value}, {w, W}, {dw, DW}]}}, 50 | 51 | receive 52 | {Pid, Res} -> 53 | ok 54 | end, 55 | Res. 56 | 57 | create_update(Pid, Bucket, Key, Value, R, W, DW) -> 58 | Pid ! {self(), {create_update, [{bucket, Bucket}, {key, Key}, {value, Value}, 59 | {r, R}, {w, W}, {dw, DW}]}}, 60 | 61 | receive 62 | {Pid, Res} -> 63 | ok 64 | end, 65 | Res. 66 | 67 | update(Pid, Bucket, Key, Value, R, W, DW) -> 68 | Pid ! {self(), {update, [{bucket, Bucket}, {key, Key}, {value, Value}, 69 | {r, R}, {w, W}, {dw, DW}]}}, 70 | 71 | receive 72 | {Pid, Res} -> 73 | ok 74 | end, 75 | Res. 76 | 77 | delete(Pid, Bucket, Key, RW) -> 78 | Pid ! {self(), {delete, [{bucket, Bucket}, {key, Key}, {r, RW}]}}, %%HACK to reuse GetArgs on java side, change 79 | receive 80 | {Pid, Res} -> 81 | ok 82 | end, 83 | Res. 84 | 85 | -------------------------------------------------------------------------------- /src/basho_bench_measurement.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_measurement). 23 | 24 | -behaviour(gen_server). 25 | 26 | %% API 27 | -export([start_link/0, 28 | run/0, 29 | take_measurement/1]). 30 | 31 | %% gen_server callbacks 32 | -export([init/1, handle_call/3, handle_cast/2, handle_info/2, 33 | terminate/2, code_change/3]). 34 | 35 | -record(state, { driver, 36 | driver_state, 37 | timer_refs = [] 38 | }). 39 | 40 | -include("basho_bench.hrl"). 41 | 42 | %% ==================================================================== 43 | %% API 44 | %% ==================================================================== 45 | 46 | start_link() -> 47 | gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). 48 | 49 | run() -> 50 | gen_server:cast(?MODULE, run). 51 | 52 | take_measurement(Measurement) -> 53 | gen_server:call(?MODULE, {take_measurement, Measurement}, infinity). 54 | 55 | %% ==================================================================== 56 | %% gen_server callbacks 57 | %% ==================================================================== 58 | 59 | init([]) -> 60 | %% Pull all config settings from environment 61 | Driver = basho_bench_config:get(measurement_driver), 62 | case catch(Driver:new()) of 63 | {ok, DriverState} -> 64 | State = #state { 65 | driver = Driver, 66 | driver_state = DriverState }, 67 | {ok, State}; 68 | Error -> 69 | ?FAIL_MSG("Failed to initialize driver ~p: ~p\n", [Driver, Error]), 70 | {stop, Error} 71 | end. 72 | 73 | handle_call(run, _From, State) -> 74 | NewState = restart_measurements(State), 75 | {reply, ok, NewState}; 76 | handle_call({take_measurement, Measurement}, _From, State) -> 77 | Driver = State#state.driver, 78 | DriverState = State#state.driver_state, 79 | {_Label, MeasurementTag} = Measurement, 80 | Result = (catch Driver:run(MeasurementTag, DriverState)), 81 | case Result of 82 | {ok, Value, NewDriverState} -> 83 | basho_bench_stats:op_complete(Measurement, ok, Value), 84 | {reply, ok, State#state { driver_state = NewDriverState}}; 85 | 86 | {error, Reason, NewDriverState} -> 87 | %% Driver encountered a recoverable error 88 | basho_bench_stats:op_complete(Measurement, {error, Reason}, 0), 89 | {reply, ok, State#state { driver_state = NewDriverState}}; 90 | 91 | {'EXIT', Reason} -> 92 | %% Driver crashed, generate a crash error and terminate. This will take down 93 | %% the corresponding measurement which will get restarted by the appropriate supervisor. 94 | basho_bench_stats:op_complete(Measurement, {error, crash}, 0), 95 | 96 | %% Give the driver a chance to cleanup 97 | (catch Driver:terminate({'EXIT', Reason}, DriverState)), 98 | 99 | ?DEBUG("Driver ~p crashed: ~p\n", [Driver, Reason]), 100 | {stop, crash, State}; 101 | 102 | {stop, Reason} -> 103 | %% Driver (or something within it) has requested that this measurement 104 | %% terminate cleanly. 105 | ?INFO("Driver ~p (~p) has requested stop: ~p\n", [Driver, self(), Reason]), 106 | 107 | %% Give the driver a chance to cleanup 108 | (catch Driver:terminate(normal, DriverState)), 109 | 110 | {stop, normal, State} 111 | end. 112 | 113 | 114 | handle_cast(run, State) -> 115 | NewState = restart_measurements(State), 116 | {noreply, NewState}. 117 | 118 | handle_info(Msg, State) -> 119 | io:format("[~s:~p] DEBUG - Msg: ~p~n", [?MODULE, ?LINE, Msg]), 120 | {noreply, State}. 121 | 122 | terminate(_Reason, _State) -> 123 | ok. 124 | 125 | code_change(_OldVsn, State, _Extra) -> 126 | {ok, State}. 127 | 128 | restart_measurements(State) -> 129 | [timer:cancel(X) || X <- State#state.timer_refs], 130 | F = 131 | fun({MeasurementTag, IntervalMS}) -> 132 | {ok, TRef} = timer:apply_interval(IntervalMS, ?MODULE, take_measurement, [{MeasurementTag, MeasurementTag}]), 133 | TRef; 134 | ({Label, MeasurementTag, IntervalMS}) -> 135 | {ok, TRef} = timer:apply_interval(IntervalMS, ?MODULE, take_measurement, [{Label, MeasurementTag}]), 136 | TRef 137 | end, 138 | TRefs = [F(X) || X <- basho_bench_config:get(measurements, [])], 139 | State#state { timer_refs = TRefs }. 140 | -------------------------------------------------------------------------------- /src/basho_bench_measurement_erlangvm.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench_measurement_erlangvm: Measurement Driver for Erlang VMs. 4 | %% 5 | %% Copyright (c) 2009 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_measurement_erlangvm). 23 | 24 | -export([new/0, 25 | run/2]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | -record(state, { 30 | nodes 31 | }). 32 | 33 | %% ==================================================================== 34 | %% API 35 | %% ==================================================================== 36 | 37 | new() -> 38 | %% Try to spin up net_kernel 39 | MyNode = basho_bench_config:get(mynode, [basho_bench, longnames]), 40 | case net_kernel:start(MyNode) of 41 | {ok, _} -> 42 | ?INFO("Net kernel started as ~p\n", [node()]); 43 | {error, {already_started, _}} -> 44 | ok; 45 | {error, Reason} -> 46 | ?FAIL_MSG("Failed to start net_kernel for ~p: ~p\n", [?MODULE, Reason]) 47 | end, 48 | 49 | Nodes = basho_bench_config:get(nodes), 50 | Cookie = basho_bench_config:get(cookie), 51 | 52 | %% Initialize cookie for each of the nodes 53 | [true = erlang:set_cookie(N, Cookie) || N <- Nodes], 54 | 55 | %% Try to ping each of the nodes 56 | ping_each(Nodes), 57 | 58 | {ok, #state{ nodes = Nodes }}. 59 | 60 | run(memory, State) -> 61 | %% Memory used: erlang:memory(total). 62 | F = fun(Node) -> 63 | rpc:call(Node, erlang, memory, [total]) 64 | end, 65 | Memory = lists:sum([F(X) || X <- State#state.nodes]), 66 | {ok, Memory, State}; 67 | 68 | run(cpu, State) -> 69 | %% CPU load: cpu_sup:avg1() / 256. 70 | F = fun(Node) -> 71 | rpc:call(Node, cpu_sup, avg1, []) / 256 * 100 72 | end, 73 | AvgLoad = trunc(lists:sum([F(X) || X <- State#state.nodes]) / length(State#state.nodes)), 74 | {ok, AvgLoad, State}; 75 | 76 | run(processes, State) -> 77 | %% processes: length(erlang:processes()). 78 | F = fun(Node) -> 79 | %% We're sending back the process list, which sucks, but 80 | %% not sure if there is a better way to do it. 81 | length(rpc:call(Node, erlang, processes, [])) 82 | end, 83 | Processes = lists:sum([F(X) || X <- State#state.nodes]), 84 | 85 | {ok, Processes, State}; 86 | 87 | run(filehandles, State) -> 88 | %% filehandles: list_to_integer(string:strip(string:strip(os:cmd("lsof -p" ++ os:getpid() ++ " | wc -l"), both), both, $\n)). 89 | F = fun(Node) -> 90 | %% We're sending back the process list, which sucks, but 91 | %% not sure if there is a better way to do it. 92 | Pid = rpc:call(Node, os, getpid, []), 93 | Cmd = io_lib:format("lsof -n -p ~p | wc -l", [Pid]), 94 | S1 = rpc:call(Node, os, cmd, [Cmd]), 95 | S2 = string:strip(S1, both), 96 | S3 = string:strip(S2, both, $\n), 97 | list_to_integer(S3) 98 | end, 99 | Filehandles = lists:sum([F(X) || X <- State#state.nodes]), 100 | {ok, Filehandles, State}; 101 | 102 | run(Measurement, _State) -> 103 | {unknown_measurement, Measurement}. 104 | 105 | ping_each([]) -> 106 | ok; 107 | ping_each([Node | Rest]) -> 108 | case net_adm:ping(Node) of 109 | pong -> 110 | ping_each(Rest); 111 | pang -> 112 | ?FAIL_MSG("Failed to ping node ~p\n", [Node]) 113 | end. 114 | -------------------------------------------------------------------------------- /src/basho_bench_stats_writer.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2014 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | %% HOWTO: 23 | %% 24 | %% * To run basho_bench with the default CSV writer, nothing needs to 25 | %% be done. But if wanting to override a former setting, then 26 | %% writing the following in the benchmark config file will switch 27 | %% the stats writer to CSV: 28 | %% 29 | %% {stats, {csv}}. 30 | %% 31 | %% * To run basho_bench with statistics sent to [Riemann][1], in the 32 | %% benchmark config file the following needs to be written: 33 | %% 34 | %% {stats, {riemann}}. 35 | %% 36 | %% This will, by default, try to connect to a Riemann server on 37 | %% localhost, port 5555, and will not set any TTL or tags. To 38 | %% configure the writer, an app config needs to be written. For 39 | %% that, one needs to add "-config app.config" (the filename can be 40 | %% anything) to escript_emu_args in rebar.config, recompile 41 | %% basho_bench, and add the necessary configuration to app.config, 42 | %% something along these lines: 43 | %% 44 | %% [ 45 | %% {katja, [ 46 | %% {host, "127.0.0.1"}, 47 | %% {port, 5555}, 48 | %% {transport, detect}, 49 | %% {pool, []}, 50 | %% {defaults, [{host, "myhost.local"}, 51 | %% {tags, ["basho_bench"]}, 52 | %% {ttl, 5.0}]} 53 | %% ]} 54 | %% ]. 55 | 56 | -module(basho_bench_stats_writer). 57 | 58 | -export([new/3, 59 | terminate/1, 60 | process_summary/5, 61 | report_error/3, 62 | report_latency/7]). 63 | 64 | -include("basho_bench.hrl"). 65 | 66 | new({csv}, Ops, Measurements) -> 67 | %% Setup output file handles for dumping periodic CSV of histogram results. 68 | [erlang:put({csv_file, X}, op_csv_file(X)) || X <- Ops], 69 | 70 | %% Setup output file handles for dumping periodic CSV of histogram results. 71 | [erlang:put({csv_file, X}, measurement_csv_file(X)) || X <- Measurements], 72 | 73 | %% Setup output file w/ counters for total requests, errors, etc. 74 | {ok, SummaryFile} = file:open("summary.csv", [raw, binary, write]), 75 | file:write(SummaryFile, <<"elapsed, window, total, successful, failed\n">>), 76 | 77 | %% Setup errors file w/counters for each error. Embedded commas likely 78 | %% in the error messages so quote the columns. 79 | {ok, ErrorsFile} = file:open("errors.csv", [raw, binary, write]), 80 | file:write(ErrorsFile, <<"\"error\",\"count\"\n">>), 81 | 82 | {SummaryFile, ErrorsFile}; 83 | new({riemann}, _, _) -> 84 | katja:start(). 85 | 86 | terminate({{csv}, {SummaryFile, ErrorsFile}}) -> 87 | [ok = file:close(F) || {{csv_file, _}, F} <- erlang:get()], 88 | ok = file:close(SummaryFile), 89 | ok = file:close(ErrorsFile), 90 | ok; 91 | terminate({{riemann}, _}) -> 92 | katja:stop(), 93 | ok. 94 | 95 | process_summary({{csv}, {SummaryFile, _ErrorsFile}}, 96 | Elapsed, Window, Oks, Errors) -> 97 | file:write(SummaryFile, 98 | io_lib:format("~w, ~w, ~w, ~w, ~w\n", 99 | [Elapsed, 100 | Window, 101 | Oks + Errors, 102 | Oks, 103 | Errors])); 104 | process_summary({{riemann}, _}, 105 | _Elapsed, _Window, Oks, Errors) -> 106 | katja:send_entities([{events, [[{service, "basho_bench summary ok"}, 107 | {metric, Oks}], 108 | [{service, "basho_bench summary errors"}, 109 | {metric, Errors}]]}]). 110 | 111 | report_error({{csv}, {_SummaryFile, ErrorsFile}}, 112 | Key, Count) -> 113 | file:write(ErrorsFile, 114 | io_lib:format("\"~w\",\"~w\"\n", 115 | [Key, Count])); 116 | report_error({{riemann}, _}, 117 | Key, Count) -> 118 | katja:send_event([{service, io_lib:format("basho_bench error for key ~p", [Key])}, 119 | {metric, Count}]). 120 | 121 | report_latency({{csv}, {_SummaryFile, _ErrorsFile}}, 122 | Elapsed, Window, Op, 123 | Stats, Errors, Units) -> 124 | case proplists:get_value(n, Stats) > 0 of 125 | true -> 126 | P = proplists:get_value(percentile, Stats), 127 | Line = io_lib:format("~w, ~w, ~w, ~w, ~.1f, ~w, ~w, ~w, ~w, ~w, ~w\n", 128 | [Elapsed, 129 | Window, 130 | Units, 131 | proplists:get_value(min, Stats), 132 | proplists:get_value(arithmetic_mean, Stats), 133 | proplists:get_value(median, Stats), 134 | proplists:get_value(95, P), 135 | proplists:get_value(99, P), 136 | proplists:get_value(999, P), 137 | proplists:get_value(max, Stats), 138 | Errors]); 139 | false -> 140 | ?WARN("No data for op: ~p\n", [Op]), 141 | Line = io_lib:format("~w, ~w, 0, 0, 0, 0, 0, 0, 0, 0, ~w\n", 142 | [Elapsed, 143 | Window, 144 | Errors]) 145 | end, 146 | file:write(erlang:get({csv_file, Op}), Line); 147 | report_latency({{riemann}, _}, 148 | _Elapsed, _Window, Op, 149 | Stats, Errors, Units) -> 150 | case proplists:get_value(n, Stats) > 0 of 151 | true -> 152 | katja:send_entities([{events, riemann_op_latencies(Op, Stats, Errors, Units)}]); 153 | false -> 154 | ?WARN("No data for op: ~p\n", [Op]) 155 | end. 156 | 157 | %% ==================================================================== 158 | %% Internal functions 159 | %% ==================================================================== 160 | 161 | op_csv_file({Label, _Op}) -> 162 | Fname = normalize_label(Label) ++ "_latencies.csv", 163 | {ok, F} = file:open(Fname, [raw, binary, write]), 164 | ok = file:write(F, <<"elapsed, window, n, min, mean, median, 95th, 99th, 99_9th, max, errors\n">>), 165 | F. 166 | 167 | measurement_csv_file({Label, _Op}) -> 168 | Fname = normalize_label(Label) ++ "_measurements.csv", 169 | {ok, F} = file:open(Fname, [raw, binary, write]), 170 | ok = file:write(F, <<"elapsed, window, n, min, mean, median, 95th, 99th, 99_9th, max, errors\n">>), 171 | F. 172 | 173 | normalize_label(Label) when is_list(Label) -> 174 | replace_special_chars(Label); 175 | normalize_label(Label) when is_binary(Label) -> 176 | normalize_label(binary_to_list(Label)); 177 | normalize_label(Label) when is_integer(Label) -> 178 | normalize_label(integer_to_list(Label)); 179 | normalize_label(Label) when is_atom(Label) -> 180 | normalize_label(atom_to_list(Label)); 181 | normalize_label(Label) when is_tuple(Label) -> 182 | Parts = [normalize_label(X) || X <- tuple_to_list(Label)], 183 | string:join(Parts, "-"). 184 | 185 | replace_special_chars([H|T]) when 186 | (H >= $0 andalso H =< $9) orelse 187 | (H >= $A andalso H =< $Z) orelse 188 | (H >= $a andalso H =< $z) -> 189 | [H|replace_special_chars(T)]; 190 | replace_special_chars([_|T]) -> 191 | [$-|replace_special_chars(T)]; 192 | replace_special_chars([]) -> 193 | []. 194 | 195 | riemann_op_latencies({Label, _Op}, Stats, Errors, Units) -> 196 | P = proplists:get_value(percentile, Stats), 197 | Service = normalize_label(Label), 198 | 199 | [[{service, io_lib:format("basho_bench op ~s latency min", [Service])}, 200 | {metric, proplists:get_value(min, Stats)}], 201 | [{service, io_lib:format("basho_bench op ~s latency max", [Service])}, 202 | {metric, proplists:get_value(max, Stats)}], 203 | [{service, io_lib:format("basho_bench op ~s latency mean", [Service])}, 204 | {metric, proplists:get_value(arithmetic_mean, Stats)}], 205 | [{service, io_lib:format("basho_bench op ~s latency median", [Service])}, 206 | {metric, proplists:get_value(median, Stats)}], 207 | [{service, io_lib:format("basho_bench op ~s latency 95%", [Service])}, 208 | {metric, proplists:get_value(95, P)}], 209 | [{service, io_lib:format("basho_bench op ~s latency 99%", [Service])}, 210 | {metric, proplists:get_value(99, P)}], 211 | [{service, io_lib:format("basho_bench op ~s latency 99.9%", [Service])}, 212 | {metric, proplists:get_value(999, P)}], 213 | [{service, io_lib:format("basho_bench op ~s #", [Service])}, 214 | {metric, Units}], 215 | [{service, io_lib:format("basho_bench op ~s error#", [Service])}, 216 | {metric, Errors}]]. 217 | -------------------------------------------------------------------------------- /src/basho_bench_stats_writer_csv.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2014 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | %% HOWTO: 23 | %% 24 | %% * To run basho_bench with the default CSV writer, nothing needs to 25 | %% be done. But if wanting to override a former setting, then 26 | %% writing the following in the benchmark config file will switch 27 | %% the stats writer to CSV: 28 | %% 29 | %% {stats, {csv}}. 30 | %%. 31 | 32 | -module(basho_bench_stats_writer_csv). 33 | 34 | -export([new/2, 35 | terminate/1, 36 | process_summary/5, 37 | report_error/3, 38 | report_latency/7]). 39 | 40 | -include("basho_bench.hrl"). 41 | 42 | new(Ops, Measurements) -> 43 | ?INFO("module=~s event=start stats_sink=csv\n", [?MODULE]), 44 | %% Setup output file handles for dumping periodic CSV of histogram results. 45 | [erlang:put({csv_file, X}, op_csv_file(X)) || X <- Ops], 46 | 47 | %% Setup output file handles for dumping periodic CSV of histogram results. 48 | [erlang:put({csv_file, X}, measurement_csv_file(X)) || X <- Measurements], 49 | 50 | %% Setup output file w/ counters for total requests, errors, etc. 51 | {ok, SummaryFile} = file:open("summary.csv", [raw, binary, write]), 52 | file:write(SummaryFile, <<"elapsed, window, total, successful, failed\n">>), 53 | 54 | %% Setup errors file w/counters for each error. Embedded commas likely 55 | %% in the error messages so quote the columns. 56 | {ok, ErrorsFile} = file:open("errors.csv", [raw, binary, write]), 57 | file:write(ErrorsFile, <<"\"error\",\"count\"\n">>), 58 | 59 | {SummaryFile, ErrorsFile}. 60 | 61 | terminate({SummaryFile, ErrorsFile}) -> 62 | ?INFO("module=~s event=stop stats_sink=csv\n", [?MODULE]), 63 | [ok = file:close(F) || {{csv_file, _}, F} <- erlang:get()], 64 | ok = file:close(SummaryFile), 65 | ok = file:close(ErrorsFile), 66 | ok. 67 | 68 | process_summary({SummaryFile, _ErrorsFile}, 69 | Elapsed, Window, Oks, Errors) -> 70 | file:write(SummaryFile, 71 | io_lib:format("~w, ~w, ~w, ~w, ~w\n", 72 | [Elapsed, 73 | Window, 74 | Oks + Errors, 75 | Oks, 76 | Errors])). 77 | 78 | report_error({_SummaryFile, ErrorsFile}, 79 | Key, Count) -> 80 | file:write(ErrorsFile, 81 | io_lib:format("\"~w\",\"~w\"\n", 82 | [Key, Count])). 83 | 84 | report_latency({_SummaryFile, _ErrorsFile}, 85 | Elapsed, Window, Op, 86 | Stats, Errors, Units) -> 87 | case proplists:get_value(n, Stats) > 0 of 88 | true -> 89 | P = proplists:get_value(percentile, Stats), 90 | Line = io_lib:format("~w, ~w, ~w, ~w, ~.1f, ~w, ~w, ~w, ~w, ~w, ~w\n", 91 | [Elapsed, 92 | Window, 93 | Units, 94 | proplists:get_value(min, Stats), 95 | proplists:get_value(arithmetic_mean, Stats), 96 | proplists:get_value(median, Stats), 97 | proplists:get_value(95, P), 98 | proplists:get_value(99, P), 99 | proplists:get_value(999, P), 100 | proplists:get_value(max, Stats), 101 | Errors]); 102 | false -> 103 | ?WARN("No data for op: ~p\n", [Op]), 104 | Line = io_lib:format("~w, ~w, 0, 0, 0, 0, 0, 0, 0, 0, ~w\n", 105 | [Elapsed, 106 | Window, 107 | Errors]) 108 | end, 109 | file:write(erlang:get({csv_file, Op}), Line). 110 | 111 | %% ==================================================================== 112 | %% Internal functions 113 | %% ==================================================================== 114 | 115 | op_csv_file({Label, _Op}) -> 116 | Fname = normalize_label(Label) ++ "_latencies.csv", 117 | {ok, F} = file:open(Fname, [raw, binary, write]), 118 | ok = file:write(F, <<"elapsed, window, n, min, mean, median, 95th, 99th, 99_9th, max, errors\n">>), 119 | F. 120 | 121 | measurement_csv_file({Label, _Op}) -> 122 | Fname = normalize_label(Label) ++ "_measurements.csv", 123 | {ok, F} = file:open(Fname, [raw, binary, write]), 124 | ok = file:write(F, <<"elapsed, window, n, min, mean, median, 95th, 99th, 99_9th, max, errors\n">>), 125 | F. 126 | 127 | normalize_label(Label) when is_list(Label) -> 128 | replace_special_chars(Label); 129 | normalize_label(Label) when is_binary(Label) -> 130 | normalize_label(binary_to_list(Label)); 131 | normalize_label(Label) when is_integer(Label) -> 132 | normalize_label(integer_to_list(Label)); 133 | normalize_label(Label) when is_atom(Label) -> 134 | normalize_label(atom_to_list(Label)); 135 | normalize_label(Label) when is_tuple(Label) -> 136 | Parts = [normalize_label(X) || X <- tuple_to_list(Label)], 137 | string:join(Parts, "-"). 138 | 139 | replace_special_chars([H|T]) when 140 | (H >= $0 andalso H =< $9) orelse 141 | (H >= $A andalso H =< $Z) orelse 142 | (H >= $a andalso H =< $z) -> 143 | [H|replace_special_chars(T)]; 144 | replace_special_chars([_|T]) -> 145 | [$-|replace_special_chars(T)]; 146 | replace_special_chars([]) -> 147 | []. 148 | 149 | -------------------------------------------------------------------------------- /src/basho_bench_stats_writer_riemann.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2014 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | %% HOWTO: 23 | %% 24 | %% * To run basho_bench with statistics sent to [Riemann][1], in the 25 | %% benchmark config file the following needs to be written: 26 | %% 27 | %% {stats, {riemann}}. 28 | %% 29 | %% This will, by default, try to connect to a Riemann server on 30 | %% localhost, port 5555, and will not set any TTL or tags. To 31 | %% configure the writer, an app config needs to be written. For 32 | %% that, one needs to add "-config app.config" (the filename can be 33 | %% anything) to escript_emu_args in rebar.config, recompile 34 | %% basho_bench, and add the necessary configuration to app.config, 35 | %% something along these lines: 36 | %% 37 | %% [ 38 | %% {katja, [ 39 | %% {host, "127.0.0.1"}, 40 | %% {port, 5555}, 41 | %% {transport, detect}, 42 | %% {pool, []}, 43 | %% {defaults, [{host, "myhost.local"}, 44 | %% {tags, ["basho_bench"]}, 45 | %% {ttl, 5.0}]} 46 | %% ]} 47 | %% ]. 48 | 49 | -module(basho_bench_stats_writer_riemann). 50 | 51 | -export([new/2, 52 | terminate/1, 53 | process_summary/5, 54 | report_error/3, 55 | report_latency/7]). 56 | 57 | -include("basho_bench.hrl"). 58 | 59 | new(_, _) -> 60 | ?INFO("module=~s event=start stats_sink=riemann\n", [?MODULE]), 61 | katja:start(). 62 | 63 | terminate(_) -> 64 | ?INFO("module=~s event=stop stats_sink=riemann\n", [?MODULE]), 65 | katja:stop(), 66 | ok. 67 | 68 | process_summary(_, _Elapsed, _Window, Oks, Errors) -> 69 | katja:send_entities([{events, [[{service, "basho_bench summary ok"}, 70 | {metric, Oks}], 71 | [{service, "basho_bench summary errors"}, 72 | {metric, Errors}]]}]). 73 | 74 | report_error(_, Key, Count) -> 75 | katja:send_event([{service, io_lib:format("basho_bench error for key ~p", [Key])}, 76 | {metric, Count}]). 77 | 78 | report_latency(_, _Elapsed, _Window, Op, 79 | Stats, Errors, Units) -> 80 | case proplists:get_value(n, Stats) > 0 of 81 | true -> 82 | katja:send_entities([{events, riemann_op_latencies(Op, Stats, Errors, Units)}]); 83 | false -> 84 | ?WARN("No data for op: ~p\n", [Op]) 85 | end. 86 | 87 | %% ==================================================================== 88 | %% Internal functions 89 | %% ==================================================================== 90 | 91 | normalize_label(Label) when is_list(Label) -> 92 | replace_special_chars(Label); 93 | normalize_label(Label) when is_binary(Label) -> 94 | normalize_label(binary_to_list(Label)); 95 | normalize_label(Label) when is_integer(Label) -> 96 | normalize_label(integer_to_list(Label)); 97 | normalize_label(Label) when is_atom(Label) -> 98 | normalize_label(atom_to_list(Label)); 99 | normalize_label(Label) when is_tuple(Label) -> 100 | Parts = [normalize_label(X) || X <- tuple_to_list(Label)], 101 | string:join(Parts, "-"). 102 | 103 | replace_special_chars([H|T]) when 104 | (H >= $0 andalso H =< $9) orelse 105 | (H >= $A andalso H =< $Z) orelse 106 | (H >= $a andalso H =< $z) -> 107 | [H|replace_special_chars(T)]; 108 | replace_special_chars([_|T]) -> 109 | [$-|replace_special_chars(T)]; 110 | replace_special_chars([]) -> 111 | []. 112 | 113 | riemann_op_latencies({Label, _Op}, Stats, Errors, Units) -> 114 | P = proplists:get_value(percentile, Stats), 115 | Service = normalize_label(Label), 116 | 117 | [[{service, io_lib:format("basho_bench op ~s latency min", [Service])}, 118 | {metric, proplists:get_value(min, Stats)}], 119 | [{service, io_lib:format("basho_bench op ~s latency max", [Service])}, 120 | {metric, proplists:get_value(max, Stats)}], 121 | [{service, io_lib:format("basho_bench op ~s latency mean", [Service])}, 122 | {metric, proplists:get_value(arithmetic_mean, Stats)}], 123 | [{service, io_lib:format("basho_bench op ~s latency median", [Service])}, 124 | {metric, proplists:get_value(median, Stats)}], 125 | [{service, io_lib:format("basho_bench op ~s latency 95%", [Service])}, 126 | {metric, proplists:get_value(95, P)}], 127 | [{service, io_lib:format("basho_bench op ~s latency 99%", [Service])}, 128 | {metric, proplists:get_value(99, P)}], 129 | [{service, io_lib:format("basho_bench op ~s latency 99.9%", [Service])}, 130 | {metric, proplists:get_value(999, P)}], 131 | [{service, io_lib:format("basho_bench op ~s #", [Service])}, 132 | {metric, Units}], 133 | [{service, io_lib:format("basho_bench op ~s error#", [Service])}, 134 | {metric, Errors}]]. 135 | -------------------------------------------------------------------------------- /src/basho_bench_sup.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_sup). 23 | 24 | -behaviour(supervisor). 25 | 26 | %% API 27 | -export([start_link/0, 28 | workers/0, 29 | stop_child/1]). 30 | 31 | %% Supervisor callbacks 32 | -export([init/1]). 33 | 34 | -include("basho_bench.hrl"). 35 | 36 | %% Helper macro for declaring children of supervisor 37 | -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). 38 | 39 | %% =================================================================== 40 | %% API functions 41 | %% =================================================================== 42 | 43 | start_link() -> 44 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 45 | 46 | workers() -> 47 | [Pid || {_Id, Pid, worker, [basho_bench_worker]} <- supervisor:which_children(?MODULE)]. 48 | 49 | stop_child(Id) -> 50 | ok = supervisor:terminate_child(?MODULE, Id), 51 | ok = supervisor:delete_child(?MODULE, Id). 52 | 53 | 54 | %% =================================================================== 55 | %% Supervisor callbacks 56 | %% =================================================================== 57 | 58 | init([]) -> 59 | %% Get the number concurrent workers we're expecting and generate child 60 | %% specs for each 61 | 62 | %% intentionally left in to show where worker profiling start/stop calls go. 63 | %% eprof:start(), 64 | %% eprof:start_profiling([self()]), 65 | Workers = worker_specs(basho_bench_config:get(concurrent), []), 66 | MeasurementDriver = 67 | case basho_bench_config:get(measurement_driver, undefined) of 68 | undefined -> []; 69 | _Driver -> [?CHILD(basho_bench_measurement, worker)] 70 | end, 71 | 72 | {ok, {{one_for_one, 5, 10}, 73 | [?CHILD(basho_bench_stats, worker)] ++ 74 | Workers ++ 75 | MeasurementDriver 76 | }}. 77 | 78 | %% =================================================================== 79 | %% Internal functions 80 | %% =================================================================== 81 | 82 | worker_specs(0, Acc) -> 83 | Acc; 84 | worker_specs(Count, Acc) -> 85 | Id = list_to_atom(lists:concat(['basho_bench_worker_', Count])), 86 | Spec = {Id, {basho_bench_worker, start_link, [Id, Count]}, 87 | permanent, 5000, worker, [basho_bench_worker]}, 88 | worker_specs(Count-1, [Spec | Acc]). 89 | -------------------------------------------------------------------------------- /src/basho_bench_valgen.erl: -------------------------------------------------------------------------------- 1 | %% ------------------------------------------------------------------- 2 | %% 3 | %% basho_bench: Benchmarking Suite 4 | %% 5 | %% Copyright (c) 2009-2010 Basho Techonologies 6 | %% 7 | %% This file is provided to you under the Apache License, 8 | %% Version 2.0 (the "License"); you may not use this file 9 | %% except in compliance with the License. You may obtain 10 | %% a copy of the License at 11 | %% 12 | %% http://www.apache.org/licenses/LICENSE-2.0 13 | %% 14 | %% Unless required by applicable law or agreed to in writing, 15 | %% software distributed under the License is distributed on an 16 | %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | %% KIND, either express or implied. See the License for the 18 | %% specific language governing permissions and limitations 19 | %% under the License. 20 | %% 21 | %% ------------------------------------------------------------------- 22 | -module(basho_bench_valgen). 23 | 24 | -export([new/2, 25 | dimension/2]). 26 | 27 | -include("basho_bench.hrl"). 28 | 29 | %% ==================================================================== 30 | %% API 31 | %% ==================================================================== 32 | 33 | new({fixed_bin, Size}, Id) 34 | when is_integer(Size), Size >= 0 -> 35 | Source = init_source(Id), 36 | fun() -> data_block(Source, Size) end; 37 | new({fixed_bin, Size, Val}, _Id) 38 | when is_integer(Size), Size >= 0, is_integer(Val), Val >= 0, Val =< 255 -> 39 | Data = list_to_binary(lists:duplicate(Size, Val)), 40 | fun() -> Data end; 41 | new({fixed_char, Size}, _Id) 42 | when is_integer(Size), Size >= 0 -> 43 | fun() -> list_to_binary(lists:map(fun (_) -> random:uniform(95)+31 end, lists:seq(1,Size))) end; 44 | new({exponential_bin, MinSize, Mean}, Id) 45 | when is_integer(MinSize), MinSize >= 0, is_number(Mean), Mean > 0 -> 46 | Source = init_source(Id), 47 | fun() -> data_block(Source, MinSize + trunc(basho_bench_stats:exponential(1 / Mean))) end; 48 | new({uniform_bin, MinSize, MaxSize}, Id) 49 | when is_integer(MinSize), is_integer(MaxSize), MinSize < MaxSize -> 50 | Source = init_source(Id), 51 | Diff = MaxSize - MinSize, 52 | fun() -> data_block(Source, MinSize + random:uniform(Diff)) end; 53 | new({function, Module, Function, Args}, Id) 54 | when is_atom(Module), is_atom(Function), is_list(Args) -> 55 | case code:ensure_loaded(Module) of 56 | {module, Module} -> 57 | erlang:apply(Module, Function, [Id] ++ Args); 58 | _Error -> 59 | ?FAIL_MSG("Could not find valgen function: ~p:~p\n", [Module, Function]) 60 | end; 61 | new({uniform_int, MaxVal}, _Id) 62 | when is_integer(MaxVal), MaxVal >= 1 -> 63 | fun() -> random:uniform(MaxVal) end; 64 | new({uniform_int, MinVal, MaxVal}, _Id) 65 | when is_integer(MinVal), is_integer(MaxVal), MaxVal > MinVal -> 66 | fun() -> random:uniform(MinVal, MaxVal) end; 67 | new(Other, _Id) -> 68 | ?FAIL_MSG("Invalid value generator requested: ~p\n", [Other]). 69 | 70 | dimension({fixed_bin, Size}, KeyDimension) -> 71 | Size * KeyDimension; 72 | dimension(_Other, _) -> 73 | 0.0. 74 | 75 | 76 | 77 | %% ==================================================================== 78 | %% Internal Functions 79 | %% ==================================================================== 80 | 81 | -define(TAB, valgen_bin_tab). 82 | 83 | init_source(Id) -> 84 | init_source(Id, basho_bench_config:get(?VAL_GEN_BLOB_CFG, undefined)). 85 | 86 | init_source(1, undefined) -> 87 | SourceSz = basho_bench_config:get(?VAL_GEN_SRC_SIZE, 96*1048576), 88 | ?INFO("Random source: calling crypto:rand_bytes(~w) (override with the '~w' config option\n", [SourceSz, ?VAL_GEN_SRC_SIZE]), 89 | Bytes = crypto:rand_bytes(SourceSz), 90 | try 91 | ?TAB = ets:new(?TAB, [public, named_table]), 92 | true = ets:insert(?TAB, {x, Bytes}) 93 | catch _:_ -> rerunning_id_1_init_source_table_already_exists 94 | end, 95 | ?INFO("Random source: finished crypto:rand_bytes(~w)\n", [SourceSz]), 96 | {?VAL_GEN_SRC_SIZE, SourceSz, Bytes}; 97 | init_source(_Id, undefined) -> 98 | [{_, Bytes}] = ets:lookup(?TAB, x), 99 | {?VAL_GEN_SRC_SIZE, size(Bytes), Bytes}; 100 | init_source(Id, Path) -> 101 | {Path, {ok, Bin}} = {Path, file:read_file(Path)}, 102 | if Id == 1 -> ?DEBUG("path source ~p ~p\n", [size(Bin), Path]); 103 | true -> ok 104 | end, 105 | {?VAL_GEN_BLOB_CFG, size(Bin), Bin}. 106 | 107 | data_block({SourceCfg, SourceSz, Source}, BlockSize) -> 108 | case SourceSz - BlockSize > 0 of 109 | true -> 110 | Offset = random:uniform(SourceSz - BlockSize), 111 | <<_:Offset/bytes, Slice:BlockSize/bytes, _Rest/binary>> = Source, 112 | Slice; 113 | false -> 114 | ?WARN("~p is too small ~p < ~p\n", 115 | [SourceCfg, SourceSz, BlockSize]), 116 | Source 117 | end. 118 | -------------------------------------------------------------------------------- /src/basho_uuid.erl: -------------------------------------------------------------------------------- 1 | % Copyright (c) 2008, Travis Vachon 2 | % All rights reserved. 3 | % 4 | % Redistribution and use in source and binary forms, with or without 5 | % modification, are permitted provided that the following conditions are 6 | % met: 7 | % 8 | % * Redistributions of source code must retain the above copyright 9 | % notice, this list of conditions and the following disclaimer. 10 | % 11 | % * Redistributions in binary form must reproduce the above copyright 12 | % notice, this list of conditions and the following disclaimer in the 13 | % documentation and/or other materials provided with the distribution. 14 | % 15 | % * Neither the name of the author nor the names of its contributors 16 | % may be used to endorse or promote products derived from this 17 | % software without specific prior written permission. 18 | % 19 | % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | % "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | % LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | % A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | % OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | % SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | % TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | % PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | % LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | % NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | % SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | % 31 | -module(basho_uuid). 32 | -export([v4/0, to_string/1, get_parts/1, to_binary/1]). 33 | 34 | % Generates a random binary UUID. 35 | v4() -> 36 | v4(random:uniform(round(math:pow(2, 48))) - 1, random:uniform(round(math:pow(2, 12))) - 1, random:uniform(round(math:pow(2, 32))) - 1, random:uniform(round(math:pow(2, 30))) - 1). 37 | v4(R1, R2, R3, R4) -> 38 | <>. 39 | 40 | % Returns a string representation of a binary UUID. 41 | to_string(U) -> 42 | lists:flatten(io_lib:format("~8.16.0b-~4.16.0b-~4.16.0b-~2.16.0b~2.16.0b-~12.16.0b", get_parts(U))). 43 | 44 | % Returns the 32, 16, 16, 8, 8, 48 parts of a binary UUID. 45 | get_parts(<>) -> 46 | [TL, TM, THV, CSR, CSL, N]. 47 | 48 | % Converts a UUID string in the format of 550e8400-e29b-41d4-a716-446655440000 49 | % (with or without the dashes) to binary. 50 | to_binary(U)-> 51 | convert(lists:filter(fun(Elem) -> Elem /= $- end, U), []). 52 | 53 | % Converts a list of pairs of hex characters (00-ff) to bytes. 54 | convert([], Acc)-> 55 | list_to_binary(lists:reverse(Acc)); 56 | convert([X, Y | Tail], Acc)-> 57 | {ok, [Byte], _} = io_lib:fread("~16u", [X, Y]), 58 | convert(Tail, [Byte | Acc]). 59 | -------------------------------------------------------------------------------- /src/voxer_gen1.erl: -------------------------------------------------------------------------------- 1 | -module(voxer_gen1). 2 | -compile(export_all). 3 | 4 | inserter_keygen2(Id, InsertsPerSec) -> 5 | fun() -> do_inserter2(Id, InsertsPerSec) end. 6 | 7 | do_inserter2(Id, InsertsPerSec) -> 8 | Workers = basho_bench_config:get(concurrent), 9 | {Ts, Remaining} = case erlang:get(insert_ts) of 10 | undefined -> 11 | {A, B, _} = os:timestamp(), 12 | {(A * 1000000) + B, InsertsPerSec - Id}; 13 | {Ts0, 0} -> 14 | {Ts0+1, InsertsPerSec - Id}; 15 | {Ts0, R0} -> 16 | {Ts0, R0} 17 | end, 18 | Suffix = random:uniform(InsertsPerSec * 10000), 19 | erlang:put(insert_ts, {Ts, Remaining-Workers}), 20 | [integer_to_list(Ts), $_, integer_to_list(Suffix)]. 21 | 22 | 23 | inserter_keygen(Id, InsertsPerSec) -> 24 | fun() -> do_inserter(Id, InsertsPerSec) end. 25 | 26 | do_inserter(_Id, InsertsPerSec) -> 27 | {Ts, Remaining} = case erlang:get(insert_ts) of 28 | undefined -> 29 | {A, B, _} = os:timestamp(), 30 | {(A * 1000000) + B, InsertsPerSec}; 31 | {Ts0, 0} -> 32 | {Ts0+1, InsertsPerSec}; 33 | {Ts0, R0} -> 34 | {Ts0, R0} 35 | end, 36 | Suffix = random:uniform(InsertsPerSec * 10000), 37 | erlang:put(insert_ts, {Ts, Remaining-1}), 38 | [integer_to_list(Ts), $_, integer_to_list(Suffix)]. 39 | -------------------------------------------------------------------------------- /tests/.keepme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/basho/basho_bench/aa66398bb6a91645dbb97e91a236f3cdcd1f188f/tests/.keepme --------------------------------------------------------------------------------