43 static const char* FLAGS_benchmarks =
64 static int FLAGS_num = 1000000;
67 static int FLAGS_reads = -1;
70 static int FLAGS_threads = 1;
73 static int FLAGS_value_size = 100;
77 static double FLAGS_compression_ratio = 0.5;
80 static bool FLAGS_histogram =
false;
84 static int FLAGS_write_buffer_size = 0;
88 static int FLAGS_cache_size = -1;
91 static int FLAGS_open_files = 0;
95 static int FLAGS_bloom_bits = -1;
100 static bool FLAGS_use_existing_db =
false;
103 static const char* FLAGS_db = NULL;
110 class RandomGenerator {
122 while (data_.size() < 1048576) {
131 Slice Generate(
int len) {
132 if (pos_ + len > data_.size()) {
134 assert(len < data_.size());
137 return Slice(data_.data() + pos_ - len, len);
141 static Slice TrimSpace(Slice s) {
143 while (start < s.size() && isspace(s[start])) {
146 int limit = s.size();
147 while (limit > start && isspace(s[limit-1])) {
150 return Slice(s.data() +
start, limit -
start);
153 static void AppendWithSpace(std::string* str, Slice msg) {
154 if (msg.empty())
return;
158 str->append(msg.data(), msg.size());
188 void Merge(
const Stats& other) {
189 hist_.Merge(other.hist_);
190 done_ += other.done_;
191 bytes_ += other.bytes_;
192 seconds_ += other.seconds_;
193 if (other.start_ < start_) start_ = other.start_;
194 if (other.finish_ > finish_) finish_ = other.finish_;
197 if (message_.empty()) message_ = other.message_;
202 seconds_ = (finish_ -
start_) * 1e-6;
205 void AddMessage(Slice msg) {
206 AppendWithSpace(&message_, msg);
209 void FinishedSingleOp() {
210 if (FLAGS_histogram) {
214 if (micros > 20000) {
215 fprintf(stderr,
"long op: %.1f micros%30s\r", micros,
"");
218 last_op_finish_ = now;
222 if (done_ >= next_report_) {
223 if (next_report_ < 1000) next_report_ += 100;
224 else if (next_report_ < 5000) next_report_ += 500;
225 else if (next_report_ < 10000) next_report_ += 1000;
226 else if (next_report_ < 50000) next_report_ += 5000;
227 else if (next_report_ < 100000) next_report_ += 10000;
228 else if (next_report_ < 500000) next_report_ += 50000;
229 else next_report_ += 100000;
230 fprintf(stderr,
"... finished %d ops%30s\r", done_,
"");
239 void Report(
const Slice&
name) {
242 if (done_ < 1) done_ = 1;
248 double elapsed = (finish_ -
start_) * 1e-6;
250 snprintf(rate,
sizeof(rate),
"%6.1f MB/s",
251 (bytes_ / 1048576.0) / elapsed);
254 AppendWithSpace(&extra, message_);
256 fprintf(stdout,
"%-12s : %11.3f micros/op;%s%s\n",
257 name.ToString().c_str(),
258 seconds_ * 1e6 /
done_,
259 (extra.empty() ?
"" :
" "),
261 if (FLAGS_histogram) {
262 fprintf(stdout,
"Microseconds per op:\n%s\n", hist_.ToString().c_str());
284 SharedState() : cv(&mu) { }
294 ThreadState(
int index)
315 const int kKeySize = 16;
317 fprintf(stdout,
"Keys: %d bytes each\n", kKeySize);
318 fprintf(stdout,
"Values: %d bytes each (%d bytes after compression)\n",
320 static_cast<int>(FLAGS_value_size * FLAGS_compression_ratio + 0.5));
321 fprintf(stdout,
"Entries: %d\n", num_);
322 fprintf(stdout,
"RawSize: %.1f MB (estimated)\n",
323 ((static_cast<int64_t>(kKeySize + FLAGS_value_size) * num_)
325 fprintf(stdout,
"FileSize: %.1f MB (estimated)\n",
326 (((kKeySize + FLAGS_value_size * FLAGS_compression_ratio) * num_)
329 fprintf(stdout,
"------------------------------------------------\n");
333 #if defined(__GNUC__) && !defined(__OPTIMIZE__)
335 "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n"
340 "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
344 const char text[] =
"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
345 std::string compressed;
347 fprintf(stdout,
"WARNING: Snappy compression is not enabled\n");
348 }
else if (compressed.size() >=
sizeof(text)) {
349 fprintf(stdout,
"WARNING: Snappy compression is not effective\n");
354 fprintf(stderr,
"LevelDB: version %d.%d\n",
355 kMajorVersion, kMinorVersion);
358 time_t now = time(NULL);
359 fprintf(stderr,
"Date: %s", ctime(&now));
361 FILE* cpuinfo = fopen(
"/proc/cpuinfo",
"r");
362 if (cpuinfo != NULL) {
365 std::string cpu_type;
366 std::string cache_size;
367 while (fgets(line,
sizeof(line), cpuinfo) != NULL) {
368 const char* sep = strchr(line,
':');
372 Slice key = TrimSpace(
Slice(line, sep - 1 - line));
374 if (key ==
"model name") {
377 }
else if (key ==
"cache size") {
382 fprintf(stderr,
"CPU: %d * %s\n", num_cpus, cpu_type.c_str());
383 fprintf(stderr,
"CPUCache: %s\n", cache_size.c_str());
390 : cache_(FLAGS_cache_size >= 0 ?
NewLRUCache(FLAGS_cache_size) : NULL),
391 filter_policy_(FLAGS_bloom_bits >= 0
396 value_size_(FLAGS_value_size),
397 entries_per_batch_(1),
398 reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
400 std::vector<std::string> files;
402 for (
int i = 0; i < files.size(); i++) {
407 if (!FLAGS_use_existing_db) {
422 const char* benchmarks = FLAGS_benchmarks;
423 while (benchmarks != NULL) {
424 const char* sep = strchr(benchmarks,
',');
430 name =
Slice(benchmarks, sep - benchmarks);
431 benchmarks = sep + 1;
436 reads_ = (FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads);
437 value_size_ = FLAGS_value_size;
438 entries_per_batch_ = 1;
441 void (
Benchmark::*method)(ThreadState*) = NULL;
442 bool fresh_db =
false;
443 int num_threads = FLAGS_threads;
445 if (name ==
Slice(
"fillseq")) {
448 }
else if (name ==
Slice(
"fillbatch")) {
450 entries_per_batch_ = 1000;
452 }
else if (name ==
Slice(
"fillrandom")) {
455 }
else if (name ==
Slice(
"overwrite")) {
458 }
else if (name ==
Slice(
"fillsync")) {
461 write_options_.
sync =
true;
463 }
else if (name ==
Slice(
"fill100K")) {
466 value_size_ = 100 * 1000;
468 }
else if (name ==
Slice(
"readseq")) {
470 }
else if (name ==
Slice(
"readreverse")) {
472 }
else if (name ==
Slice(
"readrandom")) {
474 }
else if (name ==
Slice(
"readmissing")) {
476 }
else if (name ==
Slice(
"seekrandom")) {
478 }
else if (name ==
Slice(
"readhot")) {
480 }
else if (name ==
Slice(
"readrandomsmall")) {
483 }
else if (name ==
Slice(
"deleteseq")) {
485 }
else if (name ==
Slice(
"deleterandom")) {
487 }
else if (name ==
Slice(
"readwhilewriting")) {
490 }
else if (name ==
Slice(
"compact")) {
492 }
else if (name ==
Slice(
"crc32c")) {
494 }
else if (name ==
Slice(
"acquireload")) {
496 }
else if (name ==
Slice(
"snappycomp")) {
498 }
else if (name ==
Slice(
"snappyuncomp")) {
500 }
else if (name ==
Slice(
"heapprofile")) {
502 }
else if (name ==
Slice(
"stats")) {
504 }
else if (name ==
Slice(
"sstables")) {
507 if (name !=
Slice()) {
508 fprintf(stderr,
"unknown benchmark '%s'\n", name.
ToString().c_str());
513 if (FLAGS_use_existing_db) {
514 fprintf(stdout,
"%-12s : skipped (--use_existing_db is true)\n",
525 if (method != NULL) {
542 ThreadState* thread = arg->
thread;
545 shared->num_initialized++;
546 if (shared->num_initialized >= shared->total) {
547 shared->cv.SignalAll();
549 while (!shared->start) {
554 thread->stats.Start();
556 thread->stats.Stop();
561 if (shared->num_done >= shared->total) {
562 shared->cv.SignalAll();
568 void (
Benchmark::*method)(ThreadState*)) {
571 shared.num_initialized = 0;
573 shared.start =
false;
576 for (
int i = 0; i < n; i++) {
580 arg[i].
thread =
new ThreadState(i);
586 while (shared.num_initialized < n) {
591 shared.cv.SignalAll();
592 while (shared.num_done < n) {
597 for (
int i = 1; i < n; i++) {
598 arg[0].
thread->stats.Merge(arg[i].thread->stats);
600 arg[0].
thread->stats.Report(name);
602 for (
int i = 0; i < n; i++) {
610 const int size = 4096;
611 const char* label =
"(4K per op)";
612 std::string data(size,
'x');
615 while (bytes < 500 * 1048576) {
617 thread->stats.FinishedSingleOp();
621 fprintf(stderr,
"... crc=0x%x\r", static_cast<unsigned int>(crc));
623 thread->stats.AddBytes(bytes);
624 thread->stats.AddMessage(label);
632 thread->stats.AddMessage(
"(each op is 1000 loads)");
633 while (count < 100000) {
634 for (
int i = 0; i < 1000; i++) {
638 thread->stats.FinishedSingleOp();
640 if (ptr == NULL) exit(1);
649 std::string compressed;
650 while (ok && bytes < 1024 * 1048576) {
652 produced += compressed.size();
653 bytes += input.
size();
654 thread->stats.FinishedSingleOp();
658 thread->stats.AddMessage(
"(snappy failure)");
661 snprintf(buf,
sizeof(buf),
"(output: %.1f%%)",
662 (produced * 100.0) / bytes);
663 thread->stats.AddMessage(buf);
664 thread->stats.AddBytes(bytes);
671 std::string compressed;
674 char* uncompressed =
new char[input.
size()];
675 while (ok && bytes < 1024 * 1048576) {
678 bytes += input.
size();
679 thread->stats.FinishedSingleOp();
681 delete[] uncompressed;
684 thread->stats.AddMessage(
"(snappy failure)");
686 thread->stats.AddBytes(bytes);
700 fprintf(stderr,
"open error: %s\n", s.
ToString().c_str());
714 if (num_ != FLAGS_num) {
716 snprintf(msg,
sizeof(msg),
"(%d ops)", num_);
717 thread->stats.AddMessage(msg);
727 const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num);
729 snprintf(key,
sizeof(key),
"%016d", k);
730 batch.
Put(key, gen.Generate(value_size_));
731 bytes += value_size_ + strlen(key);
732 thread->stats.FinishedSingleOp();
734 s = db_->
Write(write_options_, &batch);
736 fprintf(stderr,
"put error: %s\n", s.
ToString().c_str());
740 thread->stats.AddBytes(bytes);
749 thread->stats.FinishedSingleOp();
753 thread->stats.AddBytes(bytes);
762 thread->stats.FinishedSingleOp();
766 thread->stats.AddBytes(bytes);
773 for (
int i = 0; i <
reads_; i++) {
775 const int k = thread->rand.Next() % FLAGS_num;
776 snprintf(key,
sizeof(key),
"%016d", k);
777 if (db_->
Get(options, key, &value).
ok()) {
780 thread->stats.FinishedSingleOp();
783 snprintf(msg,
sizeof(msg),
"(%d of %d found)", found, num_);
784 thread->stats.AddMessage(msg);
790 for (
int i = 0; i <
reads_; i++) {
792 const int k = thread->rand.Next() % FLAGS_num;
793 snprintf(key,
sizeof(key),
"%016d.", k);
794 db_->
Get(options, key, &value);
795 thread->stats.FinishedSingleOp();
802 const int range = (FLAGS_num + 99) / 100;
803 for (
int i = 0; i <
reads_; i++) {
805 const int k = thread->rand.Next() % range;
806 snprintf(key,
sizeof(key),
"%016d", k);
807 db_->
Get(options, key, &value);
808 thread->stats.FinishedSingleOp();
816 for (
int i = 0; i <
reads_; i++) {
819 const int k = thread->rand.Next() % FLAGS_num;
820 snprintf(key,
sizeof(key),
"%016d", k);
822 if (iter->
Valid() && iter->
key() == key) found++;
824 thread->stats.FinishedSingleOp();
827 snprintf(msg,
sizeof(msg),
"(%d of %d found)", found, num_);
828 thread->stats.AddMessage(msg);
838 const int k = seq ? i+j : (thread->rand.Next() % FLAGS_num);
840 snprintf(key,
sizeof(key),
"%016d", k);
842 thread->stats.FinishedSingleOp();
844 s = db_->
Write(write_options_, &batch);
846 fprintf(stderr,
"del error: %s\n", s.
ToString().c_str());
861 if (thread->tid > 0) {
869 if (thread->shared->num_done + 1 >= thread->shared->num_initialized) {
875 const int k = thread->rand.Next() % FLAGS_num;
877 snprintf(key,
sizeof(key),
"%016d", k);
878 Status s = db_->
Put(write_options_, key, gen.Generate(value_size_));
880 fprintf(stderr,
"put error: %s\n", s.
ToString().c_str());
886 thread->stats.Start();
899 fprintf(stdout,
"\n%s\n", stats.c_str());
908 snprintf(fname,
sizeof(fname),
"%s/heap-%04d", FLAGS_db, ++heap_counter_);
912 fprintf(stderr,
"%s\n", s.
ToString().c_str());
918 fprintf(stderr,
"heap profiling not supported\n");
926 int main(
int argc,
char** argv) {
929 std::string default_db_path;
931 for (
int i = 1; i < argc; i++) {
936 FLAGS_benchmarks = argv[i] + strlen(
"--benchmarks=");
937 }
else if (sscanf(argv[i],
"--compression_ratio=%lf%c", &d, &junk) == 1) {
938 FLAGS_compression_ratio = d;
939 }
else if (sscanf(argv[i],
"--histogram=%d%c", &n, &junk) == 1 &&
940 (n == 0 || n == 1)) {
942 }
else if (sscanf(argv[i],
"--use_existing_db=%d%c", &n, &junk) == 1 &&
943 (n == 0 || n == 1)) {
944 FLAGS_use_existing_db = n;
945 }
else if (sscanf(argv[i],
"--num=%d%c", &n, &junk) == 1) {
947 }
else if (sscanf(argv[i],
"--reads=%d%c", &n, &junk) == 1) {
949 }
else if (sscanf(argv[i],
"--threads=%d%c", &n, &junk) == 1) {
951 }
else if (sscanf(argv[i],
"--value_size=%d%c", &n, &junk) == 1) {
952 FLAGS_value_size = n;
953 }
else if (sscanf(argv[i],
"--write_buffer_size=%d%c", &n, &junk) == 1) {
954 FLAGS_write_buffer_size = n;
955 }
else if (sscanf(argv[i],
"--cache_size=%d%c", &n, &junk) == 1) {
956 FLAGS_cache_size = n;
957 }
else if (sscanf(argv[i],
"--bloom_bits=%d%c", &n, &junk) == 1) {
958 FLAGS_bloom_bits = n;
959 }
else if (sscanf(argv[i],
"--open_files=%d%c", &n, &junk) == 1) {
960 FLAGS_open_files = n;
961 }
else if (strncmp(argv[i],
"--db=", 5) == 0) {
962 FLAGS_db = argv[i] + 5;
964 fprintf(stderr,
"Invalid flag '%s'\n", argv[i]);
970 if (FLAGS_db == NULL) {
972 default_db_path +=
"/dbbench";
973 FLAGS_db = default_db_path.c_str();
virtual void CompactRange(const Slice *begin, const Slice *end)=0
void WriteRandom(ThreadState *thread)
void RunBenchmark(int n, Slice name, void(Benchmark::*method)(ThreadState *))
virtual Status DeleteFile(const std::string &fname)=0
virtual Status Write(const WriteOptions &options, WriteBatch *updates)=0
bool Snappy_Uncompress(const char *input_data, size_t input_length, char *output)
static void WriteToFile(void *arg, const char *buf, int n)
void ReadReverse(ThreadState *thread)
void * Acquire_Load() const
bool starts_with(const Slice &x) const
const char * data() const
void ReadWhileWriting(ThreadState *thread)
void SnappyCompress(ThreadState *thread)
void AcquireLoad(ThreadState *thread)
void DeleteRandom(ThreadState *thread)
Slice CompressibleString(Random *rnd, double compressed_fraction, int len, std::string *dst)
virtual Iterator * NewIterator(const ReadOptions &options)=0
void Delete(const Slice &key)
virtual Slice value() const =0
Status DestroyDB(const std::string &dbname, const Options &options)
void SnappyUncompress(ThreadState *thread)
virtual void SeekToLast()=0
virtual Status GetChildren(const std::string &dir, std::vector< std::string > *result)=0
int std::string int dummy
void(Benchmark::* method)(ThreadState *)
bool Snappy_Compress(const char *input, size_t input_length, std::string *output)
static Status Open(const Options &options, const std::string &name, DB **dbptr)
bool GetHeapProfile(void(*func)(void *, const char *, int), void *arg)
virtual void Seek(const Slice &target)=0
void DoWrite(ThreadState *thread, bool seq)
const FilterPolicy * NewBloomFilterPolicy(int bits_per_key)
void ReadHot(ThreadState *thread)
virtual void SeekToFirst()=0
void SeekRandom(ThreadState *thread)
virtual Status GetTestDirectory(std::string *path)=0
void Crc32c(ThreadState *thread)
void ReadMissing(ThreadState *thread)
void ReadSequential(ThreadState *thread)
void Compact(ThreadState *thread)
int main(int argc, char **argv)
void DeleteSeq(ThreadState *thread)
const FilterPolicy * filter_policy
Cache * NewLRUCache(size_t capacity)
uint32_t Value(const char *data, size_t n)
virtual Status Get(const ReadOptions &options, const Slice &key, std::string *value)=0
const FilterPolicy * filter_policy_
void PrintStats(const char *key)
virtual bool Valid() const =0
void DoDelete(ThreadState *thread, bool seq)
void ReadRandom(ThreadState *thread)
virtual Slice key() const =0
virtual Status NewWritableFile(const std::string &fname, WritableFile **result)=0
virtual bool GetProperty(const Slice &property, std::string *value)=0
static void ThreadBody(void *v)
std::string ToString() const
virtual void StartThread(void(*function)(void *arg), void *arg)=0
void Put(const Slice &key, const Slice &value)
WriteOptions write_options_
void WriteSeq(ThreadState *thread)
virtual Status Put(const WriteOptions &options, const Slice &key, const Slice &value)=0
std::string ToString() const
virtual uint64_t NowMicros()=0