1#!/usr/bin/env bash
2# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3# REQUIRE: benchmark.sh exists in the current directory
4# After execution of this script, log files are generated in $output_dir.
5# report.txt provides a high level statistics
6
7# This should be run from the parent of the tools directory. The command line is:
8#   [$env_vars] tools/run_flash_bench.sh [list-of-threads]
9#
10# This runs a sequence of tests in the following sequence:
11#   step 1) load - bulkload, compact, fillseq, overwrite
12#   step 2) read-only for each number of threads
13#   step 3) read-write for each number of threads
14#   step 4) merge for each number of threads
15#
16# The list of threads is optional and when not set is equivalent to "24".
17# Were list-of-threads specified as "1 2 4" then the tests in steps 2, 3 and
18# 4 above would be repeated for 1, 2 and 4 threads. The tests in step 1 are
19# only run for 1 thread.
20
21# Test output is written to $OUTPUT_DIR, currently /tmp/output. The performance
22# summary is in $OUTPUT_DIR/report.txt. There is one file in $OUTPUT_DIR per
23# test and the tests are listed below.
24#
25# The environment variables are also optional. The variables are:
26#
27#   NKEYS         - number of key/value pairs to load
28#   BG_MBWRITEPERSEC - write rate limit in MB/second for tests in which
29#                   there is one thread doing writes and stats are
30#                   reported for read threads. "BG" stands for background.
31#                   If this is too large then the non-writer threads can get
32#                   starved. This is used for the "readwhile" tests.
33#   FG_MBWRITEPERSEC - write rate limit in MB/second for tests like overwrite
34#                   where stats are reported for the write threads.
35#   NSECONDS      - number of seconds for which to run each test in steps 2,
36#                   3 and 4. There are currently 15 tests in those steps and
37#                   they are repeated for each entry in list-of-threads so
38#                   this variable lets you control the total duration to
39#                   finish the benchmark.
40#   RANGE_LIMIT   - the number of rows to read per range query for tests that
41#                   do range queries.
42#   VAL_SIZE      - the length of the value in the key/value pairs loaded.
43#                   You can estimate the size of the test database from this,
44#                   NKEYS and the compression rate (--compression_ratio) set
45#                   in tools/benchmark.sh
46#   BLOCK_LENGTH  - value for db_bench --block_size
47#   CACHE_BYTES   - the size of the RocksDB block cache in bytes
48#   DATA_DIR      - directory in which to create database files
49#   LOG_DIR       - directory in which to create WAL files, may be the same
50#                   as DATA_DIR
51#   DO_SETUP      - when set to 0 then a backup of the database is copied from
52#                   $DATA_DIR.bak to $DATA_DIR and the load tests from step 1
53#                   The WAL directory is also copied from a backup if
54#                   DATA_DIR != LOG_DIR. This allows tests from steps 2, 3, 4
55#                   to be repeated faster.
56#   SAVE_SETUP    - saves a copy of the database at the end of step 1 to
57#                   $DATA_DIR.bak. When LOG_DIR != DATA_DIR then it is copied
58#                   to $LOG_DIR.bak.
59#   SKIP_LOW_PRI_TESTS - skip some of the tests which aren't crucial for getting
60#                   actionable benchmarking data (look for keywords "bulkload",
61#                   "sync=1", and "while merging").
62#
63
64# Size constants
65K=1024
66M=$((1024 * K))
67G=$((1024 * M))
68
69num_keys=${NKEYS:-$((1 * G))}
70# write rate for readwhile... tests
71bg_mbwps=${BG_MBWRITEPERSEC:-4}
72# write rate for tests other than readwhile, 0 means no limit
73fg_mbwps=${FG_MBWRITEPERSEC:-0}
74duration=${NSECONDS:-$((60 * 60))}
75nps=${RANGE_LIMIT:-10}
76vs=${VAL_SIZE:-400}
77cs=${CACHE_BYTES:-$(( 1 * G ))}
78bs=${BLOCK_LENGTH:-8192}
79
80# If no command line arguments then run for 24 threads.
81if [[ $# -eq 0 ]]; then
82  nthreads=( 24 )
83else
84  nthreads=( "$@" )
85fi
86
87for num_thr in "${nthreads[@]}" ; do
88  echo Will run for $num_thr threads
89done
90
91# Update these parameters before execution !!!
92db_dir=${DATA_DIR:-"/tmp/rocksdb/"}
93wal_dir=${LOG_DIR:-"/tmp/rocksdb/"}
94
95do_setup=${DO_SETUP:-1}
96save_setup=${SAVE_SETUP:-0}
97
98# By default we'll run all the tests. Set this to skip a set of tests which
99# aren't critical for getting key metrics.
100skip_low_pri_tests=${SKIP_LOW_PRI_TESTS:-0}
101
102if [[ $skip_low_pri_tests == 1 ]]; then
103  echo "Skipping some non-critical tests because SKIP_LOW_PRI_TESTS is set."
104fi
105
106output_dir="${TMPDIR:-/tmp}/output"
107
108ARGS="\
109OUTPUT_DIR=$output_dir \
110NUM_KEYS=$num_keys \
111DB_DIR=$db_dir \
112WAL_DIR=$wal_dir \
113VALUE_SIZE=$vs \
114BLOCK_SIZE=$bs \
115CACHE_SIZE=$cs"
116
117mkdir -p $output_dir
118echo -e "ops/sec\tmb/sec\tSize-GB\tL0_GB\tSum_GB\tW-Amp\tW-MB/s\tusec/op\tp50\tp75\tp99\tp99.9\tp99.99\tUptime\tStall-time\tStall%\tTest" \
119  > $output_dir/report.txt
120
121# Notes on test sequence:
122#   step 1) Setup database via sequential fill followed by overwrite to fragment it.
123#           Done without setting DURATION to make sure that overwrite does $num_keys writes
124#   step 2) read-only tests for all levels of concurrency requested
125#   step 3) non read-only tests for all levels of concurrency requested
126#   step 4) merge tests for all levels of concurrency requested. These must come last.
127
128###### Setup the database
129
130if [[ $do_setup != 0 ]]; then
131  echo Doing setup
132
133  if [[ $skip_low_pri_tests != 1 ]]; then
134    # Test 1: bulk load
135    env $ARGS ./tools/benchmark.sh bulkload
136  fi
137
138  # Test 2a: sequential fill with large values to get peak ingest
139  #          adjust NUM_KEYS given the use of larger values
140  env $ARGS BLOCK_SIZE=$((1 * M)) VALUE_SIZE=$((32 * K)) NUM_KEYS=$(( num_keys / 64 )) \
141       ./tools/benchmark.sh fillseq_disable_wal
142
143  # Test 2b: sequential fill with the configured value size
144  env $ARGS ./tools/benchmark.sh fillseq_disable_wal
145
146  # Test 2c: same as 2a, but with WAL being enabled.
147  env $ARGS BLOCK_SIZE=$((1 * M)) VALUE_SIZE=$((32 * K)) NUM_KEYS=$(( num_keys / 64 )) \
148       ./tools/benchmark.sh fillseq_enable_wal
149
150  # Test 2d: same as 2b, but with WAL being enabled.
151  env $ARGS ./tools/benchmark.sh fillseq_enable_wal
152
153  # Test 3: single-threaded overwrite
154  env $ARGS NUM_THREADS=1 DB_BENCH_NO_SYNC=1 ./tools/benchmark.sh overwrite
155
156else
157  echo Restoring from backup
158
159  rm -rf $db_dir
160
161  if [ ! -d ${db_dir}.bak ]; then
162    echo Database backup does not exist at ${db_dir}.bak
163    exit -1
164  fi
165
166  echo Restore database from ${db_dir}.bak
167  cp -p -r ${db_dir}.bak $db_dir
168
169  if [[ $db_dir != $wal_dir ]]; then
170    rm -rf $wal_dir
171
172    if [ ! -d ${wal_dir}.bak ]; then
173      echo WAL backup does not exist at ${wal_dir}.bak
174      exit -1
175    fi
176
177    echo Restore WAL from ${wal_dir}.bak
178    cp -p -r ${wal_dir}.bak $wal_dir
179  fi
180fi
181
182if [[ $save_setup != 0 ]]; then
183  echo Save database to ${db_dir}.bak
184  cp -p -r $db_dir ${db_dir}.bak
185
186  if [[ $db_dir != $wal_dir ]]; then
187    echo Save WAL to ${wal_dir}.bak
188    cp -p -r $wal_dir ${wal_dir}.bak
189  fi
190fi
191
192###### Read-only tests
193
194for num_thr in "${nthreads[@]}" ; do
195  # Test 4: random read
196  env $ARGS DURATION=$duration NUM_THREADS=$num_thr ./tools/benchmark.sh readrandom
197
198  # Test 5: random range scans
199  env $ARGS DURATION=$duration NUM_THREADS=$num_thr NUM_NEXTS_PER_SEEK=$nps \
200    ./tools/benchmark.sh fwdrange
201
202  # Test 6: random reverse range scans
203  env $ARGS DURATION=$duration NUM_THREADS=$num_thr NUM_NEXTS_PER_SEEK=$nps \
204    ./tools/benchmark.sh revrange
205done
206
207###### Non read-only tests
208
209for num_thr in "${nthreads[@]}" ; do
210  # Test 7: overwrite with sync=0
211  env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$fg_mbwps \
212    DB_BENCH_NO_SYNC=1 ./tools/benchmark.sh overwrite
213
214  if [[ $skip_low_pri_tests != 1 ]]; then
215    # Test 8: overwrite with sync=1
216    env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$fg_mbwps \
217      ./tools/benchmark.sh overwrite
218  fi
219
220  # Test 9: random update with sync=0
221  env $ARGS DURATION=$duration NUM_THREADS=$num_thr DB_BENCH_NO_SYNC=1 \
222      ./tools/benchmark.sh updaterandom
223
224  if [[ $skip_low_pri_tests != 1 ]]; then
225    # Test 10: random update with sync=1
226   env $ARGS DURATION=$duration NUM_THREADS=$num_thr ./tools/benchmark.sh updaterandom
227  fi
228
229  # Test 11: random read while writing
230  env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$bg_mbwps \
231    DB_BENCH_NO_SYNC=1 ./tools/benchmark.sh readwhilewriting
232
233  # Test 12: range scan while writing
234  env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$bg_mbwps \
235    DB_BENCH_NO_SYNC=1 NUM_NEXTS_PER_SEEK=$nps ./tools/benchmark.sh fwdrangewhilewriting
236
237  # Test 13: reverse range scan while writing
238  env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$bg_mbwps \
239    DB_BENCH_NO_SYNC=1 NUM_NEXTS_PER_SEEK=$nps ./tools/benchmark.sh revrangewhilewriting
240done
241
242###### Merge tests
243
244for num_thr in "${nthreads[@]}" ; do
245  # Test 14: random merge with sync=0
246  env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$fg_mbwps \
247    DB_BENCH_NO_SYNC=1 ./tools/benchmark.sh mergerandom
248
249  if [[ $skip_low_pri_tests != 1 ]]; then
250    # Test 15: random merge with sync=1
251    env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$fg_mbwps \
252      ./tools/benchmark.sh mergerandom
253
254    # Test 16: random read while merging
255    env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$bg_mbwps \
256      DB_BENCH_NO_SYNC=1 ./tools/benchmark.sh readwhilemerging
257
258    # Test 17: range scan while merging
259    env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$bg_mbwps \
260      DB_BENCH_NO_SYNC=1 NUM_NEXTS_PER_SEEK=$nps ./tools/benchmark.sh fwdrangewhilemerging
261
262    # Test 18: reverse range scan while merging
263    env $ARGS DURATION=$duration NUM_THREADS=$num_thr MB_WRITE_PER_SEC=$bg_mbwps \
264      DB_BENCH_NO_SYNC=1 NUM_NEXTS_PER_SEEK=$nps ./tools/benchmark.sh revrangewhilemerging
265  fi
266done
267
268###### Universal compaction tests.
269
270# Use a single thread to reduce the variability in the benchmark.
271env $ARGS COMPACTION_TEST=1 NUM_THREADS=1 ./tools/benchmark.sh universal_compaction
272
273if [[ $skip_low_pri_tests != 1 ]]; then
274  echo bulkload > $output_dir/report2.txt
275  head -1 $output_dir/report.txt >> $output_dir/report2.txt
276  grep bulkload $output_dir/report.txt >> $output_dir/report2.txt
277fi
278
279echo fillseq_wal_disabled >> $output_dir/report2.txt
280head -1 $output_dir/report.txt >> $output_dir/report2.txt
281grep fillseq.wal_disabled $output_dir/report.txt >> $output_dir/report2.txt
282
283echo fillseq_wal_enabled >> $output_dir/report2.txt
284head -1 $output_dir/report.txt >> $output_dir/report2.txt
285grep fillseq.wal_enabled $output_dir/report.txt >> $output_dir/report2.txt
286
287echo overwrite sync=0 >> $output_dir/report2.txt
288head -1 $output_dir/report.txt >> $output_dir/report2.txt
289grep overwrite $output_dir/report.txt | grep \.s0  >> $output_dir/report2.txt
290
291if [[ $skip_low_pri_tests != 1 ]]; then
292  echo overwrite sync=1 >> $output_dir/report2.txt
293  head -1 $output_dir/report.txt >> $output_dir/report2.txt
294  grep overwrite $output_dir/report.txt | grep \.s1  >> $output_dir/report2.txt
295fi
296
297echo updaterandom sync=0 >> $output_dir/report2.txt
298head -1 $output_dir/report.txt >> $output_dir/report2.txt
299grep updaterandom $output_dir/report.txt | grep \.s0 >> $output_dir/report2.txt
300
301if [[ $skip_low_pri_tests != 1 ]]; then
302  echo updaterandom sync=1 >> $output_dir/report2.txt
303  head -1 $output_dir/report.txt >> $output_dir/report2.txt
304  grep updaterandom $output_dir/report.txt | grep \.s1 >> $output_dir/report2.txt
305fi
306
307echo mergerandom sync=0 >> $output_dir/report2.txt
308head -1 $output_dir/report.txt >> $output_dir/report2.txt
309grep mergerandom $output_dir/report.txt | grep \.s0 >> $output_dir/report2.txt
310
311if [[ $skip_low_pri_tests != 1 ]]; then
312  echo mergerandom sync=1 >> $output_dir/report2.txt
313  head -1 $output_dir/report.txt >> $output_dir/report2.txt
314  grep mergerandom $output_dir/report.txt | grep \.s1 >> $output_dir/report2.txt
315fi
316
317echo readrandom >> $output_dir/report2.txt
318head -1 $output_dir/report.txt >> $output_dir/report2.txt
319grep readrandom $output_dir/report.txt  >> $output_dir/report2.txt
320
321echo fwdrange >> $output_dir/report2.txt
322head -1 $output_dir/report.txt >> $output_dir/report2.txt
323grep fwdrange\.t $output_dir/report.txt >> $output_dir/report2.txt
324
325echo revrange >> $output_dir/report2.txt
326head -1 $output_dir/report.txt >> $output_dir/report2.txt
327grep revrange\.t $output_dir/report.txt >> $output_dir/report2.txt
328
329echo readwhile >> $output_dir/report2.txt >> $output_dir/report2.txt
330head -1 $output_dir/report.txt >> $output_dir/report2.txt
331grep readwhilewriting $output_dir/report.txt >> $output_dir/report2.txt
332
333if [[ $skip_low_pri_tests != 1 ]]; then
334  echo readwhile >> $output_dir/report2.txt
335  head -1 $output_dir/report.txt >> $output_dir/report2.txt
336  grep readwhilemerging $output_dir/report.txt >> $output_dir/report2.txt
337fi
338
339echo fwdreadwhilewriting >> $output_dir/report2.txt
340head -1 $output_dir/report.txt >> $output_dir/report2.txt
341grep fwdrangewhilewriting $output_dir/report.txt >> $output_dir/report2.txt
342
343if [[ $skip_low_pri_tests != 1 ]]; then
344  echo fwdreadwhilemerging >> $output_dir/report2.txt
345  head -1 $output_dir/report.txt >> $output_dir/report2.txt
346  grep fwdrangewhilemerg $output_dir/report.txt >> $output_dir/report2.txt
347fi
348
349echo revreadwhilewriting >> $output_dir/report2.txt
350head -1 $output_dir/report.txt >> $output_dir/report2.txt
351grep revrangewhilewriting $output_dir/report.txt >> $output_dir/report2.txt
352
353if [[ $skip_low_pri_tests != 1 ]]; then
354  echo revreadwhilemerging >> $output_dir/report2.txt
355  head -1 $output_dir/report.txt >> $output_dir/report2.txt
356  grep revrangewhilemerg $output_dir/report.txt >> $output_dir/report2.txt
357fi
358
359cat $output_dir/report2.txt
360