作者: 韩晨旭 10225101440 李畅 10225102463
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

682 lines
21 KiB

  1. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <sqlite3.h>
  7. #include "util/histogram.h"
  8. #include "util/random.h"
  9. #include "util/testutil.h"
  10. // Comma-separated list of operations to run in the specified order
  11. // Actual benchmarks:
  12. //
  13. // fillseq -- write N values in sequential key order in async mode
  14. // fillseqsync -- write N/100 values in sequential key order in sync mode
  15. // fillseqbatch -- batch write N values in sequential key order in async mode
  16. // fillrandom -- write N values in random key order in async mode
  17. // fillrandsync -- write N/100 values in random key order in sync mode
  18. // fillrandbatch -- batch write N values in sequential key order in async mode
  19. // overwrite -- overwrite N values in random key order in async mode
  20. // fillrand100K -- write N/1000 100K values in random order in async mode
  21. // fillseq100K -- write N/1000 100K values in sequential order in async mode
  22. // readseq -- read N times sequentially
  23. // readrandom -- read N times in random order
  24. // readseq100K -- read N/1000 100K values in sequential order in async mode
  25. // readrand100K -- read N/1000 100K values in sequential order in async mode
  26. static const char* FLAGS_benchmarks =
  27. "fillseq,"
  28. "fillseqsync,"
  29. "fillseqbatch,"
  30. "fillrandom,"
  31. "fillrandsync,"
  32. "fillrandbatch,"
  33. "overwrite,"
  34. "overwritebatch,"
  35. "readrandom,"
  36. "readseq,"
  37. "fillrand100K,"
  38. "fillseq100K,"
  39. "readseq100K,"
  40. "readrand100K,"
  41. ;
  42. // Number of key/values to place in database
  43. static int FLAGS_num = 1000000;
  44. // Number of read operations to do. If negative, do FLAGS_num reads.
  45. static int FLAGS_reads = -1;
  46. // Size of each value
  47. static int FLAGS_value_size = 100;
  48. // Print histogram of operation timings
  49. static bool FLAGS_histogram = false;
  50. // Arrange to generate values that shrink to this fraction of
  51. // their original size after compression
  52. static double FLAGS_compression_ratio = 0.5;
  53. // Page size. Default 1 KB.
  54. static int FLAGS_page_size = 1024;
  55. // Number of pages.
  56. // Default cache size = FLAGS_page_size * FLAGS_num_pages = 4 MB.
  57. static int FLAGS_num_pages = 4096;
  58. // If true, do not destroy the existing database. If you set this
  59. // flag and also specify a benchmark that wants a fresh database, that
  60. // benchmark will fail.
  61. static bool FLAGS_use_existing_db = false;
  62. // If true, we allow batch writes to occur
  63. static bool FLAGS_transaction = true;
  64. // If true, we enable Write-Ahead Logging
  65. static bool FLAGS_WAL_enabled = false;
  66. inline
  67. static void ExecErrorCheck(int status, char *err_msg) {
  68. if (status != SQLITE_OK) {
  69. fprintf(stderr, "SQL error: %s\n", err_msg);
  70. sqlite3_free(err_msg);
  71. exit(1);
  72. }
  73. }
  74. inline
  75. static void StepErrorCheck(int status) {
  76. if (status != SQLITE_DONE) {
  77. fprintf(stderr, "SQL step error: status = %d\n", status);
  78. exit(1);
  79. }
  80. }
  81. inline
  82. static void ErrorCheck(int status) {
  83. if (status != SQLITE_OK) {
  84. fprintf(stderr, "sqlite3 error: status = %d\n", status);
  85. exit(1);
  86. }
  87. }
  88. inline
  89. static void WalCheckpoint(sqlite3* db_) {
  90. // Flush all writes to disk
  91. if (FLAGS_WAL_enabled) {
  92. sqlite3_wal_checkpoint_v2(db_, NULL, SQLITE_CHECKPOINT_FULL, NULL, NULL);
  93. }
  94. }
  95. namespace leveldb {
  96. // Helper for quickly generating random data.
  97. namespace {
  98. class RandomGenerator {
  99. private:
  100. std::string data_;
  101. int pos_;
  102. public:
  103. RandomGenerator() {
  104. // We use a limited amount of data over and over again and ensure
  105. // that it is larger than the compression window (32KB), and also
  106. // large enough to serve all typical value sizes we want to write.
  107. Random rnd(301);
  108. std::string piece;
  109. while (data_.size() < 1048576) {
  110. // Add a short fragment that is as compressible as specified
  111. // by FLAGS_compression_ratio.
  112. test::CompressibleString(&rnd, FLAGS_compression_ratio, 100, &piece);
  113. data_.append(piece);
  114. }
  115. pos_ = 0;
  116. }
  117. Slice Generate(int len) {
  118. if (pos_ + len > data_.size()) {
  119. pos_ = 0;
  120. assert(len < data_.size());
  121. }
  122. pos_ += len;
  123. return Slice(data_.data() + pos_ - len, len);
  124. }
  125. };
  126. static Slice TrimSpace(Slice s) {
  127. int start = 0;
  128. while (start < s.size() && isspace(s[start])) {
  129. start++;
  130. }
  131. int limit = s.size();
  132. while (limit > start && isspace(s[limit-1])) {
  133. limit--;
  134. }
  135. return Slice(s.data() + start, limit - start);
  136. }
  137. }
  138. class Benchmark {
  139. private:
  140. sqlite3* db_;
  141. int db_num_;
  142. int num_;
  143. int reads_;
  144. double start_;
  145. double last_op_finish_;
  146. int64_t bytes_;
  147. std::string message_;
  148. Histogram hist_;
  149. RandomGenerator gen_;
  150. Random rand_;
  151. // State kept for progress messages
  152. int done_;
  153. int next_report_; // When to report next
  154. void PrintHeader() {
  155. const int kKeySize = 16;
  156. PrintEnvironment();
  157. fprintf(stdout, "Keys: %d bytes each\n", kKeySize);
  158. fprintf(stdout, "Values: %d bytes each\n", FLAGS_value_size);
  159. fprintf(stdout, "Entries: %d\n", num_);
  160. fprintf(stdout, "RawSize: %.1f MB (estimated)\n",
  161. ((static_cast<int64_t>(kKeySize + FLAGS_value_size) * num_)
  162. / 1048576.0));
  163. PrintWarnings();
  164. fprintf(stdout, "------------------------------------------------\n");
  165. }
  166. void PrintWarnings() {
  167. #if defined(__GNUC__) && !defined(__OPTIMIZE__)
  168. fprintf(stdout,
  169. "WARNING: Optimization is disabled: benchmarks unnecessarily slow\n"
  170. );
  171. #endif
  172. #ifndef NDEBUG
  173. fprintf(stdout,
  174. "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
  175. #endif
  176. }
  177. void PrintEnvironment() {
  178. fprintf(stderr, "SQLite: version %s\n", SQLITE_VERSION);
  179. #if defined(__linux)
  180. time_t now = time(NULL);
  181. fprintf(stderr, "Date: %s", ctime(&now)); // ctime() adds newline
  182. FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
  183. if (cpuinfo != NULL) {
  184. char line[1000];
  185. int num_cpus = 0;
  186. std::string cpu_type;
  187. std::string cache_size;
  188. while (fgets(line, sizeof(line), cpuinfo) != NULL) {
  189. const char* sep = strchr(line, ':');
  190. if (sep == NULL) {
  191. continue;
  192. }
  193. Slice key = TrimSpace(Slice(line, sep - 1 - line));
  194. Slice val = TrimSpace(Slice(sep + 1));
  195. if (key == "model name") {
  196. ++num_cpus;
  197. cpu_type = val.ToString();
  198. } else if (key == "cache size") {
  199. cache_size = val.ToString();
  200. }
  201. }
  202. fclose(cpuinfo);
  203. fprintf(stderr, "CPU: %d * %s\n", num_cpus, cpu_type.c_str());
  204. fprintf(stderr, "CPUCache: %s\n", cache_size.c_str());
  205. }
  206. #endif
  207. }
  208. void Start() {
  209. start_ = Env::Default()->NowMicros() * 1e-6;
  210. bytes_ = 0;
  211. message_.clear();
  212. last_op_finish_ = start_;
  213. hist_.Clear();
  214. done_ = 0;
  215. next_report_ = 100;
  216. }
  217. void FinishedSingleOp() {
  218. if (FLAGS_histogram) {
  219. double now = Env::Default()->NowMicros() * 1e-6;
  220. double micros = (now - last_op_finish_) * 1e6;
  221. hist_.Add(micros);
  222. if (micros > 20000) {
  223. fprintf(stderr, "long op: %.1f micros%30s\r", micros, "");
  224. fflush(stderr);
  225. }
  226. last_op_finish_ = now;
  227. }
  228. done_++;
  229. if (done_ >= next_report_) {
  230. if (next_report_ < 1000) next_report_ += 100;
  231. else if (next_report_ < 5000) next_report_ += 500;
  232. else if (next_report_ < 10000) next_report_ += 1000;
  233. else if (next_report_ < 50000) next_report_ += 5000;
  234. else if (next_report_ < 100000) next_report_ += 10000;
  235. else if (next_report_ < 500000) next_report_ += 50000;
  236. else next_report_ += 100000;
  237. fprintf(stderr, "... finished %d ops%30s\r", done_, "");
  238. fflush(stderr);
  239. }
  240. }
  241. void Stop(const Slice& name) {
  242. double finish = Env::Default()->NowMicros() * 1e-6;
  243. // Pretend at least one op was done in case we are running a benchmark
  244. // that does not call FinishedSingleOp().
  245. if (done_ < 1) done_ = 1;
  246. if (bytes_ > 0) {
  247. char rate[100];
  248. snprintf(rate, sizeof(rate), "%6.1f MB/s",
  249. (bytes_ / 1048576.0) / (finish - start_));
  250. if (!message_.empty()) {
  251. message_ = std::string(rate) + " " + message_;
  252. } else {
  253. message_ = rate;
  254. }
  255. }
  256. fprintf(stdout, "%-12s : %11.3f micros/op;%s%s\n",
  257. name.ToString().c_str(),
  258. (finish - start_) * 1e6 / done_,
  259. (message_.empty() ? "" : " "),
  260. message_.c_str());
  261. if (FLAGS_histogram) {
  262. fprintf(stdout, "Microseconds per op:\n%s\n", hist_.ToString().c_str());
  263. }
  264. fflush(stdout);
  265. }
  266. public:
  267. enum Order {
  268. SEQUENTIAL,
  269. RANDOM
  270. };
  271. enum DBState {
  272. FRESH,
  273. EXISTING
  274. };
  275. Benchmark()
  276. : db_(NULL),
  277. db_num_(0),
  278. num_(FLAGS_num),
  279. reads_(FLAGS_reads < 0 ? FLAGS_num : FLAGS_reads),
  280. bytes_(0),
  281. rand_(301) {
  282. std::vector<std::string> files;
  283. Env::Default()->GetChildren("/tmp", &files);
  284. if (!FLAGS_use_existing_db) {
  285. for (int i = 0; i < files.size(); i++) {
  286. if (Slice(files[i]).starts_with("dbbench_sqlite3")) {
  287. Env::Default()->DeleteFile("/tmp/" + files[i]);
  288. }
  289. }
  290. }
  291. }
  292. ~Benchmark() {
  293. int status = sqlite3_close(db_);
  294. ErrorCheck(status);
  295. }
  296. void Run() {
  297. PrintHeader();
  298. Open();
  299. const char* benchmarks = FLAGS_benchmarks;
  300. while (benchmarks != NULL) {
  301. const char* sep = strchr(benchmarks, ',');
  302. Slice name;
  303. if (sep == NULL) {
  304. name = benchmarks;
  305. benchmarks = NULL;
  306. } else {
  307. name = Slice(benchmarks, sep - benchmarks);
  308. benchmarks = sep + 1;
  309. }
  310. bytes_ = 0;
  311. Start();
  312. bool known = true;
  313. bool write_sync = false;
  314. if (name == Slice("fillseq")) {
  315. Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1);
  316. WalCheckpoint(db_);
  317. } else if (name == Slice("fillseqbatch")) {
  318. Write(write_sync, SEQUENTIAL, FRESH, num_, FLAGS_value_size, 1000);
  319. WalCheckpoint(db_);
  320. } else if (name == Slice("fillrandom")) {
  321. Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1);
  322. WalCheckpoint(db_);
  323. } else if (name == Slice("fillrandbatch")) {
  324. Write(write_sync, RANDOM, FRESH, num_, FLAGS_value_size, 1000);
  325. WalCheckpoint(db_);
  326. } else if (name == Slice("overwrite")) {
  327. Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1);
  328. WalCheckpoint(db_);
  329. } else if (name == Slice("overwritebatch")) {
  330. Write(write_sync, RANDOM, EXISTING, num_, FLAGS_value_size, 1000);
  331. WalCheckpoint(db_);
  332. } else if (name == Slice("fillrandsync")) {
  333. write_sync = true;
  334. Write(write_sync, RANDOM, FRESH, num_ / 100, FLAGS_value_size, 1);
  335. WalCheckpoint(db_);
  336. } else if (name == Slice("fillseqsync")) {
  337. write_sync = true;
  338. Write(write_sync, SEQUENTIAL, FRESH, num_ / 100, FLAGS_value_size, 1);
  339. WalCheckpoint(db_);
  340. } else if (name == Slice("fillrand100K")) {
  341. Write(write_sync, RANDOM, FRESH, num_ / 1000, 100 * 1000, 1);
  342. WalCheckpoint(db_);
  343. } else if (name == Slice("fillseq100K")) {
  344. Write(write_sync, SEQUENTIAL, FRESH, num_ / 1000, 100 * 1000, 1);
  345. WalCheckpoint(db_);
  346. } else if (name == Slice("readseq")) {
  347. Read(SEQUENTIAL, 1);
  348. } else if (name == Slice("readrandom")) {
  349. Read(RANDOM, 1);
  350. } else if (name == Slice("readrand100K")) {
  351. int n = reads_;
  352. reads_ /= 1000;
  353. Read(RANDOM, 1);
  354. reads_ = n;
  355. } else if (name == Slice("readseq100K")) {
  356. int n = reads_;
  357. reads_ /= 1000;
  358. Read(SEQUENTIAL, 1);
  359. reads_ = n;
  360. } else {
  361. known = false;
  362. if (name != Slice()) { // No error message for empty name
  363. fprintf(stderr, "unknown benchmark '%s'\n", name.ToString().c_str());
  364. }
  365. }
  366. if (known) {
  367. Stop(name);
  368. }
  369. }
  370. }
  371. void Open() {
  372. assert(db_ == NULL);
  373. int status;
  374. char file_name[100];
  375. char* err_msg = NULL;
  376. db_num_++;
  377. // Open database
  378. snprintf(file_name, sizeof(file_name), "/tmp/dbbench_sqlite3-%d.db",
  379. db_num_);
  380. status = sqlite3_open(file_name, &db_);
  381. if (status) {
  382. fprintf(stderr, "open error: %s\n", sqlite3_errmsg(db_));
  383. exit(1);
  384. }
  385. // Change SQLite cache size
  386. char cache_size[100];
  387. snprintf(cache_size, sizeof(cache_size), "PRAGMA cache_size = %d",
  388. FLAGS_num_pages);
  389. status = sqlite3_exec(db_, cache_size, NULL, NULL, &err_msg);
  390. ExecErrorCheck(status, err_msg);
  391. // FLAGS_page_size is defaulted to 1024
  392. if (FLAGS_page_size != 1024) {
  393. char page_size[100];
  394. snprintf(page_size, sizeof(page_size), "PRAGMA page_size = %d",
  395. FLAGS_page_size);
  396. status = sqlite3_exec(db_, page_size, NULL, NULL, &err_msg);
  397. ExecErrorCheck(status, err_msg);
  398. }
  399. // Change journal mode to WAL if WAL enabled flag is on
  400. if (FLAGS_WAL_enabled) {
  401. std::string WAL_stmt = "PRAGMA journal_mode = WAL";
  402. status = sqlite3_exec(db_, WAL_stmt.c_str(), NULL, NULL, &err_msg);
  403. ExecErrorCheck(status, err_msg);
  404. }
  405. // Change locking mode to exclusive and create tables/index for database
  406. std::string locking_stmt = "PRAGMA locking_mode = EXCLUSIVE";
  407. std::string create_stmt =
  408. "CREATE TABLE test (key blob, value blob, PRIMARY KEY(key))";
  409. std::string index_stmt = "CREATE INDEX keyindex ON test (key)";
  410. std::string stmt_array[] = { locking_stmt, create_stmt, index_stmt };
  411. int stmt_array_length = sizeof(stmt_array) / sizeof(std::string);
  412. for (int i = 0; i < stmt_array_length; i++) {
  413. status = sqlite3_exec(db_, stmt_array[i].c_str(), NULL, NULL, &err_msg);
  414. ExecErrorCheck(status, err_msg);
  415. }
  416. }
  417. void Write(bool write_sync, Order order, DBState state,
  418. int num_entries, int value_size, int entries_per_batch) {
  419. // Create new database if state == FRESH
  420. if (state == FRESH) {
  421. if (FLAGS_use_existing_db) {
  422. message_ = "skipping (--use_existing_db is true)";
  423. return;
  424. }
  425. sqlite3_close(db_);
  426. db_ = NULL;
  427. Open();
  428. Start();
  429. }
  430. if (num_entries != num_) {
  431. char msg[100];
  432. snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
  433. message_ = msg;
  434. }
  435. char* err_msg = NULL;
  436. int status;
  437. sqlite3_stmt *replace_stmt, *begin_trans_stmt, *end_trans_stmt;
  438. std::string replace_str = "REPLACE INTO test (key, value) VALUES (?, ?)";
  439. std::string begin_trans_str = "BEGIN TRANSACTION;";
  440. std::string end_trans_str = "END TRANSACTION;";
  441. // Check for synchronous flag in options
  442. std::string sync_stmt = (write_sync) ? "PRAGMA synchronous = FULL" :
  443. "PRAGMA synchronous = OFF";
  444. status = sqlite3_exec(db_, sync_stmt.c_str(), NULL, NULL, &err_msg);
  445. ExecErrorCheck(status, err_msg);
  446. // Preparing sqlite3 statements
  447. status = sqlite3_prepare_v2(db_, replace_str.c_str(), -1,
  448. &replace_stmt, NULL);
  449. ErrorCheck(status);
  450. status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1,
  451. &begin_trans_stmt, NULL);
  452. ErrorCheck(status);
  453. status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1,
  454. &end_trans_stmt, NULL);
  455. ErrorCheck(status);
  456. bool transaction = (entries_per_batch > 1);
  457. for (int i = 0; i < num_entries; i += entries_per_batch) {
  458. // Begin write transaction
  459. if (FLAGS_transaction && transaction) {
  460. status = sqlite3_step(begin_trans_stmt);
  461. StepErrorCheck(status);
  462. status = sqlite3_reset(begin_trans_stmt);
  463. ErrorCheck(status);
  464. }
  465. // Create and execute SQL statements
  466. for (int j = 0; j < entries_per_batch; j++) {
  467. const char* value = gen_.Generate(value_size).data();
  468. // Create values for key-value pair
  469. const int k = (order == SEQUENTIAL) ? i + j :
  470. (rand_.Next() % num_entries);
  471. char key[100];
  472. snprintf(key, sizeof(key), "%016d", k);
  473. // Bind KV values into replace_stmt
  474. status = sqlite3_bind_blob(replace_stmt, 1, key, 16, SQLITE_STATIC);
  475. ErrorCheck(status);
  476. status = sqlite3_bind_blob(replace_stmt, 2, value,
  477. value_size, SQLITE_STATIC);
  478. ErrorCheck(status);
  479. // Execute replace_stmt
  480. bytes_ += value_size + strlen(key);
  481. status = sqlite3_step(replace_stmt);
  482. StepErrorCheck(status);
  483. // Reset SQLite statement for another use
  484. status = sqlite3_clear_bindings(replace_stmt);
  485. ErrorCheck(status);
  486. status = sqlite3_reset(replace_stmt);
  487. ErrorCheck(status);
  488. FinishedSingleOp();
  489. }
  490. // End write transaction
  491. if (FLAGS_transaction && transaction) {
  492. status = sqlite3_step(end_trans_stmt);
  493. StepErrorCheck(status);
  494. status = sqlite3_reset(end_trans_stmt);
  495. ErrorCheck(status);
  496. }
  497. }
  498. status = sqlite3_finalize(replace_stmt);
  499. ErrorCheck(status);
  500. status = sqlite3_finalize(begin_trans_stmt);
  501. ErrorCheck(status);
  502. status = sqlite3_finalize(end_trans_stmt);
  503. ErrorCheck(status);
  504. }
  505. void Read(Order order, int entries_per_batch) {
  506. int status;
  507. sqlite3_stmt *read_stmt, *begin_trans_stmt, *end_trans_stmt;
  508. std::string read_str = "SELECT * FROM test WHERE key = ?";
  509. std::string begin_trans_str = "BEGIN TRANSACTION;";
  510. std::string end_trans_str = "END TRANSACTION;";
  511. // Preparing sqlite3 statements
  512. status = sqlite3_prepare_v2(db_, begin_trans_str.c_str(), -1,
  513. &begin_trans_stmt, NULL);
  514. ErrorCheck(status);
  515. status = sqlite3_prepare_v2(db_, end_trans_str.c_str(), -1,
  516. &end_trans_stmt, NULL);
  517. ErrorCheck(status);
  518. status = sqlite3_prepare_v2(db_, read_str.c_str(), -1, &read_stmt, NULL);
  519. ErrorCheck(status);
  520. bool transaction = (entries_per_batch > 1);
  521. for (int i = 0; i < reads_; i += entries_per_batch) {
  522. // Begin read transaction
  523. if (FLAGS_transaction && transaction) {
  524. status = sqlite3_step(begin_trans_stmt);
  525. StepErrorCheck(status);
  526. status = sqlite3_reset(begin_trans_stmt);
  527. ErrorCheck(status);
  528. }
  529. // Create and execute SQL statements
  530. for (int j = 0; j < entries_per_batch; j++) {
  531. // Create key value
  532. char key[100];
  533. int k = (order == SEQUENTIAL) ? i + j : (rand_.Next() % reads_);
  534. snprintf(key, sizeof(key), "%016d", k);
  535. // Bind key value into read_stmt
  536. status = sqlite3_bind_blob(read_stmt, 1, key, 16, SQLITE_STATIC);
  537. ErrorCheck(status);
  538. // Execute read statement
  539. while ((status = sqlite3_step(read_stmt)) == SQLITE_ROW);
  540. StepErrorCheck(status);
  541. // Reset SQLite statement for another use
  542. status = sqlite3_clear_bindings(read_stmt);
  543. ErrorCheck(status);
  544. status = sqlite3_reset(read_stmt);
  545. ErrorCheck(status);
  546. FinishedSingleOp();
  547. }
  548. // End read transaction
  549. if (FLAGS_transaction && transaction) {
  550. status = sqlite3_step(end_trans_stmt);
  551. StepErrorCheck(status);
  552. status = sqlite3_reset(end_trans_stmt);
  553. ErrorCheck(status);
  554. }
  555. }
  556. status = sqlite3_finalize(read_stmt);
  557. ErrorCheck(status);
  558. status = sqlite3_finalize(begin_trans_stmt);
  559. ErrorCheck(status);
  560. status = sqlite3_finalize(end_trans_stmt);
  561. ErrorCheck(status);
  562. }
  563. };
  564. }
  565. int main(int argc, char** argv) {
  566. for (int i = 1; i < argc; i++) {
  567. double d;
  568. int n;
  569. char junk;
  570. if (leveldb::Slice(argv[i]).starts_with("--benchmarks=")) {
  571. FLAGS_benchmarks = argv[i] + strlen("--benchmarks=");
  572. } else if (sscanf(argv[i], "--histogram=%d%c", &n, &junk) == 1 &&
  573. (n == 0 || n == 1)) {
  574. FLAGS_histogram = n;
  575. } else if (sscanf(argv[i], "--compression_ratio=%lf%c", &d, &junk) == 1) {
  576. FLAGS_compression_ratio = d;
  577. } else if (sscanf(argv[i], "--use_existing_db=%d%c", &n, &junk) == 1 &&
  578. (n == 0 || n == 1)) {
  579. FLAGS_use_existing_db = n;
  580. } else if (sscanf(argv[i], "--num=%d%c", &n, &junk) == 1) {
  581. FLAGS_num = n;
  582. } else if (sscanf(argv[i], "--reads=%d%c", &n, &junk) == 1) {
  583. FLAGS_reads = n;
  584. } else if (sscanf(argv[i], "--value_size=%d%c", &n, &junk) == 1) {
  585. FLAGS_value_size = n;
  586. } else if (leveldb::Slice(argv[i]) == leveldb::Slice("--no_transaction")) {
  587. FLAGS_transaction = false;
  588. } else if (sscanf(argv[i], "--page_size=%d%c", &n, &junk) == 1) {
  589. FLAGS_page_size = n;
  590. } else if (sscanf(argv[i], "--num_pages=%d%c", &n, &junk) == 1) {
  591. FLAGS_num_pages = n;
  592. } else if (sscanf(argv[i], "--WAL_enabled=%d%c", &n, &junk) == 1 &&
  593. (n == 0 || n == 1)) {
  594. FLAGS_WAL_enabled = n;
  595. } else {
  596. fprintf(stderr, "Invalid flag '%s'\n", argv[i]);
  597. exit(1);
  598. }
  599. }
  600. leveldb::Benchmark benchmark;
  601. benchmark.Run();
  602. return 0;
  603. }