Separate out building and porting docs. (#260)
Fix omissions in the porting doc (`page_size` and C++20 concepts).
This commit is contained in:
218
README.md
218
README.md
@@ -36,222 +36,10 @@ Since writing the paper, the performance of snmalloc has improved considerably.
|
||||
|
||||
[](https://dev.azure.com/snmalloc/snmalloc/_build/latest?definitionId=1?branchName=master)
|
||||
|
||||
# Building on Windows
|
||||
|
||||
The Windows build currently depends on Visual Studio 2017.
|
||||
To build with Visual Studio:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 15 2017 Win64" ..
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config RelWithDebInfo
|
||||
```
|
||||
|
||||
You can also omit the last three steps and build from the IDE.
|
||||
Visual Studio builds use a separate directory to keep the binaries for each
|
||||
build configuration.
|
||||
|
||||
Alternatively, you can follow the steps in the next section to build with Ninja
|
||||
using the Visual Studio compiler.
|
||||
|
||||
# Building on UNIX-like platforms
|
||||
|
||||
snmalloc has platform abstraction layers for XNU (macOS, iOS, and so on),
|
||||
FreeBSD, NetBSD, OpenBSD, and Linux and is expected to work out of the box on
|
||||
these systems.
|
||||
Please open issues if it does not.
|
||||
Note that NetBSD, by default, ships with a toolchain that emits calls to
|
||||
`libatomic` but does not ship `libatomic`.
|
||||
To use snmalloc on NetBSD, you must either acquire a `libatomic` implementation
|
||||
(for example, from the GCC or LLVM project) or compile with clang.
|
||||
|
||||
snmalloc has very few dependencies, CMake, Ninja, Clang 6.0 or later and a C++17
|
||||
standard library.
|
||||
Building with GCC is currently not recommended because GCC emits calls to
|
||||
libatomic for 128-bit atomic operations.
|
||||
|
||||
To build a debug configuration:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Debug
|
||||
ninja
|
||||
```
|
||||
To build a release configuration:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release
|
||||
ninja
|
||||
```
|
||||
To build with optimizations on, but with debug information:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
ninja
|
||||
```
|
||||
|
||||
On ELF platforms, the build produces a binary `libsnmallocshim.so`.
|
||||
This file can be
|
||||
`LD_PRELOAD`ed to use the allocator in place of the system allocator, for
|
||||
example, you can run the build script using the snmalloc as the allocator for
|
||||
your toolchain:
|
||||
|
||||
```
|
||||
LD_PRELOAD=/usr/local/lib/libsnmallocshim.so ninja
|
||||
```
|
||||
|
||||
## Cross Compile for Android
|
||||
Android support is out-of-the-box.
|
||||
|
||||
To cross-compile the library for arm android, you can simply invoke CMake with the toolchain file and the andorid api settings (for more infomation, check this [document](https://developer.android.com/ndk/guides/cmake)).
|
||||
|
||||
For example, you can cross-compile for `arm64-v8a` with the following command:
|
||||
```
|
||||
cmake /path/to/snmalloc -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a
|
||||
```
|
||||
|
||||
# CMake Feature Flags
|
||||
|
||||
These can be added to your cmake command line.
|
||||
|
||||
```
|
||||
-DUSE_SNMALLOC_STATS=ON // Track allocation stats
|
||||
-DUSE_MEASURE=ON // Measure performance with histograms
|
||||
```
|
||||
|
||||
# Using snmalloc as header-only library
|
||||
|
||||
In this section we show how to compile snmalloc into your project such that it replaces the standard allocator functions such as free and malloc. The following instructions were tested with CMake and Clang running on Ubuntu 18.04.
|
||||
|
||||
Add these lines to your CMake file.
|
||||
|
||||
```cmake
|
||||
set(SNMALLOC_ONLY_HEADER_LIBRARY ON)
|
||||
add_subdirectory(snmalloc EXCLUDE_FROM_ALL)
|
||||
```
|
||||
|
||||
In addition make sure your executable is compiled to support 128 bit atomic operations. This may require you to add the following to your CMake file.
|
||||
|
||||
```cmake
|
||||
target_link_libraries([lib_name] PRIVATE snmalloc_lib)
|
||||
```
|
||||
|
||||
You will also need to compile the relevant parts of snmalloc itself. Create a new file with the following contents and compile it with the rest of your application.
|
||||
|
||||
```c++
|
||||
#define NO_BOOTSTRAP_ALLOCATOR
|
||||
|
||||
#include "snmalloc/src/override/malloc.cc"
|
||||
#include "snmalloc/src/override/new.cc"
|
||||
```
|
||||
|
||||
# Porting snmalloc to a new platform
|
||||
|
||||
All of the platform-specific logic in snmalloc is isolated in the [Platform
|
||||
Abstraction Layer (PAL)](src/pal).
|
||||
To add support for a new platform, you will need to implement a new PAL for
|
||||
your system.
|
||||
|
||||
The PAL must implement the following methods:
|
||||
|
||||
```c++
|
||||
[[noreturn]] static void error(const char* const str) noexcept;
|
||||
```
|
||||
Report a fatal error and exit.
|
||||
|
||||
```c++
|
||||
static void notify_not_using(void* p, size_t size) noexcept;
|
||||
```
|
||||
Notify the system that the range of memory from `p` to `p` + `size` is no
|
||||
longer in use, allowing the underlying physical pages to recycled for other
|
||||
purposes.
|
||||
|
||||
```c++
|
||||
template<ZeroMem zero_mem>
|
||||
static void notify_using(void* p, size_t size) noexcept;
|
||||
```
|
||||
Notify the system that the range of memory from `p` to `p` + `size` is now in use.
|
||||
On systems that lazily provide physical memory to virtual mappings, this
|
||||
function may not be required to do anything.
|
||||
If the template parameter is set to `YesZero` then this function is also
|
||||
responsible for ensuring that the newly requested memory is full of zeros.
|
||||
|
||||
```c++
|
||||
template<bool page_aligned = false>
|
||||
static void zero(void* p, size_t size) noexcept;
|
||||
```
|
||||
Zero the range of memory from `p` to `p` + `size`.
|
||||
This may be a simple `memset` call, but the `page_aligned` template parameter
|
||||
allows for more efficient implementations when entire pages are being zeroed.
|
||||
This function is typically called with very large ranges, so it may be more
|
||||
efficient to request that the operating system provides background-zeroed
|
||||
pages, rather than zeroing them synchronously in this call
|
||||
|
||||
```c++
|
||||
template<bool committed>
|
||||
static void* reserve_aligned(size_t size) noexcept;
|
||||
static std::pair<void*, size_t> reserve_at_least(size_t size) noexcept;
|
||||
```
|
||||
Only one of these needs to be implemented, depending on whether the underlying
|
||||
system can provide strongly aligned memory regions.
|
||||
If the system guarantees only page alignment, implement the second. The Pal is
|
||||
free to overallocate based on the platforms desire and snmalloc
|
||||
will find suitably aligned blocks inside the region. `reserve_at_least` should
|
||||
not commit memory as snmalloc will commit the range of memory it requires of what
|
||||
is returned.
|
||||
|
||||
If the system provides strong alignment, implement the first to return memory
|
||||
at the desired alignment. If providing the first, then the `Pal` should also
|
||||
specify the minimum size block it can provide:
|
||||
```
|
||||
static constexpr size_t minimum_alloc_size = ...;
|
||||
```
|
||||
|
||||
|
||||
Finally, you need to define a field to indicate the features that your PAL supports:
|
||||
```c++
|
||||
static constexpr uint64_t pal_features = ...;
|
||||
```
|
||||
|
||||
These features are defined in the [`PalFeatures`](src/pal/pal_consts.h) enumeration.
|
||||
|
||||
There are several partial PALs that can be used when implementing POSIX-like systems:
|
||||
|
||||
- `PALPOSIX` defines a PAL for a POSIX platform using no non-standard features.
|
||||
- `PALBSD` defines a PAL for the common set of BSD extensions to POSIX.
|
||||
- `PALBSD_Aligned` extends `PALBSD` to provide support for aligned allocation
|
||||
from `mmap`, as supported by NetBSD and FreeBSD.
|
||||
|
||||
Each of these template classes takes the PAL that inherits from it as a
|
||||
template parameter.
|
||||
A purely POSIX-compliant platform could have a PAL as simple as this:
|
||||
|
||||
```c++
|
||||
class PALMyOS : public PALPOSIX<PALMyOS> {}
|
||||
```
|
||||
|
||||
Typically, a PAL will implement at least one of the functions outlined above in
|
||||
a more-efficient platform-specific way, but this is not required.
|
||||
Non-POSIX systems will need to implement the entire PAL interface.
|
||||
The [Windows](src/pal/pal_windows.h), and
|
||||
[OpenEnclave](src/pal/pal_open_enclave.h) and
|
||||
[FreeBSD kernel](src/pal/pal_freebsd_kernel.h) implementations give examples of
|
||||
non-POSIX environments that snmalloc supports.
|
||||
|
||||
The POSIX PAL uses `mmap` to map memory.
|
||||
Some POSIX or POSIX-like systems require minor tweaks to this behaviour.
|
||||
Rather than requiring these to copy and paste the code, a PAL that inherits from the POSIX PAL can define one or both of these (`static constexpr`) fields to customise the `mmap` behaviour.
|
||||
|
||||
- `default_mmap_flags` allows a PAL to provide additional `MAP_*`
|
||||
flags to all `mmap` calls.
|
||||
- `anonymous_memory_fd` allows the PAL to override the default file
|
||||
descriptor used for memory mappings.
|
||||
# Further documentation
|
||||
|
||||
- [Instructions for building snmalloc](docs/BUILDING.md)
|
||||
- [Instructions for porting snmalloc](docs/PORTING.md)
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
118
docs/BUILDING.md
Normal file
118
docs/BUILDING.md
Normal file
@@ -0,0 +1,118 @@
|
||||
Building snmalloc
|
||||
=================
|
||||
|
||||
snmalloc uses a CMake build system and can be built on many platforms.
|
||||
|
||||
# Building on Windows
|
||||
|
||||
The Windows build currently depends on Visual Studio 2017.
|
||||
To build with Visual Studio:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "Visual Studio 15 2017 Win64" ..
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config RelWithDebInfo
|
||||
```
|
||||
|
||||
You can also omit the last three steps and build from the IDE.
|
||||
Visual Studio builds use a separate directory to keep the binaries for each
|
||||
build configuration.
|
||||
|
||||
Alternatively, you can follow the steps in the next section to build with Ninja
|
||||
using the Visual Studio compiler.
|
||||
|
||||
# Building on UNIX-like platforms
|
||||
|
||||
snmalloc has platform abstraction layers for XNU (macOS, iOS, and so on),
|
||||
FreeBSD, NetBSD, OpenBSD, and Linux and is expected to work out of the box on
|
||||
these systems.
|
||||
Please open issues if it does not.
|
||||
Note that NetBSD, by default, ships with a toolchain that emits calls to
|
||||
`libatomic` but does not ship `libatomic`.
|
||||
To use snmalloc on NetBSD, you must either acquire a `libatomic` implementation
|
||||
(for example, from the GCC or LLVM project) or compile with clang.
|
||||
|
||||
snmalloc has very few dependencies: CMake, Ninja, Clang 6.0 or later and a C++17
|
||||
standard library.
|
||||
Building with GCC is currently not recommended because GCC emits calls to
|
||||
libatomic for 128-bit atomic operations.
|
||||
|
||||
To build a debug configuration:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Debug
|
||||
ninja
|
||||
```
|
||||
To build a release configuration:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=Release
|
||||
ninja
|
||||
```
|
||||
To build with optimizations on, but with debug information:
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G Ninja .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
ninja
|
||||
```
|
||||
|
||||
On ELF platforms, the build produces a binary `libsnmallocshim.so`.
|
||||
This file can be
|
||||
`LD_PRELOAD`ed to use the allocator in place of the system allocator, for
|
||||
example, you can run the build script using the snmalloc as the allocator for
|
||||
your toolchain:
|
||||
|
||||
```
|
||||
LD_PRELOAD=/usr/local/lib/libsnmallocshim.so ninja
|
||||
```
|
||||
|
||||
## Cross Compile for Android
|
||||
Android is supported out-of-the-box.
|
||||
|
||||
To cross-compile the library for arm android, you can simply invoke CMake with the toolchain file and the andorid api settings (for more infomation, check this [document](https://developer.android.com/ndk/guides/cmake)).
|
||||
|
||||
For example, you can cross-compile for `arm64-v8a` with the following command:
|
||||
```
|
||||
cmake /path/to/snmalloc -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a
|
||||
```
|
||||
|
||||
# CMake Feature Flags
|
||||
|
||||
These can be added to your cmake command line.
|
||||
|
||||
```
|
||||
-DUSE_SNMALLOC_STATS=ON // Track allocation stats
|
||||
-DUSE_MEASURE=ON // Measure performance with histograms
|
||||
```
|
||||
|
||||
# Using snmalloc as header-only library
|
||||
|
||||
In this section we show how to compile snmalloc into your project such that it replaces the standard allocator functions such as free and malloc. The following instructions were tested with CMake and Clang running on Ubuntu 18.04.
|
||||
|
||||
Add these lines to your CMake file.
|
||||
|
||||
```cmake
|
||||
set(SNMALLOC_ONLY_HEADER_LIBRARY ON)
|
||||
add_subdirectory(snmalloc EXCLUDE_FROM_ALL)
|
||||
```
|
||||
|
||||
In addition make sure your executable is compiled to support 128 bit atomic operations. This may require you to add the following to your CMake file.
|
||||
|
||||
```cmake
|
||||
target_link_libraries([lib_name] PRIVATE snmalloc_lib)
|
||||
```
|
||||
|
||||
You will also need to compile the relevant parts of snmalloc itself. Create a new file with the following contents and compile it with the rest of your application.
|
||||
|
||||
```c++
|
||||
#define NO_BOOTSTRAP_ALLOCATOR
|
||||
|
||||
#include "snmalloc/src/override/malloc.cc"
|
||||
#include "snmalloc/src/override/new.cc"
|
||||
```
|
||||
124
docs/PORTING.md
Normal file
124
docs/PORTING.md
Normal file
@@ -0,0 +1,124 @@
|
||||
Porting snmalloc to a new platform
|
||||
==================================
|
||||
|
||||
All of the platform-specific logic in snmalloc is isolated in the [Platform
|
||||
Abstraction Layer (PAL)](src/pal).
|
||||
To add support for a new platform, you will need to implement a new PAL for
|
||||
your system.
|
||||
|
||||
After version 0.5.2, the PAL is defined by a [C++20 Concept](../src/pal/pal_concept.h).
|
||||
When compiling with C++20 or later, you should get helpful messages about any fields or methods that your PAL is missing.
|
||||
|
||||
The PAL must implement the following methods:
|
||||
|
||||
```c++
|
||||
[[noreturn]] static void error(const char* const str) noexcept;
|
||||
```
|
||||
Report a fatal error and exit.
|
||||
|
||||
```c++
|
||||
static void notify_not_using(void* p, size_t size) noexcept;
|
||||
```
|
||||
Notify the system that the range of memory from `p` to `p` + `size` is no
|
||||
longer in use, allowing the underlying physical pages to recycled for other
|
||||
purposes.
|
||||
|
||||
```c++
|
||||
template<ZeroMem zero_mem>
|
||||
static void notify_using(void* p, size_t size) noexcept;
|
||||
```
|
||||
Notify the system that the range of memory from `p` to `p` + `size` is now in use.
|
||||
On systems that lazily provide physical memory to virtual mappings, this
|
||||
function may not be required to do anything.
|
||||
If the template parameter is set to `YesZero` then this function is also
|
||||
responsible for ensuring that the newly requested memory is full of zeros.
|
||||
|
||||
```c++
|
||||
template<bool page_aligned = false>
|
||||
static void zero(void* p, size_t size) noexcept;
|
||||
```
|
||||
Zero the range of memory from `p` to `p` + `size`.
|
||||
This may be a simple `memset` call, but the `page_aligned` template parameter
|
||||
allows for more efficient implementations when entire pages are being zeroed.
|
||||
This function is typically called with very large ranges, so it may be more
|
||||
efficient to request that the operating system provides background-zeroed
|
||||
pages, rather than zeroing them synchronously in this call
|
||||
|
||||
```c++
|
||||
template<bool committed>
|
||||
static void* reserve_aligned(size_t size) noexcept;
|
||||
static std::pair<void*, size_t> reserve_at_least(size_t size) noexcept;
|
||||
```
|
||||
Only one of these needs to be implemented, depending on whether the underlying
|
||||
system can provide strongly aligned memory regions.
|
||||
If the system guarantees only page alignment, implement the second. The Pal is
|
||||
free to overallocate based on the platform's desire and snmalloc
|
||||
will find suitably aligned blocks inside the region. `reserve_at_least` should
|
||||
not commit memory as snmalloc will commit the range of memory it requires of what
|
||||
is returned.
|
||||
|
||||
If the system provides strong alignment, implement the first to return memory
|
||||
at the desired alignment. If providing the first, then the `Pal` should also
|
||||
specify the minimum size block it can provide:
|
||||
```
|
||||
static constexpr size_t minimum_alloc_size = ...;
|
||||
```
|
||||
|
||||
The PAL is also responsible for advertising the page size:
|
||||
|
||||
```c++
|
||||
static constexpr size_t page_size = 0x1000;
|
||||
```
|
||||
|
||||
This is the granularity at which the PAL is able to mark memory as in-use or not-in-use.
|
||||
The PAL is free to advertise a size greater than the minimum page size if that would be more efficient.
|
||||
When a slab is deallocated, the PAL will be instructed to mark everything after the first `page_size` bytes as not-in-use and so larger values can lead to more memory overhead.
|
||||
|
||||
The page size for any given system depends on both the underlying architecture and the operating system.
|
||||
The value exposed by the PAL may also depend on the Architecture Abstraction Layer (AAL).
|
||||
For example, the Linux PAL advertises 64 KiB on PowerPC but 4 KiB on every other supported architecture:
|
||||
|
||||
```c++
|
||||
static constexpr size_t page_size =
|
||||
Aal::aal_name == PowerPC ? 0x10000 : 0x1000;
|
||||
```
|
||||
|
||||
Finally, you need to define a field to indicate the features that your PAL supports:
|
||||
```c++
|
||||
static constexpr uint64_t pal_features = ...;
|
||||
```
|
||||
|
||||
These features are defined in the [`PalFeatures`](src/pal/pal_consts.h) enumeration.
|
||||
|
||||
There are several partial PALs that can be used when implementing POSIX-like systems:
|
||||
|
||||
- `PALPOSIX` defines a PAL for a POSIX platform using no non-standard features.
|
||||
- `PALBSD` defines a PAL for the common set of BSD extensions to POSIX.
|
||||
- `PALBSD_Aligned` extends `PALBSD` to provide support for aligned allocation
|
||||
from `mmap`, as supported by NetBSD and FreeBSD.
|
||||
|
||||
Each of these template classes takes the PAL that inherits from it as a
|
||||
template parameter.
|
||||
A purely POSIX-compliant platform could have a PAL as simple as this:
|
||||
|
||||
```c++
|
||||
class PALMyOS : public PALPOSIX<PALMyOS> {}
|
||||
```
|
||||
|
||||
Typically, a PAL will implement at least one of the functions outlined above in
|
||||
a more-efficient platform-specific way, but this is not required.
|
||||
Non-POSIX systems will need to implement the entire PAL interface.
|
||||
The [Windows](src/pal/pal_windows.h), and
|
||||
[OpenEnclave](src/pal/pal_open_enclave.h) and
|
||||
[FreeBSD kernel](src/pal/pal_freebsd_kernel.h) implementations give examples of
|
||||
non-POSIX environments that snmalloc supports.
|
||||
|
||||
The POSIX PAL uses `mmap` to map memory.
|
||||
Some POSIX or POSIX-like systems require minor tweaks to this behaviour.
|
||||
Rather than requiring these to copy and paste the code, a PAL that inherits from the POSIX PAL can define one or both of these (`static constexpr`) fields to customise the `mmap` behaviour.
|
||||
|
||||
- `default_mmap_flags` allows a PAL to provide additional `MAP_*`
|
||||
flags to all `mmap` calls.
|
||||
- `anonymous_memory_fd` allows the PAL to override the default file
|
||||
descriptor used for memory mappings.
|
||||
|
||||
Reference in New Issue
Block a user