FSTLevelDBBenchmarkTests.mm 5.9 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. #import "Firestore/Source/Local/FSTLevelDB.h"
  20. #import "Firestore/Source/Local/FSTLocalSerializer.h"
  21. #import "Firestore/Source/Remote/FSTSerializerBeta.h"
  22. #include "Firestore/core/src/firebase/firestore/local/leveldb_key.h"
  23. #include "Firestore/core/src/firebase/firestore/local/leveldb_transaction.h"
  24. #include "Firestore/core/src/firebase/firestore/model/document_key.h"
  25. #include "Firestore/core/src/firebase/firestore/model/types.h"
  26. #include "Firestore/core/src/firebase/firestore/util/filesystem.h"
  27. #include "Firestore/core/src/firebase/firestore/util/path.h"
  28. #include "Firestore/core/src/firebase/firestore/util/string_format.h"
  29. #include "benchmark/benchmark.h"
  30. NS_ASSUME_NONNULL_BEGIN
  31. namespace util = firebase::firestore::util;
  32. using firebase::firestore::local::LevelDbDocumentTargetKey;
  33. using firebase::firestore::local::LevelDbRemoteDocumentKey;
  34. using firebase::firestore::local::LevelDbTargetDocumentKey;
  35. using firebase::firestore::local::LevelDbTransaction;
  36. using firebase::firestore::model::DatabaseId;
  37. using firebase::firestore::model::DocumentKey;
  38. using firebase::firestore::model::TargetId;
  39. using firebase::firestore::util::StringFormat;
  40. using firebase::firestore::util::Path;
  41. namespace {
  42. // Pre-existing document size
  43. const int kDocumentSize = 1024 * 2; // 2 kb
  44. std::string DocumentData() {
  45. return std::string(kDocumentSize, 'a');
  46. }
  47. std::string UpdatedDocumentData(int64_t documentSize) {
  48. return std::string(documentSize, 'b');
  49. }
  50. FSTLevelDB *LevelDBPersistence() {
  51. DatabaseId db_id("p", "d");
  52. auto remoteSerializer = [[FSTSerializerBeta alloc] initWithDatabaseID:db_id];
  53. auto serializer = [[FSTLocalSerializer alloc] initWithRemoteSerializer:remoteSerializer];
  54. FSTLevelDB *db;
  55. Path path = util::TempDir().AppendUtf8("FSTLevelDBBenchmarkTests");
  56. util::Status status = [FSTLevelDB dbWithDirectory:std::move(path)
  57. serializer:serializer
  58. lruParams:local::LruParams::Disabled()
  59. ptr:&db];
  60. if (!status.ok()) {
  61. [NSException raise:NSInternalInconsistencyException
  62. format:@"Failed to open DB: %s", status.ToString().c_str()];
  63. }
  64. return db;
  65. }
  66. } // namespace
  67. class LevelDBFixture : public benchmark::Fixture {
  68. void SetUp(benchmark::State &state) override {
  69. db_ = LevelDBPersistence();
  70. FillDB();
  71. }
  72. void TearDown(benchmark::State &state) override {
  73. [db_ shutdown];
  74. db_ = nil;
  75. }
  76. void FillDB() {
  77. LevelDbTransaction txn(db_.ptr, "benchmark");
  78. for (int i = 0; i < numDocuments_; i++) {
  79. auto docKey = DocumentKey::FromPathString(StringFormat("docs/doc_%i", i));
  80. std::string docKeyString = LevelDbRemoteDocumentKey::Key(docKey);
  81. txn.Put(docKeyString, DocumentData());
  82. WriteIndex(&txn, docKey);
  83. }
  84. txn.Commit();
  85. // Force a write to disk to simulate startup situation
  86. db_.ptr->CompactRange(NULL, NULL);
  87. }
  88. protected:
  89. void WriteIndex(LevelDbTransaction *txn, const DocumentKey &docKey) {
  90. // Arbitrary target ID
  91. TargetId targetID = 1;
  92. txn->Put(LevelDbDocumentTargetKey::Key(docKey, targetID), emptyBuffer_);
  93. txn->Put(LevelDbTargetDocumentKey::Key(targetID, docKey), emptyBuffer_);
  94. }
  95. FSTLevelDB *db_;
  96. int numDocuments_ = 10;
  97. std::string emptyBuffer_;
  98. };
  99. // Plan: write a bunch of key/value pairs w/ empty strings (index entries)
  100. // Write a couple large values (documents)
  101. // In each test, either overwrite index entries and documents, or just documents
  102. BENCHMARK_DEFINE_F(LevelDBFixture, RemoteEvent)(benchmark::State &state) { // NOLINT
  103. bool writeIndexes = static_cast<bool>(state.range(0));
  104. int64_t documentSize = state.range(1);
  105. int64_t docsToUpdate = state.range(2);
  106. std::string documentUpdate = UpdatedDocumentData(documentSize);
  107. for (auto _ : state) {
  108. LevelDbTransaction txn(db_.ptr, "benchmark");
  109. for (int i = 0; i < docsToUpdate; i++) {
  110. auto docKey = DocumentKey::FromPathString(StringFormat("docs/doc_%i", i));
  111. if (writeIndexes) WriteIndex(&txn, docKey);
  112. std::string docKeyString = LevelDbRemoteDocumentKey::Key(docKey);
  113. txn.Put(docKeyString, documentUpdate);
  114. }
  115. txn.Commit();
  116. }
  117. }
  118. /**
  119. * Adjust ranges to control what test cases run. Outermost loop controls whether or
  120. * not indexes are written, the inner loops control size of document writes and number
  121. * of document writes.
  122. */
  123. static void TestCases(benchmark::internal::Benchmark *b) {
  124. for (int writeIndexes = 0; writeIndexes <= 1; writeIndexes++) {
  125. for (int documentSize = 1 << 10; documentSize <= 1 << 20; documentSize *= 4) {
  126. for (int docsToUpdate = 1; docsToUpdate <= 5; docsToUpdate++) {
  127. b->Args({writeIndexes, documentSize, docsToUpdate});
  128. }
  129. }
  130. }
  131. }
  132. BENCHMARK_REGISTER_F(LevelDBFixture, RemoteEvent)
  133. ->Apply(TestCases)
  134. ->Unit(benchmark::kMicrosecond)
  135. ->Repetitions(5);
  136. @interface FSTLevelDBBenchmarkTests : XCTestCase
  137. @end
  138. @implementation FSTLevelDBBenchmarkTests
  139. - (void)testRunBenchmarks {
  140. // Enable to run benchmarks.
  141. char *argv[3] = {const_cast<char *>("Benchmarks"),
  142. const_cast<char *>("--benchmark_out=/tmp/leveldb_benchmark"),
  143. const_cast<char *>("--benchmark_out_format=csv")};
  144. int argc = 3;
  145. benchmark::Initialize(&argc, argv);
  146. benchmark::RunSpecifiedBenchmarks();
  147. }
  148. @end
  149. NS_ASSUME_NONNULL_END