Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 42 additions & 0 deletions .github/workflows/benchmark-baselines.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Benchmark baselines

on:
push:
tags: ['v*']
workflow_dispatch:

permissions:
contents: read

jobs:
benchmark:
name: Benchmark / ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, macos-14, windows-2022]
runs-on: ${{ matrix.os }}
env:
VMODULES: ${{ github.workspace }}/modules
defaults:
run:
shell: bash
working-directory: modules/antono2/memory
steps:
- uses: actions/checkout@v7
with:
path: modules/antono2/memory
- uses: prantlf/setup-v-action@v4
with:
version: 0.5.2
- name: Record optimized benchmark baseline
run: |
v -prod run benchmarks 250000 \
| tee benchmark-results-${{ runner.os }}.txt
- name: Upload benchmark baseline
uses: actions/upload-artifact@v4
with:
name: memory-${{ github.ref_name }}-${{ runner.os }}
path: modules/antono2/memory/benchmark-results-${{ runner.os }}.txt
if-no-files-found: error
retention-days: 90
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@ jobs:
run: v fmt -verify .
- name: Vet
run: v vet .
- name: Validate public API documentation
run: v doc -f none -m .
- name: Test
run: v test .
- name: Run examples
run: ./scripts/run_examples.sh
- name: Run deterministic benchmark smoke test
run: ./scripts/run_benchmarks.sh --quick
run: ./scripts/run_benchmarks.sh --quick | tee benchmark-smoke.txt
- name: Upload benchmark smoke results
uses: actions/upload-artifact@v4
with:
name: memory-benchmark-smoke-${{ github.run_id }}
path: modules/antono2/memory/benchmark-smoke.txt
if-no-files-found: error
retention-days: 14

platform-tests:
name: Test / ${{ matrix.os }}
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.

## Unreleased

## 1.4.0 - 2026-09-12

- Add independent block and FIFO reference models for buddy and ring allocation,
including 20,000-operation deterministic comparison traces.
- Prove synchronized range and buddy allocators match their plain counterparts
across deterministic success, failure, offset, and statistics traces.
- Cover zero-capacity state, failed-allocation atomicity, and allocation-ID
wraparound without reusing zero or a live identifier.
- Expand benchmark suite v3 with synchronized-wrapper comparisons and 1, 2, 4,
and 8-worker contention workloads.
- Store benchmark smoke results as CI artifacts and record optimized Linux,
macOS, and Windows baseline artifacts for release tags.
- Document the stable 1.x API surface, ownership-token boundaries, supported V
compiler, algorithmic complexity, and synchronization guarantees.
- Validate root-module API documentation generation in CI.

## 1.3.1 - 2026-09-12

- Remove the short-lived `antono2.memory.concurrent` compatibility submodule
Expand Down
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ and the `antono2/memory` installed directory.
Projects that still import `generic_pool` should pin the 0.2.0 release until
they are ready to update their imports.

See [API stability and support](STABILITY.md) for the 1.x compatibility,
threading, ownership-token, and compiler-support guarantees.

## Choosing an allocator

| Type | Use it when | Release order | Main tradeoff |
Expand All @@ -64,6 +67,22 @@ only after its allocations are no longer live. The lightweight core types are
not internally synchronized; use the explicitly named `Synchronized` variants
when allocator metadata is shared between threads.

## Complexity and synchronization

| Type | Allocate/acquire | Release/reset | Query notes |
| --- | --- | --- | --- |
| `SlotPool[T]` | O(1) | O(1) release; O(capacity) clear | O(1) lookup; external synchronization required |
| `ObjectPool[T]` | O(1) plus factory | O(1) plus reset callback; O(capacity) release-all | External synchronization required |
| `RangeAllocator` | O(free ranges) | O(free ranges) | Statistics scan free ranges; external synchronization required |
| `LinearAllocator` | O(1) | O(1) whole-arena reset | O(1) queries; external synchronization required |
| `RingAllocator` | O(1) | Amortized O(1) FIFO release | `contains` scans live records; external synchronization required |
| `BuddyAllocator` | O(log(capacity/minimum block)) | O(log(capacity/minimum block)) | Largest-block statistics may scan the buddy tree; external synchronization required |
| `SynchronizedRangeAllocator` | Range cost plus write lock | Range cost plus write lock | Read-only queries use a shared lock |
| `SynchronizedBuddyAllocator` | Buddy cost plus write lock | Buddy cost plus write lock | Read-only queries use a shared lock |

`f` denotes the current number of free ranges. Callback execution time and
thread scheduling are outside these bounds.

## Slot pool

Create a pool once, insert values until it reaches its fixed capacity, and use
Expand Down Expand Up @@ -350,12 +369,17 @@ Run the deterministic churn workloads with production compiler optimizations:

Pass an operation count to shorten or extend a run, or use `--quick` for the CI
smoke workload. The harness covers slot and object reuse, fragmented first-fit
ranges, power-of-two buddy allocation, linear allocate/reset cycles, and FIFO
ring streaming. Range and buddy allocation replay the same bounded request and
release trace, verified by a trace hash, and report successful allocations,
failures, peak occupancy, and fragmentation alongside timing. The harness
deliberately enforces no universal performance threshold; compare results only
on the same machine, toolchain, and trace version.
ranges, power-of-two buddy allocation, linear allocate/reset cycles, FIFO ring
streaming, synchronized-wrapper overhead, and synchronized range and buddy
contention with 1, 2, 4, and 8 workers. Plain and synchronized allocators replay
the same bounded request and release trace, verified by trace hashes and result
checksums.

CI stores the quick Linux result as a downloadable text artifact. Each release
tag also records optimized Linux, macOS, and Windows baselines. These results
are diagnostic: the project enforces correctness and trace equivalence, not a
universal timing threshold. Compare timings only on equivalent machines,
toolchains, operation counts, and trace versions.

## Verify

Expand All @@ -380,8 +404,9 @@ collector.

## Roadmap

- benchmark baselines across representative machines and V compiler versions
- specialized allocation policies driven by benchmark results
- realistic allocation traces collected from downstream integrations
- specialized allocation policies only when those traces show a measurable need
- safe lease- or closure-based synchronized pool access if concrete use cases require it
- additional integrations that keep platform APIs outside the core module

## License
Expand Down
53 changes: 53 additions & 0 deletions STABILITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# API stability and support

Beginning with v1.4.0, `antono2.memory` follows semantic versioning for its
public root-module API.

## Stable surface

The following are compatibility commitments within the 1.x release series:

- public type, function, and method names in `antono2.memory`
- public allocation and statistics fields
- documented allocation order, release order, validation, and reset behavior
- acceptance of every configuration and request described as valid
- rejection of stale, forged, foreign, or out-of-order records where documented

New types, methods, and fields may be added in a minor release. Removing or
incompatibly changing stable behavior requires a new major release. When
practical, an API scheduled for removal will first be deprecated for at least
one minor release.

## Not a serialized or binary interface

Handles and allocation records are process-local capability values. Their
private ownership and generation fields must not be forged, persisted, sent to
another process, or reconstructed from public offsets and sizes. Struct memory
layout, private fields, internal data structures, allocation identifiers, and
exact error wording are implementation details.

Use error propagation for allocation failure; do not branch on the complete
error string. Public statistics are diagnostic snapshots and do not reserve or
guarantee a later allocation.

## Threading

`SlotPool`, `ObjectPool`, `RangeAllocator`, `LinearAllocator`, `RingAllocator`,
and `BuddyAllocator` require external synchronization when shared between
threads. `SynchronizedRangeAllocator` and `SynchronizedBuddyAllocator` protect
their allocation metadata with reader/writer mutexes.

Synchronization does not protect the backing host memory, mapped file, shared
memory, Vulkan memory, or other resource represented by an offset. Applications
must coordinate use, release, reset, and destruction of that resource.

Pool accessors return pointers whose use may outlive a method call. For that
reason, the package does not claim that wrapping individual pool methods in a
mutex would make pointer access thread-safe.

## Supported compiler

The minimum tested compiler for v1.4.x is V 0.5.2. Every release is tested on
Linux, macOS, and Windows with that compiler. V itself is evolving, so support
for later compiler releases is verified and adjusted in subsequent package
releases rather than assumed.
Loading
Loading