Commit d4032b17 authored by Charles Harrison's avatar Charles Harrison Committed by Commit Bot

[safe-browsing] Make the perftest less allocate-y

This CL makes the V4 Store perftest a bit faster by:
1. Using a smaller # of hashes in debug builds
2. Using one big string instead of a vector of full hashes, to avoid
   allocating and de-allocating many small strings. To get this working,
   needed to slightly modify V4Store to allow querying by StringPiece.

(2) improved local performance on my release build by 25-30%

Bug: 822624
Change-Id: I646af2b0ccfb6447ccbb94ce68b661bd235587d1
Reviewed-on: https://chromium-review.googlesource.com/965931
Commit-Queue: Charlie Harrison <csharrison@chromium.org>
Reviewed-by: default avatarVarun Khaneja <vakh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543796}
parent def2da31
...@@ -777,6 +777,10 @@ StoreWriteResult V4Store::WriteToDisk(const Checksum& checksum) { ...@@ -777,6 +777,10 @@ StoreWriteResult V4Store::WriteToDisk(const Checksum& checksum) {
} }
HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) { HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) {
return GetMatchingHashPrefix(base::StringPiece(full_hash));
}
HashPrefix V4Store::GetMatchingHashPrefix(base::StringPiece full_hash) {
// It should never be the case that more than one hash prefixes match a given // It should never be the case that more than one hash prefixes match a given
// full hash. However, if that happens, this method returns any one of them. // full hash. However, if that happens, this method returns any one of them.
// It does not guarantee which one of those will be returned. // It does not guarantee which one of those will be returned.
...@@ -784,8 +788,7 @@ HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) { ...@@ -784,8 +788,7 @@ HashPrefix V4Store::GetMatchingHashPrefix(const FullHash& full_hash) {
checks_attempted_++; checks_attempted_++;
for (const auto& pair : hash_prefix_map_) { for (const auto& pair : hash_prefix_map_) {
const PrefixSize& prefix_size = pair.first; const PrefixSize& prefix_size = pair.first;
base::StringPiece hash_prefix = base::StringPiece hash_prefix = full_hash.substr(0, prefix_size);
base::StringPiece(full_hash).substr(0, prefix_size);
if (HashPrefixMatches(hash_prefix, pair.second, prefix_size)) if (HashPrefixMatches(hash_prefix, pair.second, prefix_size))
return hash_prefix.as_string(); return hash_prefix.as_string();
} }
......
...@@ -293,6 +293,8 @@ class V4Store { ...@@ -293,6 +293,8 @@ class V4Store {
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestChecksumErrorOnStartup); FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestChecksumErrorOnStartup);
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, WriteToDiskFails); FRIEND_TEST_ALL_PREFIXES(V4StoreTest, WriteToDiskFails);
FRIEND_TEST_ALL_PREFIXES(V4StoreTest, FullUpdateFailsChecksumSynchronously); FRIEND_TEST_ALL_PREFIXES(V4StoreTest, FullUpdateFailsChecksumSynchronously);
FRIEND_TEST_ALL_PREFIXES(V4StorePerftest, StressTest);
friend class V4StoreTest; friend class V4StoreTest;
// If |prefix_size| is within expected range, and |raw_hashes_length| is a // If |prefix_size| is within expected range, and |raw_hashes_length| is a
...@@ -338,6 +340,10 @@ class V4Store { ...@@ -338,6 +340,10 @@ class V4Store {
static void ReserveSpaceInPrefixMap(const HashPrefixMap& other_prefixes_map, static void ReserveSpaceInPrefixMap(const HashPrefixMap& other_prefixes_map,
HashPrefixMap* prefix_map_to_update); HashPrefixMap* prefix_map_to_update);
// Same as the public GetMatchingHashPrefix method, but takes a StringPiece,
// for performance reasons.
HashPrefix GetMatchingHashPrefix(base::StringPiece full_hash);
// Merges the prefix map from the old store (|old_hash_prefix_map|) and the // Merges the prefix map from the old store (|old_hash_prefix_map|) and the
// update (additions_map) to populate the prefix map for the current store. // update (additions_map) to populate the prefix map for the current store.
// The indices in the |raw_removals| list, which may be NULL, are not merged. // The indices in the |raw_removals| list, which may be NULL, are not merged.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/numerics/checked_math.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/test/test_simple_task_runner.h" #include "base/test/test_simple_task_runner.h"
#include "base/timer/elapsed_timer.h" #include "base/timer/elapsed_timer.h"
...@@ -23,14 +24,28 @@ namespace safe_browsing { ...@@ -23,14 +24,28 @@ namespace safe_browsing {
class V4StorePerftest : public testing::Test {}; class V4StorePerftest : public testing::Test {};
TEST_F(V4StorePerftest, StressTest) { TEST_F(V4StorePerftest, StressTest) {
const int kNumPrefixes = 2000000; // Debug builds can be quite slow. Use a smaller number of prefixes to test.
#if defined(NDEBUG)
const size_t kNumPrefixes = 2000000;
#else
const size_t kNumPrefixes = 20000;
#endif
static_assert(kMaxHashPrefixLength == crypto::kSHA256Length,
"SHA256 produces a valid FullHash");
CHECK(base::IsValidForType<size_t>(
base::CheckMul(kNumPrefixes, kMaxHashPrefixLength)));
// Keep the full hashes as one big string to avoid tons of allocations /
// deallocations in the test.
std::string full_hashes(kNumPrefixes * kMaxHashPrefixLength, 0);
base::StringPiece full_hashes_piece = base::StringPiece(full_hashes);
std::vector<std::string> prefixes; std::vector<std::string> prefixes;
std::vector<std::string> full_hashes;
for (size_t i = 0; i < kNumPrefixes; i++) { for (size_t i = 0; i < kNumPrefixes; i++) {
std::string sha256 = crypto::SHA256HashString(base::StringPrintf("%zu", i)); size_t index = i * kMaxHashPrefixLength;
DCHECK_EQ(crypto::kSHA256Length, kMaxHashPrefixLength); crypto::SHA256HashString(base::StringPrintf("%zu", i), &full_hashes[index],
full_hashes.push_back(sha256); kMaxHashPrefixLength);
prefixes.push_back(sha256.substr(0, kMinHashPrefixLength)); prefixes.push_back(full_hashes.substr(index, kMinHashPrefixLength));
} }
auto store = std::make_unique<TestV4Store>( auto store = std::make_unique<TestV4Store>(
...@@ -39,13 +54,16 @@ TEST_F(V4StorePerftest, StressTest) { ...@@ -39,13 +54,16 @@ TEST_F(V4StorePerftest, StressTest) {
size_t matches = 0; size_t matches = 0;
base::ElapsedTimer timer; base::ElapsedTimer timer;
for (const auto& full_hash : full_hashes) { for (size_t i = 0; i < kNumPrefixes; i++) {
size_t index = i * kMaxHashPrefixLength;
base::StringPiece full_hash =
full_hashes_piece.substr(index, kMaxHashPrefixLength);
matches += !store->GetMatchingHashPrefix(full_hash).empty(); matches += !store->GetMatchingHashPrefix(full_hash).empty();
} }
perf_test::PrintResult("GetMachingHashPrefix", "", "", perf_test::PrintResult("GetMatchingHashPrefix", "", "",
timer.Elapsed().InMillisecondsF(), "ms", true); timer.Elapsed().InMillisecondsF(), "ms", true);
EXPECT_EQ(matches, full_hashes.size()); EXPECT_EQ(kNumPrefixes, matches);
} }
} // namespace safe_browsing } // namespace safe_browsing
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment