Commit bd2c1914 authored by Colin Ni's avatar Colin Ni Committed by Facebook Github Bot 7

Update FBVector.md

Summary:
Minor changes. Simplified the memory-handling explanation; also fixed some grammar issues and re-worded some confusing paragraphs. (I suggest reading the edited and unedited versions separately.)
Closes https://github.com/facebook/folly/pull/459

Reviewed By: simpkins

Differential Revision: D3779296

Pulled By: Orvid

fbshipit-source-id: 24b086cbd0b67e4c592731aeec6a7ffc14ff0319
parent bd8228d9
...@@ -35,31 +35,29 @@ folly/test/FBVectorTest.cpp for a few benchmarks. ...@@ -35,31 +35,29 @@ folly/test/FBVectorTest.cpp for a few benchmarks.
It is well known that `std::vector` grows exponentially (at a It is well known that `std::vector` grows exponentially (at a
constant factor) in order to avoid quadratic growth performance. constant factor) in order to avoid quadratic growth performance.
The trick is choosing a good factor (any factor greater than 1 The trick is choosing a good factor. Any factor greater than 1
ensures O(1) amortized append complexity towards infinity). A ensures O(1) amortized append complexity towards infinity. But a
factor that's too small causes frequent vector reallocation; one factor that's too small (say, 1.1) causes frequent vector reallocation, and
that's too large forces the vector to consume much more memory one that's too large (say, 3 or 4) forces the vector to consume much more
than needed. The initial HP implementation by Stepanov used a memory than needed.
growth factor of 2, i.e. whenever you'd `push_back` into a vector
without there being room, it would double the current capacity. The initial HP implementation by Stepanov used a
growth factor of 2; i.e., whenever you'd `push_back` into a vector
With time, other compilers reduced the growth factor to 1.5, but without there being room, it would double the current capacity. This
gcc has staunchly used a growth factor of 2. In fact it can be was not a good choice: it can be mathematically proven that a growth factor of
mathematically proven that a growth factor of 2 is rigorously the 2 is rigorously the <i>worst</i> possible because it never allows the vector
<i>worst</i> possible because it never allows the vector to reuse to reuse any of its previously-allocated memory. Despite other compilers
any of its previously-allocated memory. That makes the vector cache- reducing the growth factor to 1.5, gcc has staunchly maintained its factor of
unfriendly and memory manager unfriendly. 2. This makes `std::vector` cache- unfriendly and memory manager unfriendly.
To see why that's the case, consider a large vector of capacity C To see why that's the case, consider a large vector of capacity C.
residing somewhere at the beginning of an initially unoccupied When there's a request to grow the vector, the vector
chunk. When the request for growth comes about, the vector
(assuming no in-place resizing, see the appropriate section in (assuming no in-place resizing, see the appropriate section in
this document) will allocate a chunk next to its current chunk, this document) will allocate a chunk of memory next to its current chunk,
copy its existing data, and then deallocate the old chunk. So now copy its existing data to the new chunk, and then deallocate the old chunk.
we have a chunk of size C followed by a chunk of size k * C. So now we have a chunk of size C followed by a chunk of size k * C. Continuing
Continuing this process we'll then have a chunk of size k * k * C this process we'll then have a chunk of size k * k * C to the right and so on.
to the right and so on. That leads to a series of the form (using That leads to a series of the form (using ^^ for power):
^^ for power):
C, C*k, C*k^^2, C*k^^3, ... C, C*k, C*k^^2, C*k^^3, ...
...@@ -69,26 +67,13 @@ the remarkable equality: ...@@ -69,26 +67,13 @@ the remarkable equality:
1 + 2^^1 + 2^^2 + 2^^3... + 2^^n = 2^^(n+1) - 1 1 + 2^^1 + 2^^2 + 2^^3... + 2^^n = 2^^(n+1) - 1
What that really means is that the new request for a chunk will This means that any new chunk requested will be larger
be never satisfiable by coalescing all previously-used chunks. than all previously used chunks combined, so the vector must
This is not quite what you'd want. crawl forward in memory; it can't move back to its deallocated chunks.
But any number smaller than 2 guarantees that you'll at some point be
We would of course want the vector to not crawl forward in able to reuse the previous chunks. For instance, choosing 1.5 as the factor
memory, but instead to move back to its previously-allocated allows memory reuse after 4 reallocations; 1.45 allows memory reuse after 3
chunks. Any number smaller than 2 guarantees that you'll be able reallocations; and 1.3 allows reuse after only 2 reallocations.
at some point to reuse the previous chunks. Going through the
math reveals the equation:
k^^n <= 1 + k + k^^2 + ... + k^^(n-2)
If some number n satisfies that equation, it means you can reuse
memory after n reallocations. The graphical solver below reveals
that choosing k = 1.5 (blue line) allows memory reuse after 4
reallocations, choosing k = 1.45 (red line) allows memory reuse
after 3 reallocations, and choosing k = 1.3 (black line) allows
reuse after only 2 reallocations.
![graphical solutions](./Fbvector--graphical_solutions.png)
Of course, the above makes a number of simplifying assumptions Of course, the above makes a number of simplifying assumptions
about how the memory allocator works, but definitely you don't about how the memory allocator works, but definitely you don't
...@@ -240,4 +225,3 @@ directions may be in improving raw memory copying (`memcpy` is ...@@ -240,4 +225,3 @@ directions may be in improving raw memory copying (`memcpy` is
not an intrinsic in gcc and does not work terribly well for not an intrinsic in gcc and does not work terribly well for
large chunks) and in furthering the collaboration with large chunks) and in furthering the collaboration with
jemalloc. Have fun! jemalloc. Have fun!
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