mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
* Add Index-free benchmarks * Add BackgroundQueue Port of firebase/firebase-android-sdk#559 * Decode documents in background threads to improve performance Run on (12 X 2900 MHz CPU s) CPU Caches: L1 Data 32K (x6) L1 Instruction 32K (x6) L2 Unified 262K (x6) L3 Unified 12582K (x1) Load Average: 2.24, 2.18, 1.96 ---------------------------------------------------------------------------------- Benchmark Time CPU Iterations Improvement ---------------------------------------------------------------------------------- BM_QueryMatching/0/1 132 us 12.7 us 53524 21.4% BM_QueryMatching/1/1 150 us 18.1 us 37305 16.2% BM_QueryMatching/1/10 371 us 27.6 us 10000 48.5% BM_QueryMatching/10/10 429 us 64.3 us 11349 41.0% BM_QueryMatching/1/100 2573 us 29.0 us 1000 51.7% (max) BM_QueryMatching/100/100 3123 us 416 us 1000 45.5% BM_QueryMatching/1/1000 26785 us 33.5 us 100 50.5% BM_QueryMatching/10/1000 28389 us 74.5 us 100 48.0% BM_QueryMatching/100/1000 27883 us 470 us 100 49.4% BM_QueryMatching/1000/1000 32189 us 34.3 us 100 44.8% BM_QueryAll/1 151 us 15.2 us 45385 -49.5% (min) BM_QueryAll/10 444 us 60.7 us 12829 32.5% BM_QueryAll/100 3175 us 414 us 1000 45.1% BM_QueryAll/1000 30222 us 18.8 us 100 49.7% Mean 35.3% * Insert into a vector to reduce contention Run on (12 X 2900 MHz CPU s) CPU Caches: L1 Data 32K (x6) L1 Instruction 32K (x6) L2 Unified 262K (x6) L3 Unified 12582K (x1) Load Average: 1.43, 2.10, 1.98 ---------------------------------------------------------------------------------- Benchmark Time CPU Iterations Improvement ---------------------------------------------------------------------------------- BM_QueryMatching/0/1 127 us 12.2 us 56131 3.8% BM_QueryMatching/1/1 142 us 16.6 us 39200 5.3% BM_QueryMatching/1/10 369 us 26.6 us 10000 0.5% BM_QueryMatching/10/10 425 us 59.2 us 12724 0.9% BM_QueryMatching/1/100 2194 us 28.9 us 10000 14.7% BM_QueryMatching/100/100 2765 us 405 us 1000 11.5% BM_QueryMatching/1/1000 21095 us 32.8 us 1000 21.2% BM_QueryMatching/10/1000 20797 us 66.4 us 1000 26.7% (max) BM_QueryMatching/100/1000 21915 us 408 us 1000 21.4% BM_QueryMatching/1000/1000 23700 us 30.9 us 1000 26.4% BM_QueryAll/1 136 us 14.3 us 44799 9.9% BM_QueryAll/10 443 us 57.3 us 10000 0.2% (min) BM_QueryAll/100 2607 us 389 us 1000 17.9% BM_QueryAll/1000 23512 us 19.4 us 1000 22.2% Mean 13.1%
197 lines
6.4 KiB
Plaintext
197 lines
6.4 KiB
Plaintext
/*
|
|
* Copyright 2020 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#import <FirebaseCore/FIRApp.h>
|
|
#import <FirebaseFirestore/FirebaseFirestore.h>
|
|
|
|
#include "Firestore/core/src/firebase/firestore/util/autoid.h"
|
|
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
|
|
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
|
|
#include "Firestore/core/test/firebase/firestore/testutil/app_testing.h"
|
|
#include "benchmark/benchmark.h"
|
|
|
|
namespace {
|
|
|
|
using firebase::firestore::testutil::AppForUnitTesting;
|
|
using firebase::firestore::util::CreateAutoId;
|
|
using firebase::firestore::util::MakeNSString;
|
|
using firebase::firestore::util::MakeString;
|
|
|
|
FIRFirestore* OpenFirestore() {
|
|
FIRApp* app = AppForUnitTesting();
|
|
auto db = [FIRFirestore firestoreForApp:app];
|
|
auto settings = db.settings;
|
|
|
|
// Default to running against the emulator because we're evaluating local execution speed.
|
|
settings.host = @"localhost:8080";
|
|
settings.sslEnabled = NO;
|
|
|
|
// The default is the main queue and this deadlocks because the benchmark does not start an event
|
|
// loop and just runs on the main thread.
|
|
settings.dispatchQueue = dispatch_queue_create("results", DISPATCH_QUEUE_SERIAL);
|
|
db.settings = settings;
|
|
|
|
return db;
|
|
}
|
|
|
|
NSMutableDictionary<NSString*, id>* MakeDocumentData() {
|
|
NSMutableDictionary<NSString*, id>* doc = [[NSMutableDictionary alloc] init];
|
|
NSString* value = MakeNSString(std::string('a', 100));
|
|
|
|
// Create keys "a", "b", "c", ..., "j", each associated with the 100 byte
|
|
// value. This makes the total document size ~1 kb.
|
|
std::string key_bytes("a");
|
|
for (int i = 0; i < 10; i++) {
|
|
key_bytes[0] = static_cast<char>('a' + i);
|
|
doc[MakeNSString(key_bytes)] = value;
|
|
}
|
|
return doc;
|
|
}
|
|
|
|
FIRQuerySnapshot* GetDocumentsFromCache(FIRQuery* query) {
|
|
__block FIRQuerySnapshot* result;
|
|
dispatch_semaphore_t done = dispatch_semaphore_create(0);
|
|
[query getDocumentsWithSource:FIRFirestoreSourceCache
|
|
completion:^(FIRQuerySnapshot* snap, NSError* error) {
|
|
HARD_ASSERT(error == nil, "Failed: %s", MakeString([error description]));
|
|
result = snap;
|
|
dispatch_semaphore_signal(done);
|
|
}];
|
|
dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
|
|
return result;
|
|
}
|
|
|
|
FIRQuerySnapshot* GetDocumentsFromServer(FIRQuery* query) {
|
|
__block FIRQuerySnapshot* result;
|
|
dispatch_semaphore_t done = dispatch_semaphore_create(0);
|
|
[query getDocumentsWithSource:FIRFirestoreSourceServer
|
|
completion:^(FIRQuerySnapshot* snap, NSError* error) {
|
|
HARD_ASSERT(error == nil, "Failed: %s", MakeString([error description]));
|
|
result = snap;
|
|
dispatch_semaphore_signal(done);
|
|
}];
|
|
dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
|
|
return result;
|
|
}
|
|
|
|
void WaitForPendingWrites(FIRFirestore* db) {
|
|
dispatch_semaphore_t done = dispatch_semaphore_create(0);
|
|
[db waitForPendingWritesWithCompletion:^(NSError* error) {
|
|
dispatch_semaphore_signal(done);
|
|
}];
|
|
dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
|
|
}
|
|
|
|
void WriteDocs(FIRCollectionReference* collection, int64_t count, bool match) {
|
|
auto doc = MakeDocumentData();
|
|
for (int64_t i = 0; i < count; i++) {
|
|
doc[@"match"] = @(match);
|
|
FIRDocumentReference* ref = [collection documentWithAutoID];
|
|
[ref setData:doc];
|
|
}
|
|
WaitForPendingWrites(collection.firestore);
|
|
}
|
|
|
|
void Shutdown(FIRFirestore* db) {
|
|
dispatch_semaphore_t done = dispatch_semaphore_create(0);
|
|
[db terminateWithCompletion:^(NSError* error) {
|
|
dispatch_semaphore_signal(done);
|
|
}];
|
|
dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
|
|
}
|
|
|
|
void BM_QueryIndexFree(benchmark::State& state) {
|
|
int64_t matching_docs = state.range(0);
|
|
int64_t total_docs = state.range(1);
|
|
|
|
FIRFirestore* db = OpenFirestore();
|
|
auto collection = [db collectionWithPath:MakeNSString("docs-" + CreateAutoId())];
|
|
WriteDocs(collection, matching_docs, /*match=*/true);
|
|
WriteDocs(collection, total_docs - matching_docs, /*match=*/false);
|
|
|
|
FIRQuery* query = [collection queryWhereField:@"match" isEqualTo:@YES];
|
|
|
|
// Query the server to force the target tables to be updated.
|
|
GetDocumentsFromServer(query);
|
|
|
|
for (auto _ : state) {
|
|
auto docs = GetDocumentsFromCache(query);
|
|
(void)docs;
|
|
}
|
|
|
|
Shutdown(db);
|
|
}
|
|
BENCHMARK(BM_QueryIndexFree)
|
|
->Unit(benchmark::kMicrosecond)
|
|
->Args({0, 1})
|
|
->Args({1, 1})
|
|
->Args({1, 10})
|
|
->Args({10, 10})
|
|
->Args({1, 100})
|
|
->Args({100, 100})
|
|
->Args({1, 1000})
|
|
->Args({10, 1000})
|
|
->Args({100, 1000})
|
|
->Args({1000, 1000});
|
|
|
|
void BM_QueryMatching(benchmark::State& state) {
|
|
int64_t matching_docs = state.range(0);
|
|
int64_t total_docs = state.range(1);
|
|
|
|
FIRFirestore* db = OpenFirestore();
|
|
auto collection = [db collectionWithPath:MakeNSString("docs-" + CreateAutoId())];
|
|
WriteDocs(collection, matching_docs, /*match=*/true);
|
|
WriteDocs(collection, total_docs - matching_docs, /*match=*/false);
|
|
|
|
for (auto _ : state) {
|
|
auto docs = GetDocumentsFromCache([collection queryWhereField:@"match" isEqualTo:@YES]);
|
|
(void)docs;
|
|
}
|
|
|
|
Shutdown(db);
|
|
}
|
|
BENCHMARK(BM_QueryMatching)
|
|
->Unit(benchmark::kMicrosecond)
|
|
->Args({0, 1})
|
|
->Args({1, 1})
|
|
->Args({1, 10})
|
|
->Args({10, 10})
|
|
->Args({1, 100})
|
|
->Args({100, 100})
|
|
->Args({1, 1000})
|
|
->Args({10, 1000})
|
|
->Args({100, 1000})
|
|
->Args({1000, 1000});
|
|
|
|
void BM_QueryAll(benchmark::State& state) {
|
|
int64_t total_docs = state.range(0);
|
|
|
|
FIRFirestore* db = OpenFirestore();
|
|
auto collection = [db collectionWithPath:MakeNSString("docs-" + CreateAutoId())];
|
|
WriteDocs(collection, total_docs, /*match=*/true);
|
|
|
|
for (auto _ : state) {
|
|
auto docs = GetDocumentsFromCache(collection);
|
|
(void)docs;
|
|
}
|
|
|
|
Shutdown(db);
|
|
}
|
|
|
|
BENCHMARK(BM_QueryAll)->Unit(benchmark::kMicrosecond)->Arg(1)->Arg(10)->Arg(100)->Arg(1000);
|
|
|
|
} // namespace
|