remote_document_cache_benchmark.mm 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright 2020 Google LLC
  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 <FirebaseCore/FIRApp.h>
  17. #import <FirebaseFirestore/FirebaseFirestore.h>
  18. #include "Firestore/core/src/util/autoid.h"
  19. #include "Firestore/core/src/util/hard_assert.h"
  20. #include "Firestore/core/src/util/string_apple.h"
  21. #include "Firestore/core/test/unit/testutil/app_testing.h"
  22. #include "benchmark/benchmark.h"
  23. namespace {
  24. using firebase::firestore::testutil::AppForUnitTesting;
  25. using firebase::firestore::util::CreateAutoId;
  26. using firebase::firestore::util::MakeNSString;
  27. using firebase::firestore::util::MakeString;
  28. FIRFirestore* OpenFirestore() {
  29. FIRApp* app = AppForUnitTesting();
  30. auto db = [FIRFirestore firestoreForApp:app];
  31. auto settings = db.settings;
  32. // Default to running against the emulator because we're evaluating local execution speed.
  33. settings.host = @"localhost:8080";
  34. settings.sslEnabled = NO;
  35. // The default is the main queue and this deadlocks because the benchmark does not start an event
  36. // loop and just runs on the main thread.
  37. settings.dispatchQueue = dispatch_queue_create("results", DISPATCH_QUEUE_SERIAL);
  38. db.settings = settings;
  39. return db;
  40. }
  41. NSMutableDictionary<NSString*, id>* MakeDocumentData() {
  42. NSMutableDictionary<NSString*, id>* doc = [[NSMutableDictionary alloc] init];
  43. NSString* value = MakeNSString(std::string('a', 100));
  44. // Create keys "a", "b", "c", ..., "j", each associated with the 100 byte
  45. // value. This makes the total document size ~1 kb.
  46. std::string key_bytes("a");
  47. for (int i = 0; i < 10; i++) {
  48. key_bytes[0] = static_cast<char>('a' + i);
  49. doc[MakeNSString(key_bytes)] = value;
  50. }
  51. return doc;
  52. }
  53. FIRQuerySnapshot* GetDocumentsFromCache(FIRQuery* query) {
  54. __block FIRQuerySnapshot* result;
  55. dispatch_semaphore_t done = dispatch_semaphore_create(0);
  56. [query getDocumentsWithSource:FIRFirestoreSourceCache
  57. completion:^(FIRQuerySnapshot* snap, NSError* error) {
  58. HARD_ASSERT(error == nil, "Failed: %s", MakeString([error description]));
  59. result = snap;
  60. dispatch_semaphore_signal(done);
  61. }];
  62. dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
  63. return result;
  64. }
  65. FIRQuerySnapshot* GetDocumentsFromServer(FIRQuery* query) {
  66. __block FIRQuerySnapshot* result;
  67. dispatch_semaphore_t done = dispatch_semaphore_create(0);
  68. [query getDocumentsWithSource:FIRFirestoreSourceServer
  69. completion:^(FIRQuerySnapshot* snap, NSError* error) {
  70. HARD_ASSERT(error == nil, "Failed: %s", MakeString([error description]));
  71. result = snap;
  72. dispatch_semaphore_signal(done);
  73. }];
  74. dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
  75. return result;
  76. }
  77. void WaitForPendingWrites(FIRFirestore* db) {
  78. dispatch_semaphore_t done = dispatch_semaphore_create(0);
  79. [db waitForPendingWritesWithCompletion:^(NSError*) {
  80. dispatch_semaphore_signal(done);
  81. }];
  82. dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
  83. }
  84. void WriteDocs(FIRCollectionReference* collection, int64_t count, bool match) {
  85. auto doc = MakeDocumentData();
  86. for (int64_t i = 0; i < count; i++) {
  87. doc[@"match"] = @(match);
  88. FIRDocumentReference* ref = [collection documentWithAutoID];
  89. [ref setData:doc];
  90. }
  91. WaitForPendingWrites(collection.firestore);
  92. }
  93. void Shutdown(FIRFirestore* db) {
  94. dispatch_semaphore_t done = dispatch_semaphore_create(0);
  95. [db terminateWithCompletion:^(NSError*) {
  96. dispatch_semaphore_signal(done);
  97. }];
  98. dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
  99. }
  100. void BM_QueryIndexFree(benchmark::State& state) {
  101. int64_t matching_docs = state.range(0);
  102. int64_t total_docs = state.range(1);
  103. FIRFirestore* db = OpenFirestore();
  104. auto collection = [db collectionWithPath:MakeNSString("docs-" + CreateAutoId())];
  105. WriteDocs(collection, matching_docs, /*match=*/true);
  106. WriteDocs(collection, total_docs - matching_docs, /*match=*/false);
  107. FIRQuery* query = [collection queryWhereField:@"match" isEqualTo:@YES];
  108. // Query the server to force the target tables to be updated.
  109. GetDocumentsFromServer(query);
  110. for (auto _ : state) {
  111. auto docs = GetDocumentsFromCache(query);
  112. (void)docs;
  113. }
  114. Shutdown(db);
  115. }
  116. BENCHMARK(BM_QueryIndexFree)
  117. ->Unit(benchmark::kMicrosecond)
  118. ->Args({0, 1})
  119. ->Args({1, 1})
  120. ->Args({1, 10})
  121. ->Args({10, 10})
  122. ->Args({1, 100})
  123. ->Args({100, 100})
  124. ->Args({1, 1000})
  125. ->Args({10, 1000})
  126. ->Args({100, 1000})
  127. ->Args({1000, 1000});
  128. void BM_QueryMatching(benchmark::State& state) {
  129. int64_t matching_docs = state.range(0);
  130. int64_t total_docs = state.range(1);
  131. FIRFirestore* db = OpenFirestore();
  132. auto collection = [db collectionWithPath:MakeNSString("docs-" + CreateAutoId())];
  133. WriteDocs(collection, matching_docs, /*match=*/true);
  134. WriteDocs(collection, total_docs - matching_docs, /*match=*/false);
  135. for (auto _ : state) {
  136. auto docs = GetDocumentsFromCache([collection queryWhereField:@"match" isEqualTo:@YES]);
  137. (void)docs;
  138. }
  139. Shutdown(db);
  140. }
  141. BENCHMARK(BM_QueryMatching)
  142. ->Unit(benchmark::kMicrosecond)
  143. ->Args({0, 1})
  144. ->Args({1, 1})
  145. ->Args({1, 10})
  146. ->Args({10, 10})
  147. ->Args({1, 100})
  148. ->Args({100, 100})
  149. ->Args({1, 1000})
  150. ->Args({10, 1000})
  151. ->Args({100, 1000})
  152. ->Args({1000, 1000});
  153. void BM_QueryAll(benchmark::State& state) {
  154. int64_t total_docs = state.range(0);
  155. FIRFirestore* db = OpenFirestore();
  156. auto collection = [db collectionWithPath:MakeNSString("docs-" + CreateAutoId())];
  157. WriteDocs(collection, total_docs, /*match=*/true);
  158. for (auto _ : state) {
  159. auto docs = GetDocumentsFromCache(collection);
  160. (void)docs;
  161. }
  162. Shutdown(db);
  163. }
  164. BENCHMARK(BM_QueryAll)->Unit(benchmark::kMicrosecond)->Arg(1)->Arg(10)->Arg(100)->Arg(1000);
  165. } // namespace