FSTLevelDBBenchmarkTests.mm 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <Foundation/Foundation.h>
  17. #import <XCTest/XCTest.h>
  18. #include <cstdint>
  19. #include "Firestore/core/src/firebase/firestore/local/leveldb_key.h"
  20. #include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
  21. #include "Firestore/core/src/firebase/firestore/local/local_serializer.h"
  22. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  23. #include "Firestore/core/src/firebase/firestore/model/types.h"
  24. #include "Firestore/core/src/firebase/firestore/remote/serializer.h"
  25. #include "Firestore/core/src/firebase/firestore/util/filesystem.h"
  26. #include "Firestore/core/src/firebase/firestore/util/path.h"
  27. #include "Firestore/core/src/firebase/firestore/util/string_format.h"
  28. #include "benchmark/benchmark.h"
  29. NS_ASSUME_NONNULL_BEGIN
  30. namespace util = firebase::firestore::util;
  31. using firebase::firestore::local::LevelDbDocumentTargetKey;
  32. using firebase::firestore::local::LevelDbRemoteDocumentKey;
  33. using firebase::firestore::local::LevelDbTargetDocumentKey;
  34. using firebase::firestore::local::LevelDbTransaction;
  35. using firebase::firestore::local::LocalSerializer;
  36. using firebase::firestore::model::DatabaseId;
  37. using firebase::firestore::model::DocumentKey;
  38. using firebase::firestore::model::TargetId;
  39. using firebase::firestore::remote::Serializer;
  40. using firebase::firestore::util::StringFormat;
  41. using firebase::firestore::util::Path;
  42. namespace {
  43. // Pre-existing document size
  44. const int kDocumentSize = 1024 * 2; // 2 kb
  45. std::string DocumentData() {
  46. return std::string(kDocumentSize, 'a');
  47. }
  48. std::string UpdatedDocumentData(int64_t documentSize) {
  49. return std::string(documentSize, 'b');
  50. }
  51. FSTLevelDB *LevelDBPersistence() {
  52. DatabaseId db_id("p", "d");
  53. Serializer remoteSerializer{db_id};
  54. LocalSerializer serializer{std::move(remoteSerializer)};
  55. FSTLevelDB *db;
  56. Path path = util::TempDir().AppendUtf8("FSTLevelDBBenchmarkTests");
  57. util::Status status = [FSTLevelDB dbWithDirectory:std::move(path)
  58. serializer:std::move(serializer)
  59. lruParams:local::LruParams::Disabled()
  60. ptr:&db];
  61. if (!status.ok()) {
  62. [NSException raise:NSInternalInconsistencyException
  63. format:@"Failed to open DB: %s", status.ToString().c_str()];
  64. }
  65. return db;
  66. }
  67. } // namespace
  68. class LevelDBFixture : public benchmark::Fixture {
  69. void SetUp(benchmark::State &state) override {
  70. db_ = LevelDBPersistence();
  71. FillDB();
  72. }
  73. void TearDown(benchmark::State &state) override {
  74. db_->Shutdown();
  75. db_.reset();
  76. }
  77. void FillDB() {
  78. LevelDbTransaction txn(db_.ptr, "benchmark");
  79. for (int i = 0; i < numDocuments_; i++) {
  80. auto docKey = DocumentKey::FromPathString(StringFormat("docs/doc_%i", i));
  81. std::string docKeyString = LevelDbRemoteDocumentKey::Key(docKey);
  82. txn.Put(docKeyString, DocumentData());
  83. WriteIndex(&txn, docKey);
  84. }
  85. txn.Commit();
  86. // Force a write to disk to simulate startup situation
  87. db_.ptr->CompactRange(NULL, NULL);
  88. }
  89. protected:
  90. void WriteIndex(LevelDbTransaction *txn, const DocumentKey &docKey) {
  91. // Arbitrary target ID
  92. TargetId targetID = 1;
  93. txn->Put(LevelDbDocumentTargetKey::Key(docKey, targetID), emptyBuffer_);
  94. txn->Put(LevelDbTargetDocumentKey::Key(targetID, docKey), emptyBuffer_);
  95. }
  96. FSTLevelDB *db_;
  97. int numDocuments_ = 10;
  98. std::string emptyBuffer_;
  99. };
  100. // Plan: write a bunch of key/value pairs w/ empty strings (index entries)
  101. // Write a couple large values (documents)
  102. // In each test, either overwrite index entries and documents, or just documents
  103. BENCHMARK_DEFINE_F(LevelDBFixture, RemoteEvent)(benchmark::State &state) { // NOLINT
  104. bool writeIndexes = static_cast<bool>(state.range(0));
  105. int64_t documentSize = state.range(1);
  106. int64_t docsToUpdate = state.range(2);
  107. std::string documentUpdate = UpdatedDocumentData(documentSize);
  108. for (auto _ : state) {
  109. LevelDbTransaction txn(db_.ptr, "benchmark");
  110. for (int i = 0; i < docsToUpdate; i++) {
  111. auto docKey = DocumentKey::FromPathString(StringFormat("docs/doc_%i", i));
  112. if (writeIndexes) WriteIndex(&txn, docKey);
  113. std::string docKeyString = LevelDbRemoteDocumentKey::Key(docKey);
  114. txn.Put(docKeyString, documentUpdate);
  115. }
  116. txn.Commit();
  117. }
  118. }
  119. /**
  120. * Adjust ranges to control what test cases run. Outermost loop controls whether or
  121. * not indexes are written, the inner loops control size of document writes and number
  122. * of document writes.
  123. */
  124. static void TestCases(benchmark::internal::Benchmark *b) {
  125. for (int writeIndexes = 0; writeIndexes <= 1; writeIndexes++) {
  126. for (int documentSize = 1 << 10; documentSize <= 1 << 20; documentSize *= 4) {
  127. for (int docsToUpdate = 1; docsToUpdate <= 5; docsToUpdate++) {
  128. b->Args({writeIndexes, documentSize, docsToUpdate});
  129. }
  130. }
  131. }
  132. }
  133. BENCHMARK_REGISTER_F(LevelDBFixture, RemoteEvent)
  134. ->Apply(TestCases)
  135. ->Unit(benchmark::kMicrosecond)
  136. ->Repetitions(5);
  137. @interface FSTLevelDBBenchmarkTests : XCTestCase
  138. @end
  139. @implementation FSTLevelDBBenchmarkTests
  140. - (void)testRunBenchmarks {
  141. // Enable to run benchmarks.
  142. char *argv[3] = {const_cast<char *>("Benchmarks"),
  143. const_cast<char *>("--benchmark_out=/tmp/leveldb_benchmark"),
  144. const_cast<char *>("--benchmark_out_format=csv")};
  145. int argc = 3;
  146. benchmark::Initialize(&argc, argv);
  147. benchmark::RunSpecifiedBenchmarks();
  148. }
  149. @end
  150. NS_ASSUME_NONNULL_END