Skip to content

Update and bug fixes for alignment #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9c7cfbd
Fixed typo in comment
cschreib Sep 19, 2022
ebe3d14
Added static_assert for ref in make_observable
cschreib Sep 19, 2022
9e4509a
Rename decayed_type to object_type, do not decay
cschreib Sep 19, 2022
2892f93
Account for alignment in make_observable
cschreib Sep 19, 2022
0d142ac
Added static_assert for more unsupported cases
cschreib Sep 19, 2022
79bdce3
Port static asserts to the main pointer classes
cschreib Sep 19, 2022
4983e1a
Fixed typos in documentation
cschreib Sep 19, 2022
100fea0
Added missing "see" references
cschreib Sep 19, 2022
ce43eb9
Fixed UK/US spelling mismatch in error message
cschreib Sep 19, 2022
e992c2c
Added query eoft_always_has_block
cschreib Sep 19, 2022
2d077b7
Fixed inaccurate test name
cschreib Sep 19, 2022
0bdac7c
Fixed leaks if allocation of ctrl block fails
cschreib Sep 19, 2022
8840ce9
Attempt to fix OSX not able to run leak checks
cschreib Sep 19, 2022
b4d1be3
Handle EOFT cases with no pre-allocated block
cschreib Sep 19, 2022
b88e8ed
Attempt to fix Windows Debug CI
cschreib Sep 19, 2022
4936ff1
Added test for reusing block when not guaranteed
cschreib Sep 19, 2022
388a3b9
Simplify force_allocation_failure
cschreib Sep 19, 2022
2b4c984
Fixed spurious leaks detected on MSVC
cschreib Sep 19, 2022
a3f5f7d
Account for alignment reqs of the control block
cschreib Sep 19, 2022
f17debe
Fixed platform definitions in CMake
cschreib Sep 19, 2022
2e94195
Combine memory tracker into separate header file
cschreib Sep 19, 2022
a88f0b2
Updated heap/sack size comparison
cschreib Sep 19, 2022
35378d6
Updated speed benchmark to output markdown
cschreib Sep 19, 2022
d2938c9
Updated benchmark for linux
cschreib Sep 19, 2022
66691bd
Fixed warning about using member in catch block
cschreib Sep 19, 2022
b480de1
Added missing include
cschreib Sep 19, 2022
be350c9
Fixed defines usage for windows
cschreib Sep 19, 2022
a3ea7a8
Fixed incorrect target modified by function
cschreib Sep 19, 2022
b21d054
Fix test compilation for Emscripten
cschreib Sep 19, 2022
2f0b9df
Fix test compilation for Emscripten
cschreib Sep 19, 2022
45964a4
Do not use aligned new
cschreib Sep 19, 2022
bd82372
Add a catch for std::exception to display message
cschreib Sep 19, 2022
7a16d59
Update benchmarks
cschreib Sep 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 40 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Finally, because this library uses no global state (beyond the standard allocato

## Comparison spreadsheet

In this comparison spreadsheet, the raw pointer `T*` is assumed to never be owning, and used only to observe an existing object (which may or may not have been deleted). The stack and heap sizes were measured with gcc 9.3.0 and libstdc++.
In this comparison spreadsheet, the raw pointer `T*` is assumed to never be owning, and used only to observe an existing object (which may or may not have been deleted). Unless otherwise specified, the stack and heap sizes were measured with gcc 9.4.0 and libstdc++-9.

Labels:
- raw: `T*`
Expand All @@ -146,7 +146,7 @@ Labels:
| Number of heap alloc. | 0 | 0 | 0 | 1 | 1/2(4) | 2 | 1 |
| Size in bytes (64 bit) | | | | | | | |
| - Stack (per instance) | 8 | 16 | 16 | 8 | 16 | 16 | 16 |
| - Heap (shared) | 0 | 0 | 0 | 0 | 24 | 4 | 4 |
| - Heap (shared) | 0 | 0 | 0 | 0 | 24(5) | 4 | 4(6) |
| - Total | 8 | 16 | 16 | 8 | 40 | 20 | 20 |
| Size in bytes (32 bit) | | | | | | | |
| - Stack (per instance) | 4 | 8 | 8 | 4 | 8 | 8 | 8 |
Expand All @@ -159,13 +159,15 @@ Notes:
- (2) Not if using `std::make_shared()`.
- (3) Not defined by the C++ standard. In practice, libstdc++ stores its reference count on an `_Atomic_word`, which for a common 64bit linux platform is a 4 byte signed integer, hence the limit will be 2^31 - 1. Microsoft's STL uses `_Atomic_counter_t`, which for a 64bit Windows platform is 4 bytes unsigned integer, hence the limit will be 2^32 - 1.
- (4) 2 by default, or 1 if using `std::make_shared()`.
- (5) When using `std::make_shared()`, this can get as low as 16 bytes, or larger than 24 bytes, depending on the size and alignment requirements of the object type. This behavior is shared by libstdc++ and MS-STL.
- (6) Can get larger than 4 depending on the alignment requirements of the object type.


## Speed benchmarks

Labels are the same as in the comparison spreadsheet. The speed benchmarks were compiled with all optimizations turned on (except LTO). Speed is measured relative to `std::unique_ptr<T>` used as owner pointer, and `T*` used as observer pointer, which should be the fastest possible implementation (but obviously the one with least safety).

You can run the benchmarks yourself, they are located in `tests/speed_benchmark.cpp`. The benchmark executable runs tests for three object types: `int`, `float`, `std::string`, and `std::array<int,65'536>`, to simulate objects of various allocation cost. The timings below are the worst-case values measured across all object types, which should be most relevant to highlight the overhead from the pointer itself (and erases flukes from the benchmarking framework). In real life scenarios, the actual measured overhead will be substantially lower, as actual business logic is likely to dominate the time budget.
You can run the benchmarks yourself, they are located in `tests/speed_benchmark.cpp`. The benchmark executable runs tests for three object types: `int`, `float`, `std::string`, and `std::array<int,65'536>`, to simulate objects of various allocation cost. The timings below are the median values measured across all object types, which should be most relevant to highlight the overhead from the pointer itself (and erases flukes from the benchmarking framework). In real life scenarios, the actual measured overhead will be substantially lower, as actual business logic is likely to dominate the time budget.

Detail of the benchmarks:
- Create owner empty: default-construct an owner pointer (to nullptr).
Expand All @@ -177,46 +179,46 @@ Detail of the benchmarks:
- Create observer copy: construct a new observer pointer from another observer pointer.
- Dereference observer: get a reference to the underlying object from an observer pointer.

The benchmarks were last ran for v0.4.0.
The benchmarks were last ran for oup v0.7.1.

*Compiler: gcc 9.3.0, std: libstdc++, OS: linux 5.1.0, CPU: Ryzen 5 2600:*
*Compiler: gcc 9.4.0, std: libstdc++-9, OS: linux 5.15.0, CPU: Ryzen 5 2600:*

| Pointer | raw/unique | weak/shared | observer/obs_unique | observer/obs_sealed |
|--------------------------|------------|-------------|---------------------|---------------------|
| Create owner empty | 1 | 1.1 | 1.1 | 1.1 |
| Create owner | 1 | 2.2 | 1.9 | N/A |
| Create owner factory | 1 | 1.3 | 1.8 | 1.3 |
| Dereference owner | 1 | 1 | 1 | 1 |
| Create observer empty | 1 | 1.2 | 1.2 | 1.3 |
| Create observer | 1 | 1.5 | 1.6 | 1.6 |
| Create observer copy | 1 | 1.7 | 1.7 | 1.7 |
| Dereference observer | 1 | 4.8 | 1.2 | 1.3 |
| Pointer | raw/unique | weak/shared | observer/obs_unique | observer/obs_sealed |
| --- | --- | --- | --- | --- |
| Create owner empty | 1 | 1.1 | 1.1 | 1.2 |
| Create owner | 1 | 2.1 | 1.7 | N/A |
| Create owner factory | 1 | 1.3 | 1.7 | 1.1 |
| Dereference owner | 1 | 1.0 | 1.0 | 1.1 |
| Create observer empty | 1 | 1.1 | 1.2 | 1.2 |
| Create observer | 1 | 1.6 | 1.6 | 1.6 |
| Create observer copy | 1 | 1.7 | 1.6 | 1.6 |
| Dereference observer | 1 | 3.5 | 1.0 | 1.0 |

*Compiler: MSVC 16.11.3, std: MS-STL, OS: Windows 10.0.19043, CPU: i7-7800x:*

| Pointer | raw/unique | weak/shared | observer/obs_unique | observer/obs_sealed |
|--------------------------|------------|-------------|---------------------|---------------------|
| Create owner empty | 1 | 1.1 | 1.1 | 1.1 |
| Create owner | 1 | 2.2 | 2.0 | N/A |
| Create owner factory | 1 | 1.3 | 2.0 | 1.4 |
| Dereference owner | 1 | 0.8 | 1.8 | 1.5 |
| Create observer empty | 1 | 1.1 | 1.2 | 1.2 |
| Create observer | 1 | 5.6 | 1.5 | 1.3 |
| Create observer copy | 1 | 6.2 | 1.4 | 1.3 |
| Dereference observer | 1 | 11 | 1.5 | 1.1 |

*Compiler: Emscripten 2.0.16, std: libc++, OS: Node.js 14.15.5 + linux kernel 5.1.0, CPU: Ryzen 5 2600:*

| Pointer | raw/unique | weak/shared | observer/obs_unique | observer/obs_sealed |
|--------------------------|------------|-------------|---------------------|---------------------|
| Create owner empty | 1 | 20 | 1.2 | 1 |
| Create owner | 1 | 1.6 | 1.6 | N/A |
| Create owner factory | 1 | 1.1 | 1.6 | 1 |
| Dereference owner | 1 | 1 | 1 | 1 |
| Create observer empty | 1 | 35 | 1.8 | 1.7 |
| Create observer | 1 | 36 | 2.4 | 2.5 |
| Create observer copy | 1 | 41 | 2.3 | 2.3 |
| Dereference observer | 1 | 114 | 1 | 1 |
| Pointer | raw/unique | weak/shared | observer/obs_unique | observer/obs_sealed |
| --- | --- | --- | --- | --- |
| Create owner empty | 1 | 1.4 | 1.8 | 1.5 |
| Create owner | 1 | 2.2 | 2.9 | N/A |
| Create owner factory | 1 | 1.2 | 2.2 | 0.9 |
| Dereference owner | 1 | 0.7 | 1.3 | 1.0 |
| Create observer empty | 1 | 1.6 | 1.0 | 0.8 |
| Create observer | 1 | 5.3 | 1.6 | 1.6 |
| Create observer copy | 1 | 5.3 | 1.4 | 1.5 |
| Dereference observer | 1 | 9.4 | 1.4 | 0.8 |

*Compiler: Emscripten 2.0.34, std: libc++, OS: Node.js 14.15.5 + linux kernel 5.1.0, CPU: Ryzen 5 2600:*

| Pointer | raw/unique | weak/shared | observer/obs_unique | observer/obs_sealed |
| --- | --- | --- | --- | --- |
| Create owner empty | 1 | 6.9 | 1.1 | 1.0 |
| Create owner | 1 | 1.8 | 1.6 | N/A |
| Create owner factory | 1 | 1.2 | 1.7 | 1.0 |
| Dereference owner | 1 | 1.0 | 1.0 | 1.0 |
| Create observer empty | 1 | 11.4 | 1.6 | 1.6 |
| Create observer | 1 | 14.8 | 2.3 | 2.3 |
| Create observer copy | 1 | 14.9 | 2.3 | 2.5 |
| Dereference observer | 1 | 38.7 | 1.0 | 1.0 |


## Alternative implementation
Expand Down
Loading