pinned_vector
A Contiguous Container without Pointer Invalidation
pinned_vector A Contiguous Container without Pointer Invalidation - - PowerPoint PPT Presentation
pinned_vector A Contiguous Container without Pointer Invalidation Meeting C++ 2018 std::vector contiguous layout cache locality fastest iteration O(1) lookup random access amortized O(1) growth 2 std::vector contiguous layout cache
A Contiguous Container without Pointer Invalidation
2
contiguous layout cache locality fastest iteration O(1) lookup random access amortized O(1) growth
3
contiguous layout cache locality fastest iteration O(1) lookup random access amortized O(1) growth
capacity=6
4
capacity=6
5
capacity=12 capacity=6
6
capacity=12 capacity=6
7
capacity=12 capacity=6
8
9
may invalidate all always invalidates all may invalidate other push_back clear insert emplace_back assign erase insert emplace reserve resize shrink_to_fit
10
11
erase( )
12
erase( )
13
erase( )
14
insert( )
15
insert( )
16
insert( )
17 https://en.cppreference.com/w/cpp/container
18
boost::stable_vector<T>
vector<unique_ptr<T>>
T* T* T* T* T* T* T* T* T* T* T* T*
19
plf::colony
20
plf::colony
memory chunks
std::deque
iteration
“A Contiguous Container without Pointer Invalidation”
21
“A Contiguous Container without Pointer Invalidation”
22
not quite… must maintain contiguous layout invariant
“A Contiguous Container with Essential Pointer Invalidation”
23
The minimum amount of pointer invalidation absolutely necessary to maintain the contiguous layout invariant. If insertion or erasure occurs only at the end of the container then pointers to all other elements shall remain valid. Idealized std::vector with infinite capacity.
24
may invalidate all always invalidates all may invalidate other push_back clear insert emplace_back assign erase insert emplace reserve resize shrink_to_fit
25
may invalidate all always invalidates all may invalidate other push_back clear insert emplace_back assign erase insert emplace reserve resize shrink_to_fit
(“Virtual Address eXtension”, 1977)
MMU Intel 80286 (1982)
26
○ Physical Memory ○ Filesystem ○ Memory mapped I/O ○ Inter-Process Communication
27
28
#include <memory> #include <iostream> int main() { auto foo = std::make_unique( 42) std::cout << foo.get() << std::endl; return 0; }
29
Virtual Memory Main Memory Filesystem GPU Memory Other Process
○ Separate address space
○ x86-64 eg. 128TiB
30
○ Memory aligned in page size
○ x86-64 has also 2 MiB and 1 GiB pages ○ Performance
31
○ terminated by signal SIGSEGV (Address boundary error) ○ Access Violation
memory addresses
○ Check Read, Write, Executable Bit
32
33
○ Hardware or Software
34
35
36
37
Virtual Memory Physical Memory Swap file
38
Virtual Memory Physical Memory Swap file
39
Virtual Memory Physical Memory Swap file
40
Virtual Memory Physical Memory Swap file
41
Virtual Memory Physical Memory Swap file
42
43
MMU Memory Page table TLB Translate virtual address ✅ Return physical address
44
○ Filesystem Access
area
45
Reserve Commit
Virtual Memory Address Space
fff...
46
auto v = pinned_vector<int>(max_elements(1’000’000’000));
VirtualAlloc(..., MEM_RESERVE); mmap(..., PROT_NONE, MAP_ANON | MAP_PRIVATE);
v.max_size();
max_pages max_bytes
Virtual Memory Address Space
fff...
47
auto v = pinned_vector<int>(max_elements(1’000’000’000)); v.push_back(279); v.push_back(188); ...
VirtualAlloc(..., MEM_COMMIT); mprotect(..., PROT_READ | PROT_WRITE);
Virtual Memory Address Space
fff...
48
auto v = pinned_vector<int>(max_elements(1’000’000’000)); v.pop_back(); ...
VirtualFree(..., MEM_DECOMMIT); mprotect(..., PROT_NONE); madvise(..., MADV_DONTNEED);
v.shrink_to_fit();
49
std::vector pinned_vector
auto v = Container<T>(); v.reserve(n); ⏱ fill_n(back_inserter(v), n, x); ⏱
Round 1: establish a common baseline
50
51
struct bigval { double data[10]; };
52
53
54
std::vector pinned_vector
auto v = Container<T>(); v.reserve(n); ⏱ fill_n(back_inserter(v), n, x); ⏱
Round 2: size not known upfront
55
56
struct bigval { double data[10]; };
57
58
59
std::vector pinned_vector Round 3: so how much faster is it?
60
Windows 10 build 17134 (x64) Intel Core i7-7700HQ @ 2.80 GHz Clang-7.0.0 (VS 15.8.4 stdlib)
61
MacOS 10.14.1 (x64) Intel Core i7-7820HQ @ 2.90 GHz Apple LLVM 10.0.0 (clang-1000.11.45.5)
62
Windows 10 build 17134 (x64) Intel Core i7-7820HQ @ 2.90 GHz Clang-7.0.0 (VS 15.8.4 stdlib)
63
std::vector pinned_vector Round 4: where does a vector’s time go?
auto v = vector<T, bump_alloc>(); ⏱ fill_n(back_inserter(v), n, x); ⏱ ≡ total time - allocations ≡ insertion + copying ≡ baseline + copying Times for: insertion + allocation + copying
64
65
66
67
push_back with preceding reserve() roughly equivalent slower than std::vector for small sizes faster than std::vector after a breaking point achieved by not copying values around exact numbers vary significantly by system and value_type
○ Linux ○ macOS ○ Windows
○ Android ○ iOS (reserve limited by physical memory)
68
○ Data oriented design in C++ by Mike Acton ○ Data-oriented design in practice by Stoyan Nikolov
69
70
Storage (std::vector) Handle: Raw Pointer to Component
71
Storage (std::vector) Handle: Raw Pointer to Component New Storage (std::vector)
72
Handle:
Entity System Logic Storage Index std::vector Data Component
73
Pro:
○ grow/shrink dynamically during runtime Con:
○ e.g. index ○ Indirection
74
Pro:
Con:
=> waste of memory
75
Component Handle:
Entity System Logic Storage of Components Data Component pinned_vector
76
77
Implementation will be released at https://github.com/mknejp/vmcontainer Once all the finishing touches are done.
Jakob Schweisshelm @jakouf Miro Knejp @mknejp