benchmark.sh 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #!/usr/bin/env bash
  2. # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  3. # REQUIRE: db_bench binary exists in the current directory
  4. if [ $# -ne 1 ]; then
  5. echo -n "./benchmark.sh [bulkload/fillseq/overwrite/filluniquerandom/"
  6. echo "readrandom/readwhilewriting/readwhilemerging/updaterandom/"
  7. echo "mergerandom/randomtransaction/compact]"
  8. exit 0
  9. fi
  10. # Make it easier to run only the compaction test. Getting valid data requires
  11. # a number of iterations and having an ability to run the test separately from
  12. # rest of the benchmarks helps.
  13. if [ "$COMPACTION_TEST" == "1" -a "$1" != "universal_compaction" ]; then
  14. echo "Skipping $1 because it's not a compaction test."
  15. exit 0
  16. fi
  17. # size constants
  18. K=1024
  19. M=$((1024 * K))
  20. G=$((1024 * M))
  21. T=$((1024 * G))
  22. if [ -z $DB_DIR ]; then
  23. echo "DB_DIR is not defined"
  24. exit 0
  25. fi
  26. if [ -z $WAL_DIR ]; then
  27. echo "WAL_DIR is not defined"
  28. exit 0
  29. fi
  30. output_dir=${OUTPUT_DIR:-/tmp/}
  31. if [ ! -d $output_dir ]; then
  32. mkdir -p $output_dir
  33. fi
  34. # all multithreaded tests run with sync=1 unless
  35. # $DB_BENCH_NO_SYNC is defined
  36. syncval="1"
  37. if [ ! -z $DB_BENCH_NO_SYNC ]; then
  38. echo "Turning sync off for all multithreaded tests"
  39. syncval="0";
  40. fi
  41. num_threads=${NUM_THREADS:-64}
  42. mb_written_per_sec=${MB_WRITE_PER_SEC:-0}
  43. # Only for tests that do range scans
  44. num_nexts_per_seek=${NUM_NEXTS_PER_SEEK:-10}
  45. cache_size=${CACHE_SIZE:-$((17179869184))}
  46. compression_max_dict_bytes=${COMPRESSION_MAX_DICT_BYTES:-0}
  47. compression_type=${COMPRESSION_TYPE:-zstd}
  48. duration=${DURATION:-0}
  49. num_keys=${NUM_KEYS:-8000000000}
  50. key_size=${KEY_SIZE:-20}
  51. value_size=${VALUE_SIZE:-400}
  52. block_size=${BLOCK_SIZE:-8192}
  53. const_params="
  54. --db=$DB_DIR \
  55. --wal_dir=$WAL_DIR \
  56. \
  57. --num=$num_keys \
  58. --num_levels=6 \
  59. --key_size=$key_size \
  60. --value_size=$value_size \
  61. --block_size=$block_size \
  62. --cache_size=$cache_size \
  63. --cache_numshardbits=6 \
  64. --compression_max_dict_bytes=$compression_max_dict_bytes \
  65. --compression_ratio=0.5 \
  66. --compression_type=$compression_type \
  67. --level_compaction_dynamic_level_bytes=true \
  68. --bytes_per_sync=$((8 * M)) \
  69. --cache_index_and_filter_blocks=0 \
  70. --pin_l0_filter_and_index_blocks_in_cache=1 \
  71. --benchmark_write_rate_limit=$(( 1024 * 1024 * $mb_written_per_sec )) \
  72. \
  73. --hard_rate_limit=3 \
  74. --rate_limit_delay_max_milliseconds=1000000 \
  75. --write_buffer_size=$((128 * M)) \
  76. --target_file_size_base=$((128 * M)) \
  77. --max_bytes_for_level_base=$((1 * G)) \
  78. \
  79. --verify_checksum=1 \
  80. --delete_obsolete_files_period_micros=$((60 * M)) \
  81. --max_bytes_for_level_multiplier=8 \
  82. \
  83. --statistics=0 \
  84. --stats_per_interval=1 \
  85. --stats_interval_seconds=60 \
  86. --histogram=1 \
  87. \
  88. --memtablerep=skip_list \
  89. --bloom_bits=10 \
  90. --open_files=-1"
  91. l0_config="
  92. --level0_file_num_compaction_trigger=4 \
  93. --level0_stop_writes_trigger=20"
  94. if [ $duration -gt 0 ]; then
  95. const_params="$const_params --duration=$duration"
  96. fi
  97. params_w="$const_params \
  98. $l0_config \
  99. --max_background_compactions=16 \
  100. --max_write_buffer_number=8 \
  101. --max_background_flushes=7"
  102. params_bulkload="$const_params \
  103. --max_background_compactions=16 \
  104. --max_write_buffer_number=8 \
  105. --allow_concurrent_memtable_write=false \
  106. --max_background_flushes=7 \
  107. --level0_file_num_compaction_trigger=$((10 * M)) \
  108. --level0_slowdown_writes_trigger=$((10 * M)) \
  109. --level0_stop_writes_trigger=$((10 * M))"
  110. params_fillseq="$params_w \
  111. --allow_concurrent_memtable_write=false"
  112. #
  113. # Tune values for level and universal compaction.
  114. # For universal compaction, these level0_* options mean total sorted of runs in
  115. # LSM. In level-based compaction, it means number of L0 files.
  116. #
  117. params_level_compact="$const_params \
  118. --max_background_flushes=4 \
  119. --max_write_buffer_number=4 \
  120. --level0_file_num_compaction_trigger=4 \
  121. --level0_slowdown_writes_trigger=16 \
  122. --level0_stop_writes_trigger=20"
  123. params_univ_compact="$const_params \
  124. --max_background_flushes=4 \
  125. --max_write_buffer_number=4 \
  126. --level0_file_num_compaction_trigger=8 \
  127. --level0_slowdown_writes_trigger=16 \
  128. --level0_stop_writes_trigger=20"
  129. function summarize_result {
  130. test_out=$1
  131. test_name=$2
  132. bench_name=$3
  133. # Note that this function assumes that the benchmark executes long enough so
  134. # that "Compaction Stats" is written to stdout at least once. If it won't
  135. # happen then empty output from grep when searching for "Sum" will cause
  136. # syntax errors.
  137. uptime=$( grep ^Uptime\(secs $test_out | tail -1 | awk '{ printf "%.0f", $2 }' )
  138. stall_time=$( grep "^Cumulative stall" $test_out | tail -1 | awk '{ print $3 }' )
  139. stall_pct=$( grep "^Cumulative stall" $test_out| tail -1 | awk '{ print $5 }' )
  140. ops_sec=$( grep ^${bench_name} $test_out | awk '{ print $5 }' )
  141. mb_sec=$( grep ^${bench_name} $test_out | awk '{ print $7 }' )
  142. lo_wgb=$( grep "^ L0" $test_out | tail -1 | awk '{ print $9 }' )
  143. sum_wgb=$( grep "^ Sum" $test_out | tail -1 | awk '{ print $9 }' )
  144. sum_size=$( grep "^ Sum" $test_out | tail -1 | awk '{ printf "%.1f", $3 / 1024.0 }' )
  145. wamp=$( echo "scale=1; $sum_wgb / $lo_wgb" | bc )
  146. wmb_ps=$( echo "scale=1; ( $sum_wgb * 1024.0 ) / $uptime" | bc )
  147. usecs_op=$( grep ^${bench_name} $test_out | awk '{ printf "%.1f", $3 }' )
  148. p50=$( grep "^Percentiles:" $test_out | tail -1 | awk '{ printf "%.1f", $3 }' )
  149. p75=$( grep "^Percentiles:" $test_out | tail -1 | awk '{ printf "%.1f", $5 }' )
  150. p99=$( grep "^Percentiles:" $test_out | tail -1 | awk '{ printf "%.0f", $7 }' )
  151. p999=$( grep "^Percentiles:" $test_out | tail -1 | awk '{ printf "%.0f", $9 }' )
  152. p9999=$( grep "^Percentiles:" $test_out | tail -1 | awk '{ printf "%.0f", $11 }' )
  153. echo -e "$ops_sec\t$mb_sec\t$sum_size\t$lo_wgb\t$sum_wgb\t$wamp\t$wmb_ps\t$usecs_op\t$p50\t$p75\t$p99\t$p999\t$p9999\t$uptime\t$stall_time\t$stall_pct\t$test_name" \
  154. >> $output_dir/report.txt
  155. }
  156. function run_bulkload {
  157. # This runs with a vector memtable and the WAL disabled to load faster. It is still crash safe and the
  158. # client can discover where to restart a load after a crash. I think this is a good way to load.
  159. echo "Bulk loading $num_keys random keys"
  160. cmd="./db_bench --benchmarks=fillrandom \
  161. --use_existing_db=0 \
  162. --disable_auto_compactions=1 \
  163. --sync=0 \
  164. $params_bulkload \
  165. --threads=1 \
  166. --memtablerep=vector \
  167. --allow_concurrent_memtable_write=false \
  168. --disable_wal=1 \
  169. --seed=$( date +%s ) \
  170. 2>&1 | tee -a $output_dir/benchmark_bulkload_fillrandom.log"
  171. echo $cmd | tee $output_dir/benchmark_bulkload_fillrandom.log
  172. eval $cmd
  173. summarize_result $output_dir/benchmark_bulkload_fillrandom.log bulkload fillrandom
  174. echo "Compacting..."
  175. cmd="./db_bench --benchmarks=compact \
  176. --use_existing_db=1 \
  177. --disable_auto_compactions=1 \
  178. --sync=0 \
  179. $params_w \
  180. --threads=1 \
  181. 2>&1 | tee -a $output_dir/benchmark_bulkload_compact.log"
  182. echo $cmd | tee $output_dir/benchmark_bulkload_compact.log
  183. eval $cmd
  184. }
  185. #
  186. # Parameter description:
  187. #
  188. # $1 - 1 if I/O statistics should be collected.
  189. # $2 - compaction type to use (level=0, universal=1).
  190. # $3 - number of subcompactions.
  191. # $4 - number of maximum background compactions.
  192. #
  193. function run_manual_compaction_worker {
  194. # This runs with a vector memtable and the WAL disabled to load faster.
  195. # It is still crash safe and the client can discover where to restart a
  196. # load after a crash. I think this is a good way to load.
  197. echo "Bulk loading $num_keys random keys for manual compaction."
  198. fillrandom_output_file=$output_dir/benchmark_man_compact_fillrandom_$3.log
  199. man_compact_output_log=$output_dir/benchmark_man_compact_$3.log
  200. if [ "$2" == "1" ]; then
  201. extra_params=$params_univ_compact
  202. else
  203. extra_params=$params_level_compact
  204. fi
  205. # Make sure that fillrandom uses the same compaction options as compact.
  206. cmd="./db_bench --benchmarks=fillrandom \
  207. --use_existing_db=0 \
  208. --disable_auto_compactions=0 \
  209. --sync=0 \
  210. $extra_params \
  211. --threads=$num_threads \
  212. --compaction_measure_io_stats=$1 \
  213. --compaction_style=$2 \
  214. --subcompactions=$3 \
  215. --memtablerep=vector \
  216. --allow_concurrent_memtable_write=false \
  217. --disable_wal=1 \
  218. --max_background_compactions=$4 \
  219. --seed=$( date +%s ) \
  220. 2>&1 | tee -a $fillrandom_output_file"
  221. echo $cmd | tee $fillrandom_output_file
  222. eval $cmd
  223. summarize_result $fillrandom_output_file man_compact_fillrandom_$3 fillrandom
  224. echo "Compacting with $3 subcompactions specified ..."
  225. # This is the part we're really interested in. Given that compact benchmark
  226. # doesn't output regular statistics then we'll just use the time command to
  227. # measure how long this step takes.
  228. cmd="{ \
  229. time ./db_bench --benchmarks=compact \
  230. --use_existing_db=1 \
  231. --disable_auto_compactions=0 \
  232. --sync=0 \
  233. $extra_params \
  234. --threads=$num_threads \
  235. --compaction_measure_io_stats=$1 \
  236. --compaction_style=$2 \
  237. --subcompactions=$3 \
  238. --max_background_compactions=$4 \
  239. ;}
  240. 2>&1 | tee -a $man_compact_output_log"
  241. echo $cmd | tee $man_compact_output_log
  242. eval $cmd
  243. # Can't use summarize_result here. One way to analyze the results is to run
  244. # "grep real" on the resulting log files.
  245. }
  246. function run_univ_compaction {
  247. # Always ask for I/O statistics to be measured.
  248. io_stats=1
  249. # Values: kCompactionStyleLevel = 0x0, kCompactionStyleUniversal = 0x1.
  250. compaction_style=1
  251. # Define a set of benchmarks.
  252. subcompactions=(1 2 4 8 16)
  253. max_background_compactions=(16 16 8 4 2)
  254. i=0
  255. total=${#subcompactions[@]}
  256. # Execute a set of benchmarks to cover variety of scenarios.
  257. while [ "$i" -lt "$total" ]
  258. do
  259. run_manual_compaction_worker $io_stats $compaction_style ${subcompactions[$i]} \
  260. ${max_background_compactions[$i]}
  261. ((i++))
  262. done
  263. }
  264. function run_fillseq {
  265. # This runs with a vector memtable. WAL can be either disabled or enabled
  266. # depending on the input parameter (1 for disabled, 0 for enabled). The main
  267. # benefit behind disabling WAL is to make loading faster. It is still crash
  268. # safe and the client can discover where to restart a load after a crash. I
  269. # think this is a good way to load.
  270. # Make sure that we'll have unique names for all the files so that data won't
  271. # be overwritten.
  272. if [ $1 == 1 ]; then
  273. log_file_name=$output_dir/benchmark_fillseq.wal_disabled.v${value_size}.log
  274. test_name=fillseq.wal_disabled.v${value_size}
  275. else
  276. log_file_name=$output_dir/benchmark_fillseq.wal_enabled.v${value_size}.log
  277. test_name=fillseq.wal_enabled.v${value_size}
  278. fi
  279. echo "Loading $num_keys keys sequentially"
  280. cmd="./db_bench --benchmarks=fillseq \
  281. --use_existing_db=0 \
  282. --sync=0 \
  283. $params_fillseq \
  284. --min_level_to_compress=0 \
  285. --threads=1 \
  286. --memtablerep=vector \
  287. --allow_concurrent_memtable_write=false \
  288. --disable_wal=$1 \
  289. --seed=$( date +%s ) \
  290. 2>&1 | tee -a $log_file_name"
  291. echo $cmd | tee $log_file_name
  292. eval $cmd
  293. # The constant "fillseq" which we pass to db_bench is the benchmark name.
  294. summarize_result $log_file_name $test_name fillseq
  295. }
  296. function run_change {
  297. operation=$1
  298. echo "Do $num_keys random $operation"
  299. out_name="benchmark_${operation}.t${num_threads}.s${syncval}.log"
  300. cmd="./db_bench --benchmarks=$operation \
  301. --use_existing_db=1 \
  302. --sync=$syncval \
  303. $params_w \
  304. --threads=$num_threads \
  305. --merge_operator=\"put\" \
  306. --seed=$( date +%s ) \
  307. 2>&1 | tee -a $output_dir/${out_name}"
  308. echo $cmd | tee $output_dir/${out_name}
  309. eval $cmd
  310. summarize_result $output_dir/${out_name} ${operation}.t${num_threads}.s${syncval} $operation
  311. }
  312. function run_filluniquerandom {
  313. echo "Loading $num_keys unique keys randomly"
  314. cmd="./db_bench --benchmarks=filluniquerandom \
  315. --use_existing_db=0 \
  316. --sync=0 \
  317. $params_w \
  318. --threads=1 \
  319. --seed=$( date +%s ) \
  320. 2>&1 | tee -a $output_dir/benchmark_filluniquerandom.log"
  321. echo $cmd | tee $output_dir/benchmark_filluniquerandom.log
  322. eval $cmd
  323. summarize_result $output_dir/benchmark_filluniquerandom.log filluniquerandom filluniquerandom
  324. }
  325. function run_readrandom {
  326. echo "Reading $num_keys random keys"
  327. out_name="benchmark_readrandom.t${num_threads}.log"
  328. cmd="./db_bench --benchmarks=readrandom \
  329. --use_existing_db=1 \
  330. $params_w \
  331. --threads=$num_threads \
  332. --seed=$( date +%s ) \
  333. 2>&1 | tee -a $output_dir/${out_name}"
  334. echo $cmd | tee $output_dir/${out_name}
  335. eval $cmd
  336. summarize_result $output_dir/${out_name} readrandom.t${num_threads} readrandom
  337. }
  338. function run_readwhile {
  339. operation=$1
  340. echo "Reading $num_keys random keys while $operation"
  341. out_name="benchmark_readwhile${operation}.t${num_threads}.log"
  342. cmd="./db_bench --benchmarks=readwhile${operation} \
  343. --use_existing_db=1 \
  344. --sync=$syncval \
  345. $params_w \
  346. --threads=$num_threads \
  347. --merge_operator=\"put\" \
  348. --seed=$( date +%s ) \
  349. 2>&1 | tee -a $output_dir/${out_name}"
  350. echo $cmd | tee $output_dir/${out_name}
  351. eval $cmd
  352. summarize_result $output_dir/${out_name} readwhile${operation}.t${num_threads} readwhile${operation}
  353. }
  354. function run_rangewhile {
  355. operation=$1
  356. full_name=$2
  357. reverse_arg=$3
  358. out_name="benchmark_${full_name}.t${num_threads}.log"
  359. echo "Range scan $num_keys random keys while ${operation} for reverse_iter=${reverse_arg}"
  360. cmd="./db_bench --benchmarks=seekrandomwhile${operation} \
  361. --use_existing_db=1 \
  362. --sync=$syncval \
  363. $params_w \
  364. --threads=$num_threads \
  365. --merge_operator=\"put\" \
  366. --seek_nexts=$num_nexts_per_seek \
  367. --reverse_iterator=$reverse_arg \
  368. --seed=$( date +%s ) \
  369. 2>&1 | tee -a $output_dir/${out_name}"
  370. echo $cmd | tee $output_dir/${out_name}
  371. eval $cmd
  372. summarize_result $output_dir/${out_name} ${full_name}.t${num_threads} seekrandomwhile${operation}
  373. }
  374. function run_range {
  375. full_name=$1
  376. reverse_arg=$2
  377. out_name="benchmark_${full_name}.t${num_threads}.log"
  378. echo "Range scan $num_keys random keys for reverse_iter=${reverse_arg}"
  379. cmd="./db_bench --benchmarks=seekrandom \
  380. --use_existing_db=1 \
  381. $params_w \
  382. --threads=$num_threads \
  383. --seek_nexts=$num_nexts_per_seek \
  384. --reverse_iterator=$reverse_arg \
  385. --seed=$( date +%s ) \
  386. 2>&1 | tee -a $output_dir/${out_name}"
  387. echo $cmd | tee $output_dir/${out_name}
  388. eval $cmd
  389. summarize_result $output_dir/${out_name} ${full_name}.t${num_threads} seekrandom
  390. }
  391. function run_randomtransaction {
  392. echo "..."
  393. cmd="./db_bench $params_r --benchmarks=randomtransaction \
  394. --num=$num_keys \
  395. --transaction_db \
  396. --threads=5 \
  397. --transaction_sets=5 \
  398. 2>&1 | tee $output_dir/benchmark_randomtransaction.log"
  399. echo $cmd | tee $output_dir/benchmark_rangescanwhilewriting.log
  400. eval $cmd
  401. }
  402. function now() {
  403. echo `date +"%s"`
  404. }
  405. report="$output_dir/report.txt"
  406. schedule="$output_dir/schedule.txt"
  407. echo "===== Benchmark ====="
  408. # Run!!!
  409. IFS=',' read -a jobs <<< $1
  410. # shellcheck disable=SC2068
  411. for job in ${jobs[@]}; do
  412. if [ $job != debug ]; then
  413. echo "Start $job at `date`" | tee -a $schedule
  414. fi
  415. start=$(now)
  416. if [ $job = bulkload ]; then
  417. run_bulkload
  418. elif [ $job = fillseq_disable_wal ]; then
  419. run_fillseq 1
  420. elif [ $job = fillseq_enable_wal ]; then
  421. run_fillseq 0
  422. elif [ $job = overwrite ]; then
  423. syncval="0"
  424. params_w="$params_w \
  425. --writes=125000000 \
  426. --subcompactions=4 \
  427. --soft_pending_compaction_bytes_limit=$((1 * T)) \
  428. --hard_pending_compaction_bytes_limit=$((4 * T)) "
  429. run_change overwrite
  430. elif [ $job = updaterandom ]; then
  431. run_change updaterandom
  432. elif [ $job = mergerandom ]; then
  433. run_change mergerandom
  434. elif [ $job = filluniquerandom ]; then
  435. run_filluniquerandom
  436. elif [ $job = readrandom ]; then
  437. run_readrandom
  438. elif [ $job = fwdrange ]; then
  439. run_range $job false
  440. elif [ $job = revrange ]; then
  441. run_range $job true
  442. elif [ $job = readwhilewriting ]; then
  443. run_readwhile writing
  444. elif [ $job = readwhilemerging ]; then
  445. run_readwhile merging
  446. elif [ $job = fwdrangewhilewriting ]; then
  447. run_rangewhile writing $job false
  448. elif [ $job = revrangewhilewriting ]; then
  449. run_rangewhile writing $job true
  450. elif [ $job = fwdrangewhilemerging ]; then
  451. run_rangewhile merging $job false
  452. elif [ $job = revrangewhilemerging ]; then
  453. run_rangewhile merging $job true
  454. elif [ $job = randomtransaction ]; then
  455. run_randomtransaction
  456. elif [ $job = universal_compaction ]; then
  457. run_univ_compaction
  458. elif [ $job = debug ]; then
  459. num_keys=1000; # debug
  460. echo "Setting num_keys to $num_keys"
  461. else
  462. echo "unknown job $job"
  463. exit
  464. fi
  465. end=$(now)
  466. if [ $job != debug ]; then
  467. echo "Complete $job in $((end-start)) seconds" | tee -a $schedule
  468. fi
  469. echo -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"
  470. tail -1 $output_dir/report.txt
  471. done