+ docs in xo-alloc2/ + misc improvements
This commit is contained in:
parent
c172492007
commit
f52184f84c
29 changed files with 868 additions and 178 deletions
|
|
@ -128,6 +128,6 @@ add_subdirectory(xo-imgui)
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# documentation. must follow add_subdirectory() for satellite projects
|
# documentation. must follow add_subdirectory() for satellite projects
|
||||||
|
|
||||||
xo_umbrella_doxygen_deps(xo_facet xo_alloc indentlog xo_flatstring xo_ratio xo_unit xo_tokenizer xo_reader xo_interpreter xo_jit)
|
xo_umbrella_doxygen_deps(xo_facet xo_alloc xo_alloc2 indentlog xo_flatstring xo_ratio xo_unit xo_tokenizer xo_reader xo_interpreter xo_jit)
|
||||||
xo_umbrella_doxygen_config()
|
xo_umbrella_doxygen_config()
|
||||||
xo_umbrella_sphinx_config(index.rst docs/install.rst docs/glossary.rst)
|
xo_umbrella_sphinx_config(index.rst docs/install.rst docs/glossary.rst)
|
||||||
|
|
|
||||||
29
LICENSE
Normal file
29
LICENSE
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
Copyright (c) 2024 Roland Conybeare <git3ub@nym.hush.com>, All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Please also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of
|
||||||
|
external contributions to this project including patches, pull requests, etc.
|
||||||
34
README.md
34
README.md
|
|
@ -187,6 +187,40 @@ $ cmake -B .build -S . -DXO_ENABLE_VULKAN=1 -DXO_ENABLE_EXAMPLES=1 -DCMAKE_INSTA
|
||||||
|
|
||||||
Currently not supporting a nix sandbox build for xo-imgui
|
Currently not supporting a nix sandbox build for xo-imgui
|
||||||
|
|
||||||
|
## Directory Layout
|
||||||
|
|
||||||
|
(not in alphabetical order)
|
||||||
|
|
||||||
|
```
|
||||||
|
xo-umbrella2/
|
||||||
|
|
|
||||||
|
+- CMakeLists.txt top-level cmake config
|
||||||
|
+- cmake
|
||||||
|
| \- xo-bootstrap-macros.cmake configure xo cmake support for build
|
||||||
|
+- compile_commands.json symlink to path/to/build/compile_commands.json for LSP
|
||||||
|
|
|
||||||
|
+- conf.py sphinx config for project documentation
|
||||||
|
+- index.rst root of xo-umbrella2 doc tree
|
||||||
|
+- Doxyfile.in doxygen config template; cmake will prepare Doxyfile in build dir
|
||||||
|
+- _static/ static inputs to sphinx
|
||||||
|
|
|
||||||
|
+- etc
|
||||||
|
| +- hostegl/ sample video driver symlinks for WSL2
|
||||||
|
| \- hostubuntu/ sample video driver symlinks for ubuntu
|
||||||
|
|
|
||||||
|
+- default.nix top-level nix build (works w/ stock nixpkgs 25.05)
|
||||||
|
+- pkgs/ per-satellite nix builds. see xo-umbrella2/default.nix
|
||||||
|
| +- xo-callback.nix nix build for xo-umbrella2/xo-callback
|
||||||
|
| ..etc..
|
||||||
|
| \- xo-webutil.nix
|
||||||
|
|
|
||||||
|
+- xo-alloc/ xo-alloc subproject. independent git repo, using git subtree
|
||||||
|
+- xo-alloc2/ xo-alloc2 subproject.
|
||||||
|
..etc..
|
||||||
|
\- xo-webutil/
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## To view docs from WSL
|
## To view docs from WSL
|
||||||
|
|
||||||
1. find wsl IP address
|
1. find wsl IP address
|
||||||
|
|
|
||||||
4
conf.py
4
conf.py
|
|
@ -6,7 +6,7 @@
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
project = 'xo documentation'
|
project = 'xo umbrella2 documentation'
|
||||||
copyright = '2025, Roland Conybeare'
|
copyright = '2025, Roland Conybeare'
|
||||||
author = 'Roland Conybeare'
|
author = 'Roland Conybeare'
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ author = 'Roland Conybeare'
|
||||||
extensions = [ "breathe",
|
extensions = [ "breathe",
|
||||||
"sphinx.ext.mathjax", # inline math
|
"sphinx.ext.mathjax", # inline math
|
||||||
"sphinx.ext.autodoc", # generate info from docstrings
|
"sphinx.ext.autodoc", # generate info from docstrings
|
||||||
# "sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
"sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
||||||
"sphinxcontrib.plantuml", # text -> uml diagrams
|
"sphinxcontrib.plantuml", # text -> uml diagrams
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ Some features: kalman filters, stochastic processes, complex event processing, s
|
||||||
|
|
||||||
docs/install
|
docs/install
|
||||||
xo-facet/docs/index
|
xo-facet/docs/index
|
||||||
|
xo-alloc2/docs/index
|
||||||
xo-alloc/docs/index
|
xo-alloc/docs/index
|
||||||
xo-indentlog/docs/index
|
xo-indentlog/docs/index
|
||||||
xo-flatstring/docs/index
|
xo-flatstring/docs/index
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,6 @@ add_subdirectory(utest)
|
||||||
# docs targets depend on other library/utest/exec targets above,
|
# docs targets depend on other library/utest/exec targets above,
|
||||||
# --> must come after them.
|
# --> must come after them.
|
||||||
#
|
#
|
||||||
#add_subdirectory(docs)
|
add_subdirectory(docs)
|
||||||
|
|
||||||
# end CMakeLists.txt
|
# end CMakeLists.txt
|
||||||
|
|
|
||||||
39
xo-alloc2/docs/AAllocator-reference.rst
Normal file
39
xo-alloc2/docs/AAllocator-reference.rst
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
.. _AAllocator-reference:
|
||||||
|
|
||||||
|
AAllocator Reference
|
||||||
|
====================
|
||||||
|
|
||||||
|
Abstract interface facet for arena allocator.
|
||||||
|
Provides simple arena allocation.
|
||||||
|
|
||||||
|
Context
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. ditaa::
|
||||||
|
:--scale: 0.99
|
||||||
|
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_DArena |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_Xfer |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_ImplType |
|
||||||
|
+--------------+-----------------+
|
||||||
|
|cBLU | DArena |
|
||||||
|
| AAllocator +-----------------+
|
||||||
|
| | ArenaConfig |
|
||||||
|
+--------------+-----------------+
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#incldue <xo/alloc2/AAllocator.hpp>
|
||||||
|
|
||||||
|
Class
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. doxygenclass:: xo::mm::AAllocator
|
||||||
|
|
||||||
|
Methods
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. doxygengroup:: mm-allocator-methods
|
||||||
35
xo-alloc2/docs/ArenaConfig-reference.rst
Normal file
35
xo-alloc2/docs/ArenaConfig-reference.rst
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
.. _ArenaConfig-reference:
|
||||||
|
|
||||||
|
ArenaConfig Reference
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Configuration for an arena allocator
|
||||||
|
|
||||||
|
Context
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. ditaa::
|
||||||
|
:--scale: 0.99
|
||||||
|
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_DArena |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_Xfer |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_ImplType |
|
||||||
|
+--------------+-----------------+
|
||||||
|
| | DArena |
|
||||||
|
| AAllocator +-----------------+
|
||||||
|
| | ArenaConfig cBLU|
|
||||||
|
+--------------+-----------------+
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <xo/alloc2/DArena.hpp>
|
||||||
|
|
||||||
|
Class
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. doxygenclass:: xo::mm::ArenaConfig
|
||||||
|
|
||||||
|
.. doxygenclass:: mm-arenaconfig-instance-vars
|
||||||
17
xo-alloc2/docs/CMakeLists.txt
Normal file
17
xo-alloc2/docs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# xo-alloc2/docs/CMakeLists.txt
|
||||||
|
|
||||||
|
xo_doxygen_collect_deps()
|
||||||
|
xo_docdir_doxygen_config()
|
||||||
|
xo_docdir_sphinx_config(
|
||||||
|
index.rst
|
||||||
|
glossary.rst
|
||||||
|
implementation.rst
|
||||||
|
ArenaConfig-reference.rst
|
||||||
|
DArena-reference.rst
|
||||||
|
#install.rst
|
||||||
|
#introduction.rst
|
||||||
|
#implementation.rst
|
||||||
|
)
|
||||||
|
|
||||||
|
# see xo-reader/doc or xo-unit/doc for working examples
|
||||||
|
# example.rst install.rst implementation.rst
|
||||||
64
xo-alloc2/docs/DArena-reference.rst
Normal file
64
xo-alloc2/docs/DArena-reference.rst
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
.. _DArena-reference:
|
||||||
|
|
||||||
|
DArena Reference
|
||||||
|
================
|
||||||
|
|
||||||
|
Native representation for arena allocator
|
||||||
|
|
||||||
|
Context
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. ditaa::
|
||||||
|
:--scale: 0.99
|
||||||
|
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_DArena |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_Xfer |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_ImplType |
|
||||||
|
+--------------+-----------------+
|
||||||
|
| | DArena cBLU|
|
||||||
|
| AAllocator +-----------------+
|
||||||
|
| | ArenaConfig |
|
||||||
|
+--------------+-----------------+
|
||||||
|
|
||||||
|
.. code-block:: cpp
|
||||||
|
|
||||||
|
#include <xo/alloc2/DArena.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
Arena memory layout::
|
||||||
|
|
||||||
|
<----------------------------size-------------------------->
|
||||||
|
<------------committed-----------><-------uncommitted------>
|
||||||
|
<--allocated-->
|
||||||
|
|
||||||
|
XXXXXXXXXXXXXXX___________________..........................
|
||||||
|
^ ^ ^ ^
|
||||||
|
lo free limit hi
|
||||||
|
|
||||||
|
[X] allocated: in use
|
||||||
|
[_] committed: physical memory obtained
|
||||||
|
[.] uncommitted: mapped in virtual memory, not backed by memory
|
||||||
|
|
||||||
|
|
||||||
|
Class
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. doxygenclass:: xo::mm::DArena
|
||||||
|
|
||||||
|
Member Variables
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. doxygengroup:: mm-arena-instance-vars
|
||||||
|
|
||||||
|
Type Traits
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. doxygengroup:: mm-arena-traits
|
||||||
|
|
||||||
|
Constructors
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. doxygengroup:: mm-arena-ctors
|
||||||
70
xo-alloc2/docs/README
Normal file
70
xo-alloc2/docs/README
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
build
|
||||||
|
|
||||||
|
+-----------------------------------------------+
|
||||||
|
| cmake |
|
||||||
|
| CMakeLists.txt |
|
||||||
|
| $PREFIX/share/cmake/xo_macros/xo_cxx.cmake |
|
||||||
|
+-----------------------------------------------+
|
||||||
|
|
|
||||||
|
| +----------------------+
|
||||||
|
+------------------------------------------------->| .build/docs/Doxyfile |
|
||||||
|
| +----------------------+
|
||||||
|
| |
|
||||||
|
| /------------/
|
||||||
|
| |
|
||||||
|
| v
|
||||||
|
| +---------------------------------------+ +-----------------+
|
||||||
|
+---->| doxygen |--->| .build/docs/dox |
|
||||||
|
| | $PREFIX/share/xo-macros/Doxyfile.in | | +- html/ |
|
||||||
|
| +---------------------------------------+ | +- xml/ |
|
||||||
|
| +-----------------+
|
||||||
|
| |
|
||||||
|
| /------------/
|
||||||
|
| |
|
||||||
|
| v
|
||||||
|
| +---------------------------------------+ +--------------------+
|
||||||
|
\---->| sphinx |--->| .build/docs/sphinx |
|
||||||
|
| +- conf.py | | +- html/ |
|
||||||
|
| +- _static/ | +--------------------+
|
||||||
|
| +- *.rst |
|
||||||
|
+---------------------------------------+
|
||||||
|
|
||||||
|
files
|
||||||
|
|
||||||
|
README this file
|
||||||
|
CMakeLists.txt build entry point
|
||||||
|
conf.py sphinx config
|
||||||
|
_static static files for sphinx
|
||||||
|
|
||||||
|
map
|
||||||
|
|
||||||
|
index.rst
|
||||||
|
+- install.rst
|
||||||
|
+- examples.rst
|
||||||
|
+- unit-quantities.rst
|
||||||
|
+- classes.rst
|
||||||
|
+- glossary.rst
|
||||||
|
...
|
||||||
|
|
||||||
|
examples
|
||||||
|
|
||||||
|
.. doxygenclass:: ${c++ class name}
|
||||||
|
:project:
|
||||||
|
:path:
|
||||||
|
:members:
|
||||||
|
:protected-members:
|
||||||
|
:private-members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-groups:
|
||||||
|
:members-only:
|
||||||
|
:outline:
|
||||||
|
:no-link:
|
||||||
|
:allow-dot-graphs:
|
||||||
|
|
||||||
|
.. doxygendefine:: ${c preprocessor define}
|
||||||
|
|
||||||
|
.. doxygenconcept:: ${c++ concept definition}
|
||||||
|
|
||||||
|
.. doxygenenum:: ${c++ enum definition}
|
||||||
|
|
||||||
|
.. doxygenfunction:: ${c++ function name}
|
||||||
1
xo-alloc2/docs/_static/README
vendored
Normal file
1
xo-alloc2/docs/_static/README
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
add any static {.html, .js, ..} files for sphinx to pickup here
|
||||||
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 303 KiB |
39
xo-alloc2/docs/conf.py
Normal file
39
xo-alloc2/docs/conf.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# For the full list of built-in configuration values, see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
||||||
|
|
||||||
|
project = 'xo alloc2 documentation'
|
||||||
|
copyright = '2025, Roland Conybeare'
|
||||||
|
author = 'Roland Conybeare'
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
||||||
|
#extensions = []
|
||||||
|
extensions = [ "breathe",
|
||||||
|
"sphinx.ext.mathjax", # inline math
|
||||||
|
"sphinx.ext.autodoc", # generate info from docstrings
|
||||||
|
"sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
||||||
|
"sphinxcontrib.plantuml" # text -> uml diagrams
|
||||||
|
]
|
||||||
|
|
||||||
|
# note: breathe requires doxygen xml output -> must have GENERATE_XML = YES in Doxyfile.in
|
||||||
|
# match project name in Doxyfile.in
|
||||||
|
breathe_default_project = "xodoxxml"
|
||||||
|
|
||||||
|
templates_path = ['_templates']
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
pygments_style = 'sphinx'
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
||||||
|
|
||||||
|
#html_theme = 'alabaster'
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
html_static_path = ['_static']
|
||||||
|
html_favicon = '_static/img/favicon.ico'
|
||||||
24
xo-alloc2/docs/glossary.rst
Normal file
24
xo-alloc2/docs/glossary.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
.. _glossary:
|
||||||
|
|
||||||
|
Glossary
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. glossary::
|
||||||
|
FOMO
|
||||||
|
| facet object model
|
||||||
|
|
||||||
|
page
|
||||||
|
| a (4k) page of virtual memory.
|
||||||
|
| O/S manages virtual memory in chunks of this size.
|
||||||
|
|
||||||
|
hugepage
|
||||||
|
| large (2MB) VM page; use to reduce page fault expense and TLB pressure.
|
||||||
|
|
||||||
|
THP
|
||||||
|
| transparent huge pages
|
||||||
|
|
||||||
|
TLB
|
||||||
|
| translation lookaside buffer
|
||||||
|
|
||||||
|
VM
|
||||||
|
| virtual memory
|
||||||
51
xo-alloc2/docs/implementation.rst
Normal file
51
xo-alloc2/docs/implementation.rst
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
.. _implementation:
|
||||||
|
|
||||||
|
Components
|
||||||
|
==========
|
||||||
|
|
||||||
|
Library dependency tower for *xo-alloc2*
|
||||||
|
|
||||||
|
.. ditaa::
|
||||||
|
|
||||||
|
+-----------------+
|
||||||
|
| xo_alloc2 |
|
||||||
|
+-----------------+
|
||||||
|
| xo_facet |
|
||||||
|
+-----------------+
|
||||||
|
| xo_cmake |
|
||||||
|
+-----------------+
|
||||||
|
|
||||||
|
Abstraction tower for *xo-alloc2* components
|
||||||
|
|
||||||
|
.. ditaa::
|
||||||
|
:--scale: 0.99
|
||||||
|
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_DArena |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_Xfer |
|
||||||
|
+--------------------------------+
|
||||||
|
| IAllocator_ImplType |
|
||||||
|
+--------------+-----------------+
|
||||||
|
| | DArena |
|
||||||
|
| AAllocator +-----------------+
|
||||||
|
| | ArenaConfig |
|
||||||
|
+--------------+-----------------+
|
||||||
|
|
||||||
|
.. list-table:: Descriptions
|
||||||
|
:header-rows: 1
|
||||||
|
:widths: 20 90
|
||||||
|
|
||||||
|
* - Component
|
||||||
|
- Description
|
||||||
|
* - ``AAllocator``
|
||||||
|
- allocator facet (abstract interface)
|
||||||
|
* - ``DArena``
|
||||||
|
- arena representation
|
||||||
|
* - ``IAllocator_ImplType<D>``
|
||||||
|
- lookup implementation for allocator A
|
||||||
|
with representation D.
|
||||||
|
* - ``IAllocator_Xfer<D>``
|
||||||
|
- transfer interface. downcast to native state.
|
||||||
|
* - ``IAllocator_DArena``
|
||||||
|
- allocator implementation for ``DArena``
|
||||||
28
xo-alloc2/docs/index.rst
Normal file
28
xo-alloc2/docs/index.rst
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
# xo-alloc2 documentation master file
|
||||||
|
|
||||||
|
xo-alloc2 documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
xo-alloc2 is intended to provide fast vm-aware arena allocation.
|
||||||
|
Next-generation version of xo-alloc.
|
||||||
|
At present (Dec 2025) xo-alloc is fully functional,
|
||||||
|
while xo-alloc2 is aspirational.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
* allocates uncommitted virtual memory, and commits on demand.
|
||||||
|
* ses THP (Transparent Huge Pages) when available.
|
||||||
|
|
||||||
|
Implemented using FOMO (faceted rust-like object model) from xo-facet
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: xo-alloc2 contents
|
||||||
|
|
||||||
|
implementation
|
||||||
|
AAllocator-reference
|
||||||
|
ArenaConfig-reference
|
||||||
|
DArena-reference
|
||||||
|
glossary
|
||||||
|
genindex
|
||||||
|
search
|
||||||
|
|
@ -14,52 +14,86 @@ namespace xo {
|
||||||
using Copaque = const void *;
|
using Copaque = const void *;
|
||||||
using Opaque = void *;
|
using Opaque = void *;
|
||||||
|
|
||||||
|
/** @class AAllocator
|
||||||
/** Abstract facet for allocation
|
* @brief Abstract facet for allocation
|
||||||
*
|
*
|
||||||
* <----------------------------size-------------------------->
|
|
||||||
* <------------committed-----------><-------uncommitted------>
|
|
||||||
* <--allocated-->
|
|
||||||
*
|
|
||||||
* XXXXXXXXXXXXXXX___________________..........................
|
|
||||||
*
|
|
||||||
* allocated: in use
|
|
||||||
* committed: physical memory obtained
|
|
||||||
* uncommitted: mapped in virtual memory, not backed by memory
|
|
||||||
**/
|
**/
|
||||||
struct AAllocator {
|
struct AAllocator {
|
||||||
/** RTTI: unique id# for actual runtime data repr **/
|
/*
|
||||||
|
* <----------------------------size-------------------------->
|
||||||
|
* <------------committed-----------><-------uncommitted------>
|
||||||
|
* <--allocated-->
|
||||||
|
*
|
||||||
|
* XXXXXXXXXXXXXXX___________________..........................
|
||||||
|
*
|
||||||
|
* allocated: in use
|
||||||
|
* committed: physical memory obtained
|
||||||
|
* uncommitted: mapped in virtual memory, not backed by memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup mm-allocator-methods Allocator methods **/
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/** RTTI: unique id# for actual runtime data representation **/
|
||||||
virtual int32_t _typeseq() = 0;
|
virtual int32_t _typeseq() = 0;
|
||||||
/** optional name for this allocator.
|
/** optional name for allocator @p d
|
||||||
* Labeling, for diagnostics.
|
* Labeling, for diagnostics.
|
||||||
**/
|
**/
|
||||||
virtual const std::string & name(Copaque d) = 0;
|
virtual const std::string & name(Copaque d) = 0;
|
||||||
/** allocator size in bytes (up to reserved limit)
|
/** allocator size in bytes (up to reserved limit)
|
||||||
* includes allocated and uncomitted memory
|
* for allocator @p d.
|
||||||
|
* Includes allocated and uncomitted memory
|
||||||
**/
|
**/
|
||||||
virtual std::size_t size(Copaque d) = 0;
|
virtual std::size_t size(Copaque d) = 0;
|
||||||
/** committed size (physical addresses obtained)
|
/** committed size (physical addresses obtained)
|
||||||
|
* for allocator @p d.
|
||||||
**/
|
**/
|
||||||
virtual std::size_t committed(Copaque d) = 0;
|
virtual std::size_t committed(Copaque d) = 0;
|
||||||
/** true iff pointer @p in range of this allocator
|
/** true iff allocator @p d is responsible for memory at address @p p.
|
||||||
**/
|
**/
|
||||||
virtual bool contains(Copaque d, const void * p) = 0;
|
virtual bool contains(Copaque d, const void * p) = 0;
|
||||||
|
|
||||||
/** allocate @p z bytes of memory. **/
|
/** allocate @p z bytes of memory from allocator @p d. **/
|
||||||
virtual std::byte * alloc(Opaque d, std::size_t z) = 0;
|
virtual std::byte * alloc(Opaque d, std::size_t z) = 0;
|
||||||
/** reset allocator to empty state **/
|
/** reset allocator @p d to empty state **/
|
||||||
virtual void clear(Opaque d) = 0;
|
virtual void clear(Opaque d) = 0;
|
||||||
/** **/
|
/** destruct allocator @p d **/
|
||||||
virtual void destruct_data(Opaque d) = 0;
|
virtual void destruct_data(Opaque d) = 0;
|
||||||
};
|
|
||||||
|
///@}
|
||||||
|
}; /*AAllocator*/
|
||||||
|
|
||||||
template <typename DRepr>
|
template <typename DRepr>
|
||||||
struct IAllocator_Impl;
|
struct IAllocator_Impl;
|
||||||
|
|
||||||
|
template <typename DRepr>
|
||||||
|
using IAllocator_ImplType = IAllocator_Impl<DRepr>::ImplType;
|
||||||
|
|
||||||
|
struct IAllocator_Any : public AAllocator {
|
||||||
|
using Impl = Allocator_ImplType<xo::facet::DVariantPlaceholder>;
|
||||||
|
|
||||||
|
// from AAllocator
|
||||||
|
int32_t _typeseq() override { return s_typeseq; }
|
||||||
|
|
||||||
|
const std::string & name(Copaque d) override { assert(false); static std::string x; return x; }
|
||||||
|
std::size_t size(Copaque d) override { assert(false); return 0ul; }
|
||||||
|
std::size_t committed(Copaque d) override { assert(false); reutrn 0ul; }
|
||||||
|
bool contains(Copaque d, const void * p) override { assert(false); return false; }
|
||||||
|
|
||||||
|
std::byte * alloc(Opaque d, std::size_t z) override { assert(false); return nullptr; }
|
||||||
|
void clear(Opaque d) override { assert(false); }
|
||||||
|
void destruct_data(Opaque d) override { assert(false); }
|
||||||
|
|
||||||
|
static int32_t s_typeseq;
|
||||||
|
static bool _valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @class IAllocator_Xfer
|
||||||
|
**/
|
||||||
template <typename DRepr>
|
template <typename DRepr>
|
||||||
struct IAllocator_Xfer : public AAllocator {
|
struct IAllocator_Xfer : public AAllocator {
|
||||||
// parallel interface to AAllocator, with specific data type
|
// parallel interface to AAllocator, with specific data type
|
||||||
using Impl = IAllocator_Impl<DRepr>;
|
using Impl = IAllocator_ImplType<DRepr>;
|
||||||
|
|
||||||
static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; }
|
static const DRepr & _dcast(Copaque d) { return *(const DRepr *)d; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,17 @@
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace mm {
|
namespace mm {
|
||||||
|
|
||||||
/** ArenaConfig
|
/** @class ArenaConfig
|
||||||
|
*
|
||||||
|
* @brief configuration for a @ref DArena instance
|
||||||
**/
|
**/
|
||||||
struct ArenaConfig {
|
struct ArenaConfig {
|
||||||
|
/** @defgroup mm-arenaconfig-instance-vars ArenaConfig members **/
|
||||||
|
///@{
|
||||||
|
|
||||||
/** optional name, for diagnostics **/
|
/** optional name, for diagnostics **/
|
||||||
std::string name_;
|
std::string name_;
|
||||||
/** arena size -- hard max = reserved virtual memory **/
|
/** desired arena size -- hard max = reserved virtual memory **/
|
||||||
std::size_t size_;
|
std::size_t size_;
|
||||||
/** hugepage size -- using huge pages relieves some TLB pressure
|
/** hugepage size -- using huge pages relieves some TLB pressure
|
||||||
* (provided you use their full extent :)
|
* (provided you use their full extent :)
|
||||||
|
|
@ -23,31 +28,70 @@ namespace xo {
|
||||||
std::size_t hugepage_z_ = 2 * 1024 * 1024;
|
std::size_t hugepage_z_ = 2 * 1024 * 1024;
|
||||||
/** true to enable debug logging **/
|
/** true to enable debug logging **/
|
||||||
bool debug_flag_ = false;
|
bool debug_flag_ = false;
|
||||||
|
|
||||||
|
///@}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Arena allocator state
|
/** @class DArena
|
||||||
*
|
*
|
||||||
* <----------------------------size-------------------------->
|
* @brief represent arena allocator state
|
||||||
* <------------committed-----------><-------uncommitted------>
|
|
||||||
* <--allocated-->
|
|
||||||
*
|
*
|
||||||
* XXXXXXXXXXXXXXX___________________..........................
|
* Provides minimal RAII functionality around memory mapping.
|
||||||
*
|
* For allocation see @ref IAllocator_DArena
|
||||||
* allocated: in use
|
|
||||||
* committed: physical memory obtained
|
|
||||||
* uncommitted: mapped in virtual memory, not backed by memory
|
|
||||||
**/
|
**/
|
||||||
struct DArena {
|
struct DArena {
|
||||||
/** [lo, hi) already-mapped address range **/
|
/*
|
||||||
DArena(const ArenaConfig & cfg,
|
* <----------------------------size-------------------------->
|
||||||
std::byte * lo,
|
* <------------committed-----------><-------uncommitted------>
|
||||||
std::byte * hi);
|
* <--allocated-->
|
||||||
|
*
|
||||||
|
* XXXXXXXXXXXXXXX___________________..........................
|
||||||
|
*
|
||||||
|
* [X] allocated: in use
|
||||||
|
* [_] committed: physical memory obtained
|
||||||
|
* [.] uncommitted: mapped in virtual memory, not backed by memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @defgroup mm-arena-traits arena type traits **/
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/** @brief an amount of memory **/
|
||||||
|
using size_type = std::size_t;
|
||||||
|
/** @brief a contiguous memory range **/
|
||||||
|
using range_type = std::pair<std::byte*,std::byte*>;
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/** @defgroup mm-arena-ctors arena constructors and destructors **/
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/** create arena per configuration @p cfg. **/
|
||||||
|
static DArena map(const ArenaConfig & cfg);
|
||||||
|
|
||||||
|
/** ctor from already-mapped (but not committed) address range **/
|
||||||
|
DArena(const ArenaConfig & cfg, size_type page_z, std::byte * lo, std::byte * hi);
|
||||||
|
/** DArena is not copyable **/
|
||||||
|
DArena(const DArena & other) = delete;
|
||||||
|
/** move ctor **/
|
||||||
|
DArena(DArena && other);
|
||||||
|
/** dtor releases mapped memory **/
|
||||||
~DArena();
|
~DArena();
|
||||||
|
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/** obtain uncommitted contiguous memory range comprising
|
||||||
|
* a whole multiple of @p hugepage_z bytes, of at least size @p req_z,
|
||||||
|
* aligned on a @p hugepage_z boundary
|
||||||
|
**/
|
||||||
|
static range_type map_aligned_range(size_type req_z, size_type hugepage_z);
|
||||||
|
|
||||||
|
/** @defgroup mm-arena-instance-vars **/
|
||||||
|
///@{
|
||||||
|
|
||||||
|
/** arena configuration **/
|
||||||
ArenaConfig config_;
|
ArenaConfig config_;
|
||||||
|
|
||||||
/** size of a VM page (via getpagesize()). Likely 4k **/
|
/** size of a VM page (obtained automatically via getpagesize()). Likely 4k **/
|
||||||
std::size_t page_z_ = 0;
|
std::size_t page_z_ = 0;
|
||||||
|
|
||||||
/** arena owns memory in range [@ref lo_, @ref hi_)
|
/** arena owns memory in range [@ref lo_, @ref hi_)
|
||||||
|
|
@ -74,6 +118,8 @@ namespace xo {
|
||||||
* Memory in range [@ref limit_, @ref hi_) is uncommitted
|
* Memory in range [@ref limit_, @ref hi_) is uncommitted
|
||||||
**/
|
**/
|
||||||
std::byte * hi_ = nullptr;
|
std::byte * hi_ = nullptr;
|
||||||
|
|
||||||
|
///@}
|
||||||
};
|
};
|
||||||
|
|
||||||
} /*namespace mm*/
|
} /*namespace mm*/
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,8 @@
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace mm {
|
namespace mm {
|
||||||
|
|
||||||
template <>
|
struct IAllocator_DArena {
|
||||||
struct IAllocator_Impl<DArena> {
|
static const std::string & name(const DArena & s);
|
||||||
static const std::string & name(const DArena & s) {
|
|
||||||
return s.name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::size_t size(const DArena & s);
|
static std::size_t size(const DArena & s);
|
||||||
static std::size_t committed(const DArena & s);
|
static std::size_t committed(const DArena & s);
|
||||||
static bool contains(const DArena & s, const void * p);
|
static bool contains(const DArena & s, const void * p);
|
||||||
|
|
@ -23,6 +19,10 @@ namespace xo {
|
||||||
static void destruct_data(DArena & s);
|
static void destruct_data(DArena & s);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct IAllocator_Impl<DArena> {
|
||||||
|
using ImplType = IAllocator_DArena;
|
||||||
|
};
|
||||||
|
|
||||||
} /*namespace mm*/
|
} /*namespace mm*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
|
||||||
38
xo-alloc2/include/xo/alloc2/RAllocator.hpp
Normal file
38
xo-alloc2/include/xo/alloc2/RAllocator.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/** @file RAllocator.hpp
|
||||||
|
*
|
||||||
|
* @author Roland Conybeare, Dec 2025
|
||||||
|
**/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "xo/facet/RRouter.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
namespace mm {
|
||||||
|
/** @class RAllocator **/
|
||||||
|
template <typename Object>
|
||||||
|
struct RAllocator : public Object {
|
||||||
|
using ObjectType = Object;
|
||||||
|
|
||||||
|
RAllocator() {}
|
||||||
|
RAllocator(Object::DataPtr data) : Object{std::move(data)} {}
|
||||||
|
|
||||||
|
int32_t _typeseq() const { return Object::iface()->_typeseq(); }
|
||||||
|
|
||||||
|
static bool _valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Object>
|
||||||
|
bool
|
||||||
|
RAllocator<Object>::_valid = facet::valid_object_router<Object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace facet {
|
||||||
|
template <typename Object>
|
||||||
|
struct RoutingFor<xo::mm::AAllocator, Object> {
|
||||||
|
using RoutingType = xo::mm::RAllocator<Object>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end RAllocator.hpp */
|
||||||
19
xo-alloc2/src/alloc2/AAllocator.cpp
Normal file
19
xo-alloc2/src/alloc2/AAllocator.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/** @file AAllocator.cpp **/
|
||||||
|
|
||||||
|
#include "xo/alloc2/AAllocator.hpp"
|
||||||
|
|
||||||
|
namespace xo {
|
||||||
|
using xo::facet::DVariantPlaceholder;
|
||||||
|
using xo::facet::typeseq;
|
||||||
|
using xo::facet::valid_facet_implementation;
|
||||||
|
|
||||||
|
namespace mm {
|
||||||
|
int32_t
|
||||||
|
IAllocator_Any::s_typeseq = typeseq::id<DVariantPlaceholder>;
|
||||||
|
|
||||||
|
bool
|
||||||
|
IAllocator_Any::_valid = valid_facet_implementation<AAllocator, IAllocator_Any>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end AAlocator.cpp */
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
set(SELF_LIB xo_alloc2)
|
set(SELF_LIB xo_alloc2)
|
||||||
set(SELF_SRCS
|
set(SELF_SRCS
|
||||||
|
AAllocator.cpp
|
||||||
DArena.cpp
|
DArena.cpp
|
||||||
IAllocator_DArena.cpp
|
IAllocator_DArena.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,107 +9,135 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <sys/mman.h> // for ::munmap()
|
#include <sys/mman.h> // for ::munmap()
|
||||||
#include <unistd.h> // for ::getpagesize()
|
#include <unistd.h> // for ::getpagesize()
|
||||||
|
#include <string.h> // for ::memset()
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
using std::byte;
|
using std::byte;
|
||||||
|
using std::size_t;
|
||||||
|
|
||||||
namespace mm {
|
namespace mm {
|
||||||
|
|
||||||
DArena::DArena(const ArenaConfig & cfg,
|
/** Map a contiguous uncommitted memory range comprising
|
||||||
std::byte * lo,
|
* a whole multiple of @p hugepage_z, with at least
|
||||||
std::byte * hi
|
* @p req_z bytes.
|
||||||
)
|
*
|
||||||
|
* Memory will also be aligned on @p hugepage_z boundary
|
||||||
|
* (2MB in practice)
|
||||||
|
*
|
||||||
|
* - @p req_z is rounded up to a multiple of @p hugepage_z
|
||||||
|
* - Resulting uncommitted address range not backed by
|
||||||
|
* physical memory.
|
||||||
|
* - since hugpage-aligned, can find base of mapped range
|
||||||
|
* by masking off the bottom log2(align_z) bits.
|
||||||
|
* May rely on this for GC metadata
|
||||||
|
* - opt-in to transparent huge pages (THP).
|
||||||
|
* Reduces page-fault time by a lot, in return for
|
||||||
|
* lower VM granularity
|
||||||
|
* - rejecting inferior MAP_HUGETLB|MAP_HUGE_2MB flags on ::mmap here:
|
||||||
|
* - requires previously-reserved memory in /proc/sys/vm/nr_hugepages
|
||||||
|
* - reserved pages permenently resident in RAM, never swapped
|
||||||
|
* - memory cost incurred even if no application is using said pages
|
||||||
|
*
|
||||||
|
* TODO: for OSX -> need something else here.
|
||||||
|
* MAP_ALIGNED_SUPER with mmap() and/or
|
||||||
|
* use mach_vm_allocate()
|
||||||
|
*
|
||||||
|
* @return pair giving mapped address range [lo, hi)
|
||||||
|
**/
|
||||||
|
auto
|
||||||
|
DArena::map_aligned_range(size_t req_z, size_t hugepage_z) -> range_type
|
||||||
{
|
{
|
||||||
//scope log(XO_DEBUG(debug_flag), xtag("name", name));
|
// 1. round up to multiple of hugepage_z
|
||||||
|
size_t target_z = padding::with_padding(req_z, hugepage_z); // 4.
|
||||||
|
|
||||||
this->page_z_ = getpagesize();
|
// 2. mmap() will give us page-aligned memory,
|
||||||
|
// but not hugepage-aligned.
|
||||||
// 1. need k pagetable entries where k is lub {k | k * .page_z >= z}
|
|
||||||
// 2. base will be aligned with .page_z but likely not with .hugepage_z
|
|
||||||
// 3. bad to have misalignment, because misaligned {prefix, suffix} of [base, base+z)
|
|
||||||
// will use 4k pages instead of 2mb pages
|
|
||||||
//
|
//
|
||||||
// strategy:
|
// Over-request by hugepage_z to ensure
|
||||||
// 4. round up z to multiple of hugepage_z_
|
// hugepage-aligned subrange of size target_z
|
||||||
// 5. over-request so reserved range contains an aligned subrange of size z
|
|
||||||
// 6. unmap misaligned prefix
|
|
||||||
// 7. unmap misaligned suffix.
|
|
||||||
// 8. enable huge pages for now-aligned remainder of reserved range
|
|
||||||
//
|
//
|
||||||
// Z. note: rejecting inferior MAP_HUGETLB|MAP_HUGE_2MB flags on ::mmap here:
|
byte * base = (byte *)(::mmap(nullptr,
|
||||||
// Za. requires previously-reserved memory in /proc/sys/vm/nr_hugepages
|
target_z + hugepage_z,
|
||||||
// Zb. reserved pages permenently resident in RAM, never swapped
|
PROT_NONE,
|
||||||
// Zc. memory cost incurred even if no application is using said pages
|
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||||
|
-1, 0));
|
||||||
|
|
||||||
std::size_t z = cfg.size_;
|
// on mmap success: upper limit of mapped address range
|
||||||
|
byte * hi = base + (target_z + hugepage_z);
|
||||||
z = padding::with_padding(z, config_.hugepage_z_); // 4.
|
// lowest hugepage-aligned address in [base, hi)
|
||||||
|
byte * aligned_base = (byte *)(padding::with_padding((size_t)base, hugepage_z));
|
||||||
// 5.
|
// end of hugeppage-aligned range starting at aligned_base
|
||||||
byte * base = reinterpret_cast<byte *>(
|
byte * aligned_hi = aligned_base + target_z;
|
||||||
::mmap(nullptr,
|
|
||||||
z + config_.hugepage_z_,
|
|
||||||
PROT_NONE,
|
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
|
||||||
-1, 0));
|
|
||||||
|
|
||||||
#ifdef NOT_YET
|
#ifdef NOT_YET
|
||||||
log && log("acquired memory [lo,hi) using mmap",
|
log && log("acquired memory [lo,hi) using mmap",
|
||||||
xtag("lo", base),
|
xtag("lo", base),
|
||||||
xtag("z", z),
|
xtag("req_z", req_z),
|
||||||
xtag("hi", reinterpret_cast<byte *>(base) + z));
|
xtag("target_z", target_z),
|
||||||
|
xtag("hi", (byte *)(base) + z));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (base == MAP_FAILED) {
|
|
||||||
assert(false);
|
// 3. assess mmap success
|
||||||
|
{
|
||||||
|
if (base == MAP_FAILED) {
|
||||||
|
assert(false);
|
||||||
#ifdef NOPE
|
#ifdef NOPE
|
||||||
throw std::runtime_error(tostr("ArenaAlloc: uncommitted allocation failed",
|
throw std::runtime_error(tostr("ArenaAlloc: uncommitted allocation failed",
|
||||||
xtag("size", z)));
|
xtag("size", z)));
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
assert((size_t)aligned_base % hugepage_z == 0);
|
||||||
|
assert(aligned_base >= base);
|
||||||
|
assert(aligned_base < base + hugepage_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte * aligned_base = reinterpret_cast<byte *>
|
// 4. release unaligned prefix
|
||||||
(padding::with_padding(reinterpret_cast<size_t>(base),
|
|
||||||
config_.hugepage_z_));
|
|
||||||
|
|
||||||
assert(reinterpret_cast<size_t>(aligned_base) % config_.hugepage_z_ == 0);
|
|
||||||
assert(aligned_base >= base);
|
|
||||||
assert(aligned_base < base + config_.hugepage_z_);
|
|
||||||
|
|
||||||
if (base < aligned_base) {
|
if (base < aligned_base) {
|
||||||
size_t prefix = aligned_base - base;
|
size_t ua_prefix = aligned_base - base;
|
||||||
|
|
||||||
::munmap(base, prefix); // 6.
|
::munmap(base, ua_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte * aligned_hi = aligned_base + z;
|
// 5. release unaligned suffix
|
||||||
byte * hi = base + z + config_.hugepage_z_;
|
|
||||||
|
|
||||||
if (aligned_hi < hi) {
|
if (aligned_hi < hi) {
|
||||||
size_t suffix = hi - aligned_hi;
|
size_t suffix = hi - aligned_hi;
|
||||||
|
|
||||||
::munmap(aligned_hi, suffix); // 7.
|
::munmap(aligned_hi, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/** opt-in to huge pages, provided they're available.
|
/** linux:
|
||||||
* otherwise fallback gracefully
|
* opt-in to transparent huge pages (THP)
|
||||||
|
* provided OS configured to support them.
|
||||||
|
* otherwise fallback gracefully.
|
||||||
|
*
|
||||||
|
* Huge pages -> use fewer TLB entries + faster
|
||||||
|
* shorter path through page table.
|
||||||
|
*
|
||||||
|
* When we commit (i.e. obtain physical memory on page fault),
|
||||||
|
* typically expect to pay ~1us per superpage.
|
||||||
|
* Much better than ~500us to commit 512 4k VM pages.
|
||||||
|
*
|
||||||
|
* But wasted if we don't use the memory.
|
||||||
**/
|
**/
|
||||||
::madvise(aligned_base, z, MADV_HUGEPAGE); // 8.
|
::madvise(aligned_base, target_z, MADV_HUGEPAGE); // 8.
|
||||||
#endif
|
#endif
|
||||||
// TODO: for OSX -> need something else here.
|
|
||||||
// MAP_ALIGNED_SUPER with mmap() and/or
|
|
||||||
// use mach_vm_allocate()
|
|
||||||
//
|
|
||||||
|
|
||||||
this->lo_ = aligned_base;
|
return std::make_pair(aligned_base, aligned_hi);
|
||||||
this->committed_z_ = 0;
|
}
|
||||||
//this->checkpoint_ = lo_;
|
|
||||||
this->free_ = lo_;
|
DArena
|
||||||
this->limit_ = lo_;
|
DArena::map(const ArenaConfig & cfg)
|
||||||
this->hi_ = lo_ + z;
|
{
|
||||||
|
//scope log(XO_DEBUG(debug_flag), xtag("name", name));
|
||||||
|
|
||||||
|
auto [lo, hi] = map_aligned_range(cfg.size_, cfg.hugepage_z_);
|
||||||
|
|
||||||
|
if (!lo) {
|
||||||
|
// control here implies mmap() failed silently
|
||||||
|
|
||||||
if (!lo_) {
|
|
||||||
assert(false);
|
assert(false);
|
||||||
#ifdef NOPE
|
#ifdef NOPE
|
||||||
throw std::runtime_error(tostr("ArenaAlloc: allocation failed",
|
throw std::runtime_error(tostr("ArenaAlloc: allocation failed",
|
||||||
|
|
@ -117,11 +145,47 @@ namespace xo {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t page_z = getpagesize();
|
||||||
|
|
||||||
|
|
||||||
#ifdef NOPE
|
#ifdef NOPE
|
||||||
log && log(xtag("lo", (void*)lo_),
|
log && log(xtag("lo", (void*)lo_),
|
||||||
xtag("page_z", page_z_),
|
xtag("page_z", page_z_),
|
||||||
xtag("hugepage_z", hugepage_z_));
|
xtag("hugepage_z", hugepage_z_));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return DArena(cfg, page_z, lo, hi);
|
||||||
|
} /*map*/
|
||||||
|
|
||||||
|
DArena::DArena(const ArenaConfig & cfg,
|
||||||
|
size_type page_z,
|
||||||
|
byte * lo,
|
||||||
|
byte * hi) : config_{cfg},
|
||||||
|
page_z_{page_z},
|
||||||
|
lo_{lo},
|
||||||
|
committed_z_{0},
|
||||||
|
free_{lo},
|
||||||
|
limit_{lo},
|
||||||
|
hi_{hi}
|
||||||
|
{
|
||||||
|
//retval.checkpoint_ = lo_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DArena::DArena(DArena && other) {
|
||||||
|
config_ = other.config_;
|
||||||
|
page_z_ = other.page_z_;
|
||||||
|
lo_ = other.lo_;
|
||||||
|
committed_z_ = other.committed_z_;
|
||||||
|
free_ = other.free_;
|
||||||
|
limit_ = other.limit_;
|
||||||
|
hi_ = other.hi_;
|
||||||
|
|
||||||
|
other.config_ = ArenaConfig();
|
||||||
|
other.lo_ = nullptr;
|
||||||
|
other.committed_z_ = 0;
|
||||||
|
other.free_ = nullptr;
|
||||||
|
other.limit_ = nullptr;
|
||||||
|
other.hi_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DArena::~DArena()
|
DArena::~DArena()
|
||||||
|
|
@ -136,12 +200,12 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// hygiene
|
// hygiene
|
||||||
lo_ = nullptr;
|
this->lo_ = nullptr;
|
||||||
committed_z_ = 0;
|
this->committed_z_ = 0;
|
||||||
// checkpoint_ = nullptr;
|
// checkpoint_ = nullptr;
|
||||||
free_ = nullptr;
|
this->free_ = nullptr;
|
||||||
limit_ = nullptr;
|
this->limit_ = nullptr;
|
||||||
hi_ = nullptr;
|
this->hi_ = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
|
||||||
|
|
@ -9,25 +9,30 @@
|
||||||
namespace xo {
|
namespace xo {
|
||||||
namespace mm {
|
namespace mm {
|
||||||
|
|
||||||
|
const std::string &
|
||||||
|
IAllocator_DArena::name(const DArena & s) {
|
||||||
|
return s.config_.name_;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
IAllocator_Impl<DArena>::size(const DArena & s) {
|
IAllocator_DArena::size(const DArena & s) {
|
||||||
return s.limit_ - s.lo_;
|
return s.limit_ - s.lo_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
IAllocator_Impl<DArena>::committed(const DArena & s) {
|
IAllocator_DArena::committed(const DArena & s) {
|
||||||
return s.committed_z_;
|
return s.committed_z_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IAllocator_Impl<DArena>::contains(const DArena & s,
|
IAllocator_DArena::contains(const DArena & s,
|
||||||
const void * p)
|
const void * p)
|
||||||
{
|
{
|
||||||
return (s.lo_ <= p) && (p < s.hi_);
|
return (s.lo_ <= p) && (p < s.hi_);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::byte *
|
std::byte *
|
||||||
IAllocator_Impl<DArena>::alloc(const DArena & s,
|
IAllocator_DArena::alloc(const DArena & s,
|
||||||
std::size_t z)
|
std::size_t z)
|
||||||
{
|
{
|
||||||
(void)s;
|
(void)s;
|
||||||
|
|
@ -39,14 +44,14 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IAllocator_Impl<DArena>::clear(DArena & s)
|
IAllocator_DArena::clear(DArena & s)
|
||||||
{
|
{
|
||||||
s.free_ = s.lo_;
|
s.free_ = s.lo_;
|
||||||
//s.checkpoint_ = s.lo_;
|
//s.checkpoint_ = s.lo_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
IAllocator_Impl<DArena>::destruct_data(DArena & s)
|
IAllocator_DArena::destruct_data(DArena & s)
|
||||||
{
|
{
|
||||||
s.~DArena();
|
s.~DArena();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ set(UTEST_SRCS
|
||||||
|
|
||||||
if (ENABLE_TESTING)
|
if (ENABLE_TESTING)
|
||||||
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
|
xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS})
|
||||||
|
xo_self_dependency(${UTEST_EXE} xo_alloc2)
|
||||||
xo_headeronly_dependency(${UTEST_EXE} xo_facet)
|
xo_headeronly_dependency(${UTEST_EXE} xo_facet)
|
||||||
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)
|
xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,19 @@
|
||||||
#include "xo/alloc2/AAllocator.hpp"
|
#include "xo/alloc2/AAllocator.hpp"
|
||||||
#include "xo/alloc2/DArena.hpp"
|
#include "xo/alloc2/DArena.hpp"
|
||||||
#include "xo/alloc2/IAllocator_DArena.hpp"
|
#include "xo/alloc2/IAllocator_DArena.hpp"
|
||||||
|
#include "xo/alloc2/RAllocator.hpp"
|
||||||
#include "xo/alloc2/padding.hpp"
|
#include "xo/alloc2/padding.hpp"
|
||||||
|
#include "xo/facet/obj.hpp"
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
namespace xo {
|
namespace xo {
|
||||||
|
using xo::mm::AAllocator;
|
||||||
using xo::mm::IAllocator_Xfer;
|
using xo::mm::IAllocator_Xfer;
|
||||||
using xo::mm::DArena;
|
using xo::mm::DArena;
|
||||||
|
using xo::mm::ArenaConfig;
|
||||||
|
using xo::facet::obj;
|
||||||
|
using std::byte;
|
||||||
|
using std::size_t;
|
||||||
|
|
||||||
namespace ut {
|
namespace ut {
|
||||||
TEST_CASE("IAllocator_Xfer_DArena", "[alloc2]")
|
TEST_CASE("IAllocator_Xfer_DArena", "[alloc2]")
|
||||||
|
|
@ -20,6 +27,65 @@ namespace xo {
|
||||||
|
|
||||||
REQUIRE(IAllocator_Xfer<DArena>::_valid);
|
REQUIRE(IAllocator_Xfer<DArena>::_valid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("DArena", "[alloc2][DArena]")
|
||||||
|
{
|
||||||
|
ArenaConfig cfg { .name_ = "testarena",
|
||||||
|
.size_ = 1 };
|
||||||
|
DArena arena = DArena::map(cfg);
|
||||||
|
|
||||||
|
REQUIRE(arena.config_.name_ == cfg.name_);
|
||||||
|
REQUIRE(arena.lo_ != nullptr);
|
||||||
|
REQUIRE(arena.free_ == arena.lo_);
|
||||||
|
REQUIRE(arena.limit_ == arena.lo_);
|
||||||
|
REQUIRE(arena.hi_ != nullptr);
|
||||||
|
REQUIRE(arena.hi_ > arena.lo_);
|
||||||
|
REQUIRE(((size_t)arena.hi_ - (size_t)arena.lo_) % cfg.hugepage_z_ == 0);
|
||||||
|
REQUIRE(arena.lo_ + cfg.size_ <= arena.hi_);
|
||||||
|
|
||||||
|
/* verify arena.lo_ is aligned on a hugepage boundary */
|
||||||
|
REQUIRE(((size_t)(arena.lo_) & (cfg.hugepage_z_ - 1)) == 0);
|
||||||
|
|
||||||
|
/* verify arena.hi_ is aligned on a hugepage boundary */
|
||||||
|
REQUIRE(((size_t)(arena.hi_) & (cfg.hugepage_z_ - 1)) == 0);
|
||||||
|
|
||||||
|
byte * lo = arena.lo_;
|
||||||
|
byte * free = arena.free_;
|
||||||
|
byte * limit = arena.limit_;
|
||||||
|
byte * hi = arena.hi_;
|
||||||
|
size_t committed_z = arena.committed_z_;
|
||||||
|
|
||||||
|
DArena arena2 = std::move(arena);
|
||||||
|
|
||||||
|
REQUIRE(arena.lo_ == nullptr);
|
||||||
|
REQUIRE(arena.free_ == nullptr);
|
||||||
|
REQUIRE(arena.limit_ == nullptr);
|
||||||
|
REQUIRE(arena.hi_ == nullptr);
|
||||||
|
REQUIRE(arena.committed_z_ == 0);
|
||||||
|
|
||||||
|
REQUIRE(arena.lo_ == nullptr);
|
||||||
|
REQUIRE(arena2.lo_ == lo);
|
||||||
|
REQUIRE(arena2.free_ == free);
|
||||||
|
REQUIRE(arena2.limit_ == limit);
|
||||||
|
REQUIRE(arena2.hi_ == hi);
|
||||||
|
REQUIRE(arena2.committed_z_ == committed_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("allocator-any-1", "[alloc2][AAllocator]")
|
||||||
|
{
|
||||||
|
#ifdef NOPE
|
||||||
|
ArenaConfig cfg { .name_ = "testarena",
|
||||||
|
.size_ = 1 };
|
||||||
|
DArena arena = DArena::map(cfg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* empty allocator */
|
||||||
|
obj<AAllocator> alloc1;
|
||||||
|
|
||||||
|
REQUIRE(!alloc1);
|
||||||
|
REQUIRE(alloc1.iface() != nullptr);
|
||||||
|
REQUIRE(alloc1.data() == nullptr);
|
||||||
|
}
|
||||||
} /*namespace ut*/
|
} /*namespace ut*/
|
||||||
} /*namespace xo*/
|
} /*namespace xo*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,57 +19,39 @@ Abstraction tower for *xo-facet* components.
|
||||||
:--scale: 0.85
|
:--scale: 0.85
|
||||||
|
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| obj(A,D) |
|
| obj(A,D) |
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| RRouter(A,D) |
|
| RRouter(A,D) |
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| OObject(A,D) |
|
| OObject(A,D) |
|
||||||
+--------------------------------+
|
+--------------------------------+
|
||||||
| FacetImplmentationType(A,D) |
|
| FacetImplType(A,D) |
|
||||||
+----------------+---------------+
|
+----------------+---------------+
|
||||||
| facet [A] | data [D] |
|
| facet [A] | data [D] |
|
||||||
+----------------+---------------+
|
+----------------+---------------+
|
||||||
|
|
||||||
|
|
||||||
Decorated with sample method calls, to reveal type recovery
|
|
||||||
|
|
||||||
.. ditaa::
|
|
||||||
:--scale: 0.85
|
|
||||||
|
|
||||||
+--------------------------------+
|
|
||||||
| obj(A,D) | x.foo()
|
|
||||||
+--------------------------------+
|
|
||||||
| RRouter(A,D) | x.foo()
|
|
||||||
+--------------------------------+
|
|
||||||
| OObject(A,D) | x.iface_.foo(x.data_)
|
|
||||||
+--------------------------------+
|
|
||||||
| FacetImplmentationType(A,D) | x.foo(void*data)
|
|
||||||
+----------------+---------------+
|
|
||||||
| facet A | data D | virtual x.foo(void* data)
|
|
||||||
+----------------+---------------+
|
|
||||||
|
|
||||||
.. list-table:: Descriptions
|
.. list-table:: Descriptions
|
||||||
:header-rows: 1
|
:header-rows: 1
|
||||||
:widths: 30 30 60
|
:widths: 18 30 50
|
||||||
|
|
||||||
* - Component
|
* - Component
|
||||||
- Use
|
- Use
|
||||||
- Description
|
- Description
|
||||||
* - obj<A,D>
|
* - ``obj<A,D>``
|
||||||
- x.foo()
|
- ``x.foo()``
|
||||||
- convenience wrapper with interface A, with state D*
|
- convenience wrapper with interface A, with state D*
|
||||||
* - RRouter<A,D>
|
* - ``RRouter<A,D>``
|
||||||
- x.foo()
|
- ``x.foo()``
|
||||||
- auto injects data pointer
|
- auto injects data pointer
|
||||||
* - OObject<A,D>
|
* - ``OObject<A,D>``
|
||||||
- x.iface()->foo(x.data(), ..)
|
- ``x.iface()->foo(x.data(), ..)``
|
||||||
- fat object pointer. combine i/face + data pointer.
|
- fat object pointer. combine i/face + data pointer.
|
||||||
* - FacetImplementationType<A,D>
|
* - ``FacetImplType<A,D>``
|
||||||
- x.foo(void* data, ..)
|
- ``x.foo(void* data, ..)``
|
||||||
- implement facet for a particular state datatype;
|
- implement facet for a particular state datatype;
|
||||||
explicit type-erased state
|
explicit type-erased state
|
||||||
* - facet
|
* - facet
|
||||||
- x.foo(void* data, ..)=0
|
- ``x.foo(void* data, ..)=0``
|
||||||
- fully abstract interface; explicit type-erased state
|
- fully abstract interface; explicit type-erased state
|
||||||
|
|
||||||
.. uml::
|
.. uml::
|
||||||
|
|
|
||||||
|
|
@ -4,27 +4,29 @@
|
||||||
set(SELF_EXE utest.tree)
|
set(SELF_EXE utest.tree)
|
||||||
set(SELF_SOURCE_FILES tree_utest_main.cpp redblacktree.cpp bplustree.cpp RedBlackTree-gc.test.cpp)
|
set(SELF_SOURCE_FILES tree_utest_main.cpp redblacktree.cpp bplustree.cpp RedBlackTree-gc.test.cpp)
|
||||||
|
|
||||||
add_executable(${SELF_EXE} ${SELF_SOURCE_FILES})
|
if (ENABLE_TESTING)
|
||||||
xo_include_options2(${SELF_EXE})
|
add_executable(${SELF_EXE} ${SELF_SOURCE_FILES})
|
||||||
|
xo_include_options2(${SELF_EXE})
|
||||||
|
|
||||||
add_test(NAME ${SELF_EXE} COMMAND ${SELF_EXE})
|
add_test(NAME ${SELF_EXE} COMMAND ${SELF_EXE})
|
||||||
# need coverage on unit test b/c header-only libraries
|
# need coverage on unit test b/c header-only libraries
|
||||||
#target_code_coverage(${SELF_EXE} EXCLUDE */nix/store* utest/*)
|
#target_code_coverage(${SELF_EXE} EXCLUDE */nix/store* utest/*)
|
||||||
#target_code_coverage(${SELF_EXE} AUTO ALL)
|
#target_code_coverage(${SELF_EXE} AUTO ALL)
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# internal dependencies: refcnt, ...
|
# internal dependencies: refcnt, ...
|
||||||
|
|
||||||
xo_self_dependency(${SELF_EXE} xo_ordinaltree)
|
xo_self_dependency(${SELF_EXE} xo_ordinaltree)
|
||||||
xo_dependency(${SELF_EXE} xo_object)
|
xo_dependency(${SELF_EXE} xo_object)
|
||||||
xo_dependency(${SELF_EXE} xo_alloc)
|
xo_dependency(${SELF_EXE} xo_alloc)
|
||||||
xo_dependency(${SELF_EXE} refcnt)
|
xo_dependency(${SELF_EXE} refcnt)
|
||||||
xo_dependency(${SELF_EXE} indentlog)
|
xo_dependency(${SELF_EXE} indentlog)
|
||||||
xo_dependency(${SELF_EXE} randomgen)
|
xo_dependency(${SELF_EXE} randomgen)
|
||||||
|
|
||||||
# ----------------------------------------------------------------
|
# ----------------------------------------------------------------
|
||||||
# 3rd part dependency: catch2:
|
# 3rd part dependency: catch2:
|
||||||
|
|
||||||
xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2)
|
xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2)
|
||||||
|
endif()
|
||||||
|
|
||||||
# end ordinaltree/utest/CMakeLists.txt
|
# end ordinaltree/utest/CMakeLists.txt
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue