Commit 7e2b9654 authored by Nathan Bronson's avatar Nathan Bronson Committed by Facebook Github Bot

fix over-reliance on compiler optimizer in reserveForInsertImpl

Summary:
rehash's max_size check was previously relying on the optimizer
to inline and then remove a loop whose value could be determined at
compile time.  It failed to do this even in some trivial cases, wasting
about 10 nanoseconds per rehash.  This code moves the max_size check lower
(more than 6 entries) and removes the loop entirely.

Reviewed By: ot

Differential Revision: D8499582

fbshipit-source-id: 8f5c288d3922b094da81ee9261254c729e8cb1b9
parent 0ce40de7
......@@ -1657,15 +1657,6 @@ class F14Table : public Policy {
capacity = size();
}
auto unroundedLimit = max_size();
std::size_t exactLimit = Chunk::kDesiredCapacity;
while (exactLimit <= unroundedLimit / 2) {
exactLimit *= 2;
}
if (UNLIKELY(capacity > exactLimit)) {
throw_exception<std::bad_alloc>();
}
std::size_t const kInitialCapacity = 2;
std::size_t const kHalfChunkCapacity =
(Chunk::kDesiredCapacity / 2) & ~std::size_t{1};
......@@ -1678,11 +1669,18 @@ class F14Table : public Policy {
chunkCount = 1;
maxSizeWithoutRehash = kHalfChunkCapacity;
} else {
chunkCount = 1;
while (chunkCount * Chunk::kDesiredCapacity < capacity) {
chunkCount *= 2;
}
chunkCount = folly::nextPowTwo(
(capacity + Chunk::kDesiredCapacity - 1) / Chunk::kDesiredCapacity);
maxSizeWithoutRehash = chunkCount * Chunk::kDesiredCapacity;
constexpr std::size_t kMaxChunksWithoutCapacityOverflow =
(std::numeric_limits<std::size_t>::max)() / Chunk::kDesiredCapacity;
if (UNLIKELY(
chunkCount > kMaxChunksWithoutCapacityOverflow ||
maxSizeWithoutRehash > max_size())) {
throw_exception<std::bad_alloc>();
}
}
if (bucket_count() != maxSizeWithoutRehash) {
rehashImpl(chunkCount, maxSizeWithoutRehash);
......
......@@ -16,6 +16,7 @@
#include <folly/container/F14Map.h>
#include <algorithm>
#include <unordered_map>
#include <folly/Conv.h>
......@@ -62,8 +63,11 @@ void runAllocatedMemorySizeTest() {
TMap<K, V, DefaultHasher<K>, DefaultKeyEqual<K>, A> m;
EXPECT_EQ(testAllocatedMemorySize, m.getAllocatedMemorySize());
std::size_t maxSize = 0;
for (size_t i = 0; i < 1000; ++i) {
m.insert(std::make_pair(folly::to<K>(i), V{}));
maxSize = std::max(m.size(), maxSize);
EXPECT_GT(maxSize, (m.bucket_count() / 2) & ~std::size_t{1});
m.erase(folly::to<K>(i / 10 + 2));
EXPECT_EQ(testAllocatedMemorySize, m.getAllocatedMemorySize());
std::size_t size = 0;
......
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