]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/tools/regression_test.sh
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / tools / regression_test.sh
CommitLineData
11fdf7f2 1#!/usr/bin/env bash
f67539c2 2# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
7c673cae
FG
3# The RocksDB regression test script.
4# REQUIREMENT: must be able to run make db_bench in the current directory
5#
6# This script will do the following things in order:
7#
8# 1. check out the specified rocksdb commit.
9# 2. build db_bench using the specified commit
10# 3. setup test directory $TEST_PATH. If not specified, then the test directory
11# will be "/tmp/rocksdb/regression_test"
12# 4. run set of benchmarks on the specified host
13# (can be either locally or remotely)
14# 5. generate report in the $RESULT_PATH. If RESULT_PATH is not specified,
15# RESULT_PATH will be set to $TEST_PATH/current_time
16#
17# = Examples =
18# * Run the regression test using rocksdb commit abcdef that outputs results
19# and temp files in "/my/output/dir"
20#r
21# TEST_PATH=/my/output/dir COMMIT_ID=abcdef ./tools/regression_test.sh
22#
23# * Run the regression test on a remost host under "/my/output/dir" directory
24# and stores the result locally in "/my/benchmark/results" using commit
25# abcdef and with the rocksdb options specified in /my/path/to/OPTIONS-012345
26# with 1000000000 keys in each benchmark in the regression test where each
27# key and value are 100 and 900 bytes respectively:
28#
29# REMOTE_USER_AT_HOST=yhchiang@my.remote.host \
30# TEST_PATH=/my/output/dir \
31# RESULT_PATH=/my/benchmark/results \
32# COMMIT_ID=abcdef \
33# OPTIONS_FILE=/my/path/to/OPTIONS-012345 \
34# NUM_KEYS=1000000000 \
35# KEY_SIZE=100 \
36# VALUE_SIZE=900 \
37# ./tools/regression_test.sh
38#
39# = Regression test environmental parameters =
40# DEBUG: If true, then the script will not checkout master and build db_bench
41# if db_bench already exists
42# Default: 0
43# TEST_MODE: If 1, run fillseqdeterminstic and benchmarks both
44# if 0, only run fillseqdeterministc
45# if 2, only run benchmarks
46# Default: 1
47# TEST_PATH: the root directory of the regression test.
48# Default: "/tmp/rocksdb/regression_test"
49# RESULT_PATH: the directory where the regression results will be generated.
50# Default: "$TEST_PATH/current_time"
51# REMOTE_USER_AT_HOST: If set, then test will run on the specified host under
52# TEST_PATH directory and outputs test results locally in RESULT_PATH
53# The REMOTE_USER_AT_HOST should follow the format user-id@host.name
54# DB_PATH: the path where the rocksdb database will be created during the
55# regression test. Default: $TEST_PATH/db
56# WAL_PATH: the path where the rocksdb WAL will be outputed.
57# Default: $TEST_PATH/wal
58# OPTIONS_FILE: If specified, then the regression test will use the specified
59# file to initialize the RocksDB options in its benchmarks. Note that
60# this feature only work for commits after 88acd93 or rocksdb version
61# later than 4.9.
62# DELETE_TEST_PATH: If true, then the test directory will be deleted
63# after the script ends.
64# Default: 0
65#
66# = db_bench parameters =
67# NUM_THREADS: The number of concurrent foreground threads that will issue
68# database operations in the benchmark. Default: 16.
69# NUM_KEYS: The key range that will be used in the entire regression test.
70# Default: 1G.
71# NUM_OPS: The number of operations (reads, writes, or deletes) that will
72# be issued in EACH thread.
73# Default: $NUM_KEYS / $NUM_THREADS
74# KEY_SIZE: The size of each key in bytes in db_bench. Default: 100.
75# VALUE_SIZE: The size of each value in bytes in db_bench. Default: 900.
76# CACHE_SIZE: The size of RocksDB block cache used in db_bench. Default: 1G
77# STATISTICS: If 1, then statistics is on in db_bench. Default: 0.
78# COMPRESSION_RATIO: The compression ratio of the key generated in db_bench.
79# Default: 0.5.
80# HISTOGRAM: If 1, then the histogram feature on performance feature is on.
81# STATS_PER_INTERVAL: If 1, then the statistics will be reported for every
82# STATS_INTERVAL_SECONDS seconds. Default 1.
83# STATS_INTERVAL_SECONDS: If STATS_PER_INTERVAL is set to 1, then statistics
84# will be reported for every STATS_INTERVAL_SECONDS. Default 60.
85# MAX_BACKGROUND_FLUSHES: The maxinum number of concurrent flushes in
86# db_bench. Default: 4.
87# MAX_BACKGROUND_COMPACTIONS: The maximum number of concurrent compactions
88# in db_bench. Default: 16.
11fdf7f2
TL
89# NUM_HIGH_PRI_THREADS: The number of high-pri threads available for
90# concurrent flushes in db_bench. Default: 4.
91# NUM_LOW_PRI_THREADS: The number of low-pri threads available for
92# concurrent compactions in db_bench. Default: 16.
7c673cae
FG
93# SEEK_NEXTS: Controls how many Next() will be called after seek.
94# Default: 10.
95# SEED: random seed that controls the randomness of the benchmark.
96# Default: $( date +%s )
97
98#==============================================================================
99# CONSTANT
100#==============================================================================
101TITLE_FORMAT="%40s,%25s,%30s,%7s,%9s,%8s,"
102TITLE_FORMAT+="%10s,%13s,%14s,%11s,%12s,"
103TITLE_FORMAT+="%7s,%11s,"
104TITLE_FORMAT+="%9s,%10s,%10s,%10s,%10s,%10s,%5s,"
105TITLE_FORMAT+="%5s,%5s,%5s" # time
106TITLE_FORMAT+="\n"
107
108DATA_FORMAT="%40s,%25s,%30s,%7s,%9s,%8s,"
109DATA_FORMAT+="%10s,%13.0f,%14s,%11s,%12s,"
110DATA_FORMAT+="%7s,%11s,"
111DATA_FORMAT+="%9.0f,%10.0f,%10.0f,%10.0f,%10.0f,%10.0f,%5.0f,"
112DATA_FORMAT+="%5.0f,%5.0f,%5.0f" # time
113DATA_FORMAT+="\n"
114
115MAIN_PATTERN="$1""[[:blank:]]+:.*[[:blank:]]+([0-9\.]+)[[:blank:]]+ops/sec"
116PERC_PATTERN="Percentiles: P50: ([0-9\.]+) P75: ([0-9\.]+) "
117PERC_PATTERN+="P99: ([0-9\.]+) P99.9: ([0-9\.]+) P99.99: ([0-9\.]+)"
118#==============================================================================
119
120function main {
11fdf7f2
TL
121 TEST_ROOT_DIR=${TEST_PATH:-"/tmp/rocksdb/regression_test"}
122 init_arguments $TEST_ROOT_DIR
123
124 build_db_bench_and_ldb
7c673cae
FG
125
126 setup_test_directory
127 if [ $TEST_MODE -le 1 ]; then
128 tmp=$DB_PATH
129 DB_PATH=$ORIGIN_PATH
130 test_remote "test -d $DB_PATH"
11fdf7f2 131 if [[ $? -ne 0 ]]; then
7c673cae 132 echo "Building DB..."
11fdf7f2
TL
133 # compactall alone will not print ops or threads, which will fail update_report
134 run_db_bench "fillseq,compactall" $NUM_KEYS 1 0 0
7c673cae
FG
135 fi
136 DB_PATH=$tmp
137 fi
138 if [ $TEST_MODE -ge 1 ]; then
139 build_checkpoint
140 run_db_bench "readrandom"
141 run_db_bench "readwhilewriting"
142 run_db_bench "deleterandom" $((NUM_KEYS / 10 / $NUM_THREADS))
143 run_db_bench "seekrandom"
144 run_db_bench "seekrandomwhilewriting"
145 fi
146
11fdf7f2 147 cleanup_test_directory $TEST_ROOT_DIR
7c673cae
FG
148 echo ""
149 echo "Benchmark completed! Results are available in $RESULT_PATH"
150}
151
152############################################################################
153function init_arguments {
154 K=1024
155 M=$((1024 * K))
156 G=$((1024 * M))
157
158 current_time=$(date +"%F-%H:%M:%S")
159 RESULT_PATH=${RESULT_PATH:-"$1/results/$current_time"}
160 COMMIT_ID=`git log | head -n1 | cut -c 8-`
161 SUMMARY_FILE="$RESULT_PATH/SUMMARY.csv"
162
163 DB_PATH=${3:-"$1/db"}
164 ORIGIN_PATH=${ORIGIN_PATH:-"$(dirname $(dirname $DB_PATH))/db"}
165 WAL_PATH=${4:-""}
166 if [ -z "$REMOTE_USER_AT_HOST" ]; then
167 DB_BENCH_DIR=${5:-"."}
168 else
169 DB_BENCH_DIR=${5:-"$1/db_bench"}
170 fi
171
172 DEBUG=${DEBUG:-0}
173 TEST_MODE=${TEST_MODE:-1}
174 SCP=${SCP:-"scp"}
175 SSH=${SSH:-"ssh"}
176 NUM_THREADS=${NUM_THREADS:-16}
177 NUM_KEYS=${NUM_KEYS:-$((1 * G))} # key range
178 NUM_OPS=${NUM_OPS:-$(($NUM_KEYS / $NUM_THREADS))}
179 KEY_SIZE=${KEY_SIZE:-100}
180 VALUE_SIZE=${VALUE_SIZE:-900}
181 CACHE_SIZE=${CACHE_SIZE:-$((1 * G))}
182 STATISTICS=${STATISTICS:-0}
183 COMPRESSION_RATIO=${COMPRESSION_RATIO:-0.5}
184 HISTOGRAM=${HISTOGRAM:-1}
185 NUM_MULTI_DB=${NUM_MULTI_DB:-1}
186 STATS_PER_INTERVAL=${STATS_PER_INTERVAL:-1}
187 STATS_INTERVAL_SECONDS=${STATS_INTERVAL_SECONDS:-600}
188 MAX_BACKGROUND_FLUSHES=${MAX_BACKGROUND_FLUSHES:-4}
189 MAX_BACKGROUND_COMPACTIONS=${MAX_BACKGROUND_COMPACTIONS:-16}
11fdf7f2
TL
190 NUM_HIGH_PRI_THREADS=${NUM_HIGH_PRI_THREADS:-4}
191 NUM_LOW_PRI_THREADS=${NUM_LOW_PRI_THREADS:-16}
7c673cae
FG
192 DELETE_TEST_PATH=${DELETE_TEST_PATH:-0}
193 SEEK_NEXTS=${SEEK_NEXTS:-10}
194 SEED=${SEED:-$( date +%s )}
195}
196
197# $1 --- benchmark name
198# $2 --- number of operations. Default: $NUM_KEYS
199# $3 --- number of threads. Default $NUM_THREADS
200# $4 --- use_existing_db. Default: 1
11fdf7f2 201# $5 --- update_report. Default: 1
7c673cae
FG
202function run_db_bench {
203 # this will terminate all currently-running db_bench
204 find_db_bench_cmd="ps aux | grep db_bench | grep -v grep | grep -v aux | awk '{print \$2}'"
205
7c673cae
FG
206 ops=${2:-$NUM_OPS}
207 threads=${3:-$NUM_THREADS}
11fdf7f2
TL
208 USE_EXISTING_DB=${4:-1}
209 UPDATE_REPORT=${5:-1}
7c673cae
FG
210 echo ""
211 echo "======================================================================="
212 echo "Benchmark $1"
213 echo "======================================================================="
214 echo ""
215 db_bench_error=0
216 options_file_arg=$(setup_options_file)
217 echo "$options_file_arg"
218 # use `which time` to avoid using bash's internal time command
219 db_bench_cmd="("'\$(which time)'" -p $DB_BENCH_DIR/db_bench \
220 --benchmarks=$1 --db=$DB_PATH --wal_dir=$WAL_PATH \
221 --use_existing_db=$USE_EXISTING_DB \
222 --disable_auto_compactions \
223 --threads=$threads \
224 --num=$NUM_KEYS \
225 --reads=$ops \
226 --writes=$ops \
227 --deletes=$ops \
228 --key_size=$KEY_SIZE \
229 --value_size=$VALUE_SIZE \
230 --cache_size=$CACHE_SIZE \
231 --statistics=$STATISTICS \
232 $options_file_arg \
233 --compression_ratio=$COMPRESSION_RATIO \
234 --histogram=$HISTOGRAM \
235 --seek_nexts=$SEEK_NEXTS \
236 --stats_per_interval=$STATS_PER_INTERVAL \
237 --stats_interval_seconds=$STATS_INTERVAL_SECONDS \
238 --max_background_flushes=$MAX_BACKGROUND_FLUSHES \
239 --num_multi_db=$NUM_MULTI_DB \
240 --max_background_compactions=$MAX_BACKGROUND_COMPACTIONS \
11fdf7f2
TL
241 --num_high_pri_threads=$NUM_HIGH_PRI_THREADS \
242 --num_low_pri_threads=$NUM_LOW_PRI_THREADS \
7c673cae
FG
243 --seed=$SEED) 2>&1"
244 ps_cmd="ps aux"
245 if ! [ -z "$REMOTE_USER_AT_HOST" ]; then
246 echo "Running benchmark remotely on $REMOTE_USER_AT_HOST"
247 db_bench_cmd="$SSH $REMOTE_USER_AT_HOST \"$db_bench_cmd\""
248 ps_cmd="$SSH $REMOTE_USER_AT_HOST $ps_cmd"
249 fi
250
251 ## make sure no db_bench is running
252 # The following statement is necessary make sure "eval $ps_cmd" will success.
253 # Otherwise, if we simply check whether "$(eval $ps_cmd | grep db_bench)" is
254 # successful or not, then it will always be false since grep will return
255 # non-zero status when there's no matching output.
256 ps_output="$(eval $ps_cmd)"
257 exit_on_error $? "$ps_cmd"
258
259 # perform the actual command to check whether db_bench is running
260 grep_output="$(eval $ps_cmd | grep db_bench | grep -v grep)"
261 if [ "$grep_output" != "" ]; then
262 echo "Stopped regression_test.sh as there're still db_bench processes running:"
263 echo $grep_output
11fdf7f2
TL
264 echo "Clean up test directory"
265 cleanup_test_directory $TEST_ROOT_DIR
7c673cae
FG
266 exit 2
267 fi
268
269 ## run the db_bench
270 cmd="($db_bench_cmd || db_bench_error=1) | tee -a $RESULT_PATH/$1"
271 exit_on_error $?
272 echo $cmd
273 eval $cmd
274 exit_on_error $db_bench_error
11fdf7f2
TL
275 if [ $UPDATE_REPORT -ne 0 ]; then
276 update_report "$1" "$RESULT_PATH/$1" $ops $threads
277 fi
7c673cae
FG
278}
279
280function build_checkpoint {
281 cmd_prefix=""
282 if ! [ -z "$REMOTE_USER_AT_HOST" ]; then
283 cmd_prefix="$SSH $REMOTE_USER_AT_HOST "
284 fi
11fdf7f2
TL
285 if [ $NUM_MULTI_DB -gt 1 ]; then
286 dirs=$($cmd_prefix find $ORIGIN_PATH -type d -links 2)
287 for dir in $dirs; do
288 db_index=$(basename $dir)
289 echo "Building checkpoints: $ORIGIN_PATH/$db_index -> $DB_PATH/$db_index ..."
290 $cmd_prefix $DB_BENCH_DIR/ldb checkpoint --checkpoint_dir=$DB_PATH/$db_index \
291 --db=$ORIGIN_PATH/$db_index 2>&1
292 done
293 else
294 # checkpoint cannot build in directory already exists
295 $cmd_prefix rm -rf $DB_PATH
296 echo "Building checkpoint: $ORIGIN_PATH -> $DB_PATH ..."
297 $cmd_prefix $DB_BENCH_DIR/ldb checkpoint --checkpoint_dir=$DB_PATH \
298 --db=$ORIGIN_PATH 2>&1
299 fi
7c673cae
FG
300}
301
302function multiply {
303 echo "$1 * $2" | bc
304}
305
306# $1 --- name of the benchmark
307# $2 --- the filename of the output log of db_bench
308function update_report {
309 main_result=`cat $2 | grep $1`
310 exit_on_error $?
311 perc_statement=`cat $2 | grep Percentile`
312 exit_on_error $?
313
314 # Obtain micros / op
315
316 [[ $main_result =~ $MAIN_PATTERN ]]
317 ops_per_s=${BASH_REMATCH[1]}
318
319 # Obtain percentile information
320 [[ $perc_statement =~ $PERC_PATTERN ]]
321 perc[0]=${BASH_REMATCH[1]} # p50
322 perc[1]=${BASH_REMATCH[2]} # p75
323 perc[2]=${BASH_REMATCH[3]} # p99
324 perc[3]=${BASH_REMATCH[4]} # p99.9
325 perc[4]=${BASH_REMATCH[5]} # p99.99
326
327 # Parse the output of the time command
328 real_sec=`tail -3 $2 | grep real | awk '{print $2}'`
329 user_sec=`tail -3 $2 | grep user | awk '{print $2}'`
330 sys_sec=`tail -3 $2 | grep sys | awk '{print $2}'`
331
332 (printf "$DATA_FORMAT" \
333 $COMMIT_ID $1 $REMOTE_USER_AT_HOST $NUM_MULTI_DB $NUM_KEYS $KEY_SIZE $VALUE_SIZE \
334 $(multiply $COMPRESSION_RATIO 100) \
335 $3 $4 $CACHE_SIZE \
336 $MAX_BACKGROUND_FLUSHES $MAX_BACKGROUND_COMPACTIONS \
337 $ops_per_s \
338 $(multiply ${perc[0]} 1000) \
339 $(multiply ${perc[1]} 1000) \
340 $(multiply ${perc[2]} 1000) \
341 $(multiply ${perc[3]} 1000) \
342 $(multiply ${perc[4]} 1000) \
343 $DEBUG \
344 $real_sec \
345 $user_sec \
346 $sys_sec \
347 >> $SUMMARY_FILE)
348 exit_on_error $?
349}
350
351function exit_on_error {
352 if [ $1 -ne 0 ]; then
353 echo ""
354 echo "ERROR: Benchmark did not complete successfully."
355 if ! [ -z "$2" ]; then
356 echo "Failure command: $2"
357 fi
358 echo "Partial results are output to $RESULT_PATH"
359 echo "ERROR" >> $SUMMARY_FILE
360 exit $1
361 fi
362}
363
364function checkout_rocksdb {
365 echo "Checking out commit $1 ..."
366
367 git fetch --all
368 exit_on_error $?
369
370 git checkout $1
371 exit_on_error $?
372}
373
374function build_db_bench_and_ldb {
375 echo "Building db_bench & ldb ..."
376
377 make clean
378 exit_on_error $?
379
11fdf7f2 380 DEBUG_LEVEL=0 PORTABLE=1 make db_bench ldb -j32
7c673cae
FG
381 exit_on_error $?
382}
383
384function run_remote {
385 test_remote "$1"
386 exit_on_error $? "$1"
387}
388
389function test_remote {
390 if ! [ -z "$REMOTE_USER_AT_HOST" ]; then
391 cmd="$SSH $REMOTE_USER_AT_HOST '$1'"
392 else
393 cmd="$1"
394 fi
395 eval "$cmd"
396}
397
398function run_local {
399 eval "$1"
400 exit_on_error $?
401}
402
403function setup_options_file {
404 if ! [ -z "$OPTIONS_FILE" ]; then
405 if ! [ -z "$REMOTE_USER_AT_HOST" ]; then
406 options_file="$DB_BENCH_DIR/OPTIONS_FILE"
407 run_local "$SCP $OPTIONS_FILE $REMOTE_USER_AT_HOST:$options_file"
408 else
409 options_file="$OPTIONS_FILE"
410 fi
411 echo "--options_file=$options_file"
412 fi
413 echo ""
414}
415
416function setup_test_directory {
417 echo "Deleting old regression test directories and creating new ones"
418
419 run_remote "rm -rf $DB_PATH"
420 run_remote "rm -rf $DB_BENCH_DIR"
421 run_local "rm -rf $RESULT_PATH"
422
423 if ! [ -z "$WAL_PATH" ]; then
424 run_remote "rm -rf $WAL_PATH"
425 run_remote "mkdir -p $WAL_PATH"
426 fi
427
428 run_remote "mkdir -p $DB_PATH"
429
430 run_remote "mkdir -p $DB_BENCH_DIR"
431 run_remote "ls -l $DB_BENCH_DIR"
432
433 if ! [ -z "$REMOTE_USER_AT_HOST" ]; then
434 run_local "$SCP ./db_bench $REMOTE_USER_AT_HOST:$DB_BENCH_DIR/db_bench"
435 run_local "$SCP ./ldb $REMOTE_USER_AT_HOST:$DB_BENCH_DIR/ldb"
436 fi
437
438 run_local "mkdir -p $RESULT_PATH"
439
440 (printf $TITLE_FORMAT \
441 "commit id" "benchmark" "user@host" "num-dbs" "key-range" "key-size" \
442 "value-size" "compress-rate" "ops-per-thread" "num-threads" "cache-size" \
443 "flushes" "compactions" \
444 "ops-per-s" "p50" "p75" "p99" "p99.9" "p99.99" "debug" \
445 "real-sec" "user-sec" "sys-sec" \
446 >> $SUMMARY_FILE)
447 exit_on_error $?
448}
449
450function cleanup_test_directory {
451
452 if [ $DELETE_TEST_PATH -ne 0 ]; then
453 echo "Clear old regression test directories and creating new ones"
454 run_remote "rm -rf $DB_PATH"
455 run_remote "rm -rf $WAL_PATH"
456 if ! [ -z "$REMOTE_USER_AT_HOST" ]; then
457 run_remote "rm -rf $DB_BENCH_DIR"
458 fi
459 run_remote "rm -rf $1"
460 else
461 echo "------------ DEBUG MODE ------------"
462 echo "DB PATH: $DB_PATH"
463 echo "WAL PATH: $WAL_PATH"
464 fi
465}
466
467############################################################################
468
11fdf7f2 469# shellcheck disable=SC2068
7c673cae 470main $@