Fast, concurrent, arena-based allocator with drop support

Overview

blink-alloc

crates docs actions MIT/Apache loc

Blink-alloc is extremely fast allocator based on the common idea of allocating linearly zipping a cursor through memory chunk and reset everything at once by setting cursor back to start.

With Rust's borrow checker this idea can be implemented safely, preventing resets to occur while allocated memory is in use.

Jump to examples

Design

The blink-allocator acts as an adaptor to some lower-level allocator. Grabs chunks of memory from underlying allocator and serves allocations from them. When chunk is exhausted blink-allocator requests new larger chunk of memory from lower-level allocator.

On reset all but last chunks are returned back to underlying allocator. The goal is to allocate a single chunk large enough to serve all allocations between resets, so that lower-level allocator is not touched after initial warm-up phase. Making allocations and resets almost free.

The way blink-allocators are implemented offers cheap allocation shrinks when new layout fits into currently allocated memory block. Which is certainly the case for things like Vec::shrink_to and Vec::shrink_to_fit. When done on the tip of allocation it also frees the memory for reuse.

Additionally fast allocation grows is possible when done on the tip of allocation. Which is easy to control when using thread-local version. This opens a way for blazing fast Vec::push call even at full Vec capacity.

The simple implementation uses unsynchronized interior mutability and thus only works in single-thread scenario. It can be send to another thread but not shared.

Maintaining an instance per thread is one way to tackle this problem. Yet not always possible or desireable.

This crate provides additional implementation for multi-threaded scenario with slight performance penalty. To negate it, a local copy of single-threaded blink-allocator can be created to take memory from shared multi-threaded blink-allocator, allowing reusing memory across threads while keeping blazing fast allocations of single-threaded version. It works best for fork-join type of parallelism since it requires a point where the multi-threaded blink-allocator is not shared to reset it.

For task-based parallelism a cache of blink-allocators can be constructed. Task may borrow single-threaded blink-allocator and return it when its done. This will keep cache full of pre-warmed blink-allocators.

Single-threaded

BlinkAlloc is a single-threaded version of the allocator. It uses unsynchronized interior mutability for fastest performance. BlinkAlloc can be sent to other threads but not shared.

For multi-threading an instance of BlinkAlloc per thread/task can be created. Though it may be not possible or practical in some ways, so consider alternatives below.

Multi-threaded

SyncBlinkAlloc works in multithreaded environment and shares memory from one chunk between threads. Reduces overall memory usage, skips warm-up phase for new threads and tasks. SyncBlinkAlloc can spawn LocalBlinkAlloc instances that work similarly to BlinkAlloc. LocalBlinkAlloc instances fetch memory chunks from shared SyncBlinkAlloc. SyncBlinkAlloc still requires exclusive access to reset. Works best for fork-join style of parallelism, where reset happens after joining all threads.

For task/based parallelism this crate provides BlinkAllocCache type which is a cache of BlinkAlloc instances. Tasks may fetch blink allocator from cache, use it and then return it back to cache. Cache keeps BlinkAlloc instances warmed up.

Allocator API

Allocators implement Allocator interface from alloc crate or a copy of it when feature "nightly" is not enabled. "nightly" requires Rust feature allocator_api and works only on nightly. Once Allocator trait is stable the feature will do nothing and removed in next major release.

Blink without collections

BlinkAlloc and friends implement Allocator from allocator_api unstable feature. It is only available when "nightly" feature is enabled for this crate. Otherwise Allocator is not core::alloc::Allocator but a duplicate defined in the crate. With allocator_api it is possible to use BlinkAlloc and others for allocator type in collection types that support one. Currently Vec, VecDeque, BTreeMap and BTreeSet can use user-provided allocator. Also hashbrown::HashMap and hashbrown::HashSet support it with "nightly" feature.

However on stable it cannot be used right now.

It is still possible to use blink-allocators in safe manner - meet Blink allocator adaptor. Put anything into memory allocated by Blink. Values, iterators, closures to construct a value, slices and strings. It works with everything*. Uses underlying blink-allocator and returns mutable reference to values placed into allocated memory. By default it drops placed values on reset.

* Ask for API extension if doesn't work for your use case.

Examples

Usage of Blink allocator adaptor. Initialize and start putting values there.

use blink_alloc::Blink;

fn main() {
    // `Blink::new` uses `BlinkAlloc<Global>`
    let mut blink = Blink::new();

    // Allocates memory and moves value there.
    // Returns mutable reference to it.
    let x = blink.put(42);
    assert_eq!(*x, 42);
    *x = 11;

    // Copies string slice to the blink-allocated memory.
    let string = blink.copy_str("Hello world");

    // Mutable reference allows string mutation
    string.make_ascii_lowercase();
    assert_eq!(string, "hello world");

    // Consumes iterator and returns all values from it in slice.
    // Works fine on problematic iterators with terrible size hint.
    let slice = blink.emplace().from_iter((0..10).filter(|x| x % 3 != 0));
    assert_eq!(&*slice, &[1, 2, 4, 5, 7, 8]);
    blink.reset();
}
#![cfg_attr(feature = "nightly", feature(allocator_api))]
use blink_alloc::BlinkAlloc;

fn main() {
    #[cfg(feature = "nightly")]
    {
        let mut blink = BlinkAlloc::new();
        let mut vec = Vec::new_in(&blink);
        vec.extend((1..10).map(|x| x * 3 - 2));

        drop(vec);
        blink.reset();
    }
}

No-std

This crate supports no_std environment. "alloc" feature is enabled by default and adds dependency on alloc crate.

License

Licensed under either of

at your option.

Contributions

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

You might also like...
Use enum to predicate something, support | and & operator.
Use enum to predicate something, support | and & operator.

Predicate Use enum to predicate something. Just need to implement Predicate Trait with predicate-macros crate, support | and & operator. Don't impleme

RustSBI support on SiFive FU740 board; FU740 is a five-core heterogeneous processor with four SiFive U74 cores, and one SiFive S7 core

RustSBI 在 HiFive Unmatched 主板的支持软件 这个项目的目的是在SiFive HiFive Unmatched主板上支持RustSBI。 RustSBI是一个引导程序环境;主板上电时,RustSBI将会先行启动,而后,它将会找到一个可引导的操作系统,引导启动这个操作系统。 在

Add toast support in your dioxus project

Add toast support in your dioxus project

Tiny Discord ticket support bot that utilizes the OpenAI GPT-3.5-turbo model.
Tiny Discord ticket support bot that utilizes the OpenAI GPT-3.5-turbo model.

BDFD AI Mod Our tiny Discord ticket support bot that utilizes the OpenAI GPT-3.5-turbo model. This project aims to help users by providing a very fast

Meet Rustacean GPT, an experimental project transforming OpenAi's GPT into a helpful, autonomous software engineer to support senior developers and simplify coding life! 🚀🤖🧠
Meet Rustacean GPT, an experimental project transforming OpenAi's GPT into a helpful, autonomous software engineer to support senior developers and simplify coding life! 🚀🤖🧠

Rustacean GPT Welcome, fellow coding enthusiasts! 🚀 🤖 I am excited to introduce you to Rustacean GPT, my humble yet ambitious project that aims to t

MeiliSearch is a powerful, fast, open-source, easy to use and deploy search engine
MeiliSearch is a powerful, fast, open-source, easy to use and deploy search engine

MeiliSearch is a powerful, fast, open-source, easy to use and deploy search engine. Both searching and indexing are highly customizable. Features such as typo-tolerance, filters, and synonyms are provided out-of-the-box. For more information about features go to our documentation.

Extreme fast factor expression & computation library for quantitative trading in Python.

Extreme fast factor expression & computation library for quantitative trading in Python.

Novus - A blazingly fast and efficient package manager for windows.

Novus - A blazingly fast and efficient package manager for windows. Why Novus Swift Unlike any other package manager, Novus uses multithreaded downloads

Beanstalk is a simple, fast work queue.

beanstalkd Simple and fast general purpose work queue.

Comments
  • Use as a Global allocator with malloc/free as a backend

    Use as a Global allocator with malloc/free as a backend

    I think this allocator would be really useful as the default Rust allocator when generating C-compatible libraries.

    It seems feasible to allow for configuring a backend as part of the allocator generic parameter (e.g just providing aligned_alloc and free or a wrapped GlobalAlloc implementation to line-up with new_in). Alternatively, just defaulting to using System as the backend.

    What do you think?

    opened by VariantXYZ 0
Owner
Zakarum
Zakarum
A (mostly) drop-in replacement for Rust's Result that provides backtrace support

Errant A (mostly) drop-in replacement for Rust's Result that provides backtrace support. Please note that Errant is still very early in development an

Joshua Barretto 17 Dec 26, 2022
global allocator that provides hooks for tracking allocation events

tracking-allocator A GlobalAlloc-compatible allocator implementation that provides the ability to track allocation events. examples As allocators are

Toby Lawrence 39 Dec 22, 2022
🌋 A very lightweight wrapper around the Vulkan Memory Allocator 🦀

?? vk-mem-alloc-rs A very lightweight wrapper around the Vulkan Memory Allocator ?? [dependencies] vk-mem-alloc = "0.1.1" Simple Vulkan Memory Allocat

Project KML 13 Nov 8, 2022
The Solid-State Register Allocator

The Solid-State Register Allocator A simple, extremely fast, reverse linear scan register allocator. See the detailed write-up for an in-depth explana

Matt Keeter 66 Dec 13, 2022
Rustyread is a drop in replacement of badread simulate.

Rustyread is a drop in replacement of badread simulate. Rustyread is very heavily inspired by badread, it reuses the same error and quality model file. But Rustyreads is multi-threaded and benefits from other optimizations.

Pierre Marijon 20 Oct 1, 2022
Modern Drop-in Replacement for Nginx AutoIndex / FancyIndex!

MeowIndex A cute, feature-rich file listing module to replace nginx's autoindex / fancyindex. Features List files Show file icons Clickable, length-sa

Hykilpikonna 4 Feb 25, 2023
Simple library to host lv2 plugins. Is not meant to support any kind of GUI.

lv2-host-minimal Simple library to host lv2 plugins. Is not meant to support any kind of GUI. Host fx plugins (audio in, audio out) Set parameters Hos

Cody Bloemhard 11 Aug 31, 2022
A simple entity-component-system crate for rust with serialization support

Gallium A simple entity-component-system crate for rust with serialization support Usage You can include the library using carge: [dependencies] galli

null 7 Aug 31, 2021
Serde support for (rusty_)v8

serde_v8 Serde support for (rusty_)v8 WIP: see denoland/deno#9540 TODO Experiment with KeyCache to optimize struct keys Experiment with external v8 st

Aaron O'Mullan 13 Nov 28, 2022
3MF (3D Manufacturing Format) support for Rust

3MF (3D Manufacturing Format) support for Rust About This library provides support for 3MF files to programs written in the Rust programming language.

Hanno Braun 21 Dec 17, 2022