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#
5# This should be used with the LevelDB fork listed here to use additional test options.
6# For more details on the changes see the blog post listed below.
7#   https://github.com/mdcallag/leveldb-1
8#   http://smalldatum.blogspot.com/2015/04/comparing-leveldb-and-rocksdb-take-2.html
9
10if [ $# -ne 1 ]; then
11  echo -n "./benchmark.sh [fillseq/overwrite/readrandom/readwhilewriting]"
12  exit 0
13fi
14
15# size constants
16K=1024
17M=$((1024 * K))
18G=$((1024 * M))
19
20if [ -z $DB_DIR ]; then
21  echo "DB_DIR is not defined"
22  exit 0
23fi
24
25output_dir=${OUTPUT_DIR:-/tmp/}
26if [ ! -d $output_dir ]; then
27  mkdir -p $output_dir
28fi
29
30# all multithreaded tests run with sync=1 unless
31# $DB_BENCH_NO_SYNC is defined
32syncval="1"
33if [ ! -z $DB_BENCH_NO_SYNC ]; then
34  echo "Turning sync off for all multithreaded tests"
35  syncval="0";
36fi
37
38num_threads=${NUM_THREADS:-16}
39# Only for *whilewriting, *whilemerging
40writes_per_second=${WRITES_PER_SECOND:-$((10 * K))}
41cache_size=${CACHE_SIZE:-$((1 * G))}
42
43num_keys=${NUM_KEYS:-$((1 * G))}
44key_size=20
45value_size=${VALUE_SIZE:-400}
46block_size=${BLOCK_SIZE:-4096}
47
48const_params="
49  --db=$DB_DIR \
50  \
51  --num=$num_keys \
52  --value_size=$value_size \
53  --cache_size=$cache_size \
54  --compression_ratio=0.5 \
55  \
56  --write_buffer_size=$((2 * M)) \
57  \
58  --histogram=1 \
59  \
60  --bloom_bits=10 \
61  --open_files=$((20 * K))"
62
63params_w="$const_params "
64
65function summarize_result {
66  test_out=$1
67  test_name=$2
68  bench_name=$3
69  nthr=$4
70
71  usecs_op=$( grep ^${bench_name} $test_out | awk '{ printf "%.1f", $3 }' )
72  mb_sec=$( grep ^${bench_name} $test_out | awk '{ printf "%.1f", $5 }' )
73  ops=$( grep "^Count:" $test_out | awk '{ print $2 }' )
74  ops_sec=$( echo "scale=0; (1000000.0 * $nthr) / $usecs_op" | bc )
75  avg=$( grep "^Count:" $test_out | awk '{ printf "%.1f", $4 }' )
76  p50=$( grep "^Min:" $test_out | awk '{ printf "%.1f", $4 }' )
77  echo -e "$ops_sec\t$mb_sec\t$usecs_op\t$avg\t$p50\t$test_name" \
78    >> $output_dir/report.txt
79}
80
81function run_fillseq {
82  # This runs with a vector memtable and the WAL disabled to load faster. It is still crash safe and the
83  # client can discover where to restart a load after a crash. I think this is a good way to load.
84  echo "Loading $num_keys keys sequentially"
85  cmd="./db_bench --benchmarks=fillseq \
86       --use_existing_db=0 \
87       --sync=0 \
88       $params_w \
89       --threads=1 \
90       --seed=$( date +%s ) \
91       2>&1 | tee -a $output_dir/benchmark_fillseq.v${value_size}.log"
92  echo $cmd | tee $output_dir/benchmark_fillseq.v${value_size}.log
93  eval $cmd
94  summarize_result $output_dir/benchmark_fillseq.v${value_size}.log fillseq.v${value_size} fillseq 1
95}
96
97function run_change {
98  operation=$1
99  echo "Do $num_keys random $operation"
100  out_name="benchmark_${operation}.t${num_threads}.s${syncval}.log"
101  cmd="./db_bench --benchmarks=$operation \
102       --use_existing_db=1 \
103       --sync=$syncval \
104       $params_w \
105       --threads=$num_threads \
106       --seed=$( date +%s ) \
107       2>&1 | tee -a $output_dir/${out_name}"
108  echo $cmd | tee $output_dir/${out_name}
109  eval $cmd
110  summarize_result $output_dir/${out_name} ${operation}.t${num_threads}.s${syncval} $operation $num_threads
111}
112
113function run_readrandom {
114  echo "Reading $num_keys random keys"
115  out_name="benchmark_readrandom.t${num_threads}.log"
116  cmd="./db_bench --benchmarks=readrandom \
117       --use_existing_db=1 \
118       $params_w \
119       --threads=$num_threads \
120       --seed=$( date +%s ) \
121       2>&1 | tee -a $output_dir/${out_name}"
122  echo $cmd | tee $output_dir/${out_name}
123  eval $cmd
124  summarize_result $output_dir/${out_name} readrandom.t${num_threads} readrandom $num_threads
125}
126
127function run_readwhile {
128  operation=$1
129  echo "Reading $num_keys random keys while $operation"
130  out_name="benchmark_readwhile${operation}.t${num_threads}.log"
131  cmd="./db_bench --benchmarks=readwhile${operation} \
132       --use_existing_db=1 \
133       --sync=$syncval \
134       $params_w \
135       --threads=$num_threads \
136       --writes_per_second=$writes_per_second \
137       --seed=$( date +%s ) \
138       2>&1 | tee -a $output_dir/${out_name}"
139  echo $cmd | tee $output_dir/${out_name}
140  eval $cmd
141  summarize_result $output_dir/${out_name} readwhile${operation}.t${num_threads} readwhile${operation} $num_threads
142}
143
144function now() {
145  echo `date +"%s"`
146}
147
148report="$output_dir/report.txt"
149schedule="$output_dir/schedule.txt"
150
151echo "===== Benchmark ====="
152
153# Run!!!
154IFS=',' read -a jobs <<< $1
155# shellcheck disable=SC2068
156for job in ${jobs[@]}; do
157
158  if [ $job != debug ]; then
159    echo "Start $job at `date`" | tee -a $schedule
160  fi
161
162  start=$(now)
163  if [ $job = fillseq ]; then
164    run_fillseq
165  elif [ $job = overwrite ]; then
166    run_change overwrite
167  elif [ $job = readrandom ]; then
168    run_readrandom
169  elif [ $job = readwhilewriting ]; then
170    run_readwhile writing
171  elif [ $job = debug ]; then
172    num_keys=1000; # debug
173    echo "Setting num_keys to $num_keys"
174  else
175    echo "unknown job $job"
176    exit
177  fi
178  end=$(now)
179
180  if [ $job != debug ]; then
181    echo "Complete $job in $((end-start)) seconds" | tee -a $schedule
182  fi
183
184  echo -e "ops/sec\tmb/sec\tusec/op\tavg\tp50\tTest"
185  tail -1 $output_dir/report.txt
186
187done
188