Safe Haskell | None |
---|---|
Language | Haskell2010 |
A very basic memory pool imlemented in haskell.
The core idea is that the pool allocates large chunks of memory that are some power-of-two factor (e.g. 256) of some base size (e.g. 10k). The user of the pool allocates chunks of a power-of-two factor of the base size (i.e. 10k, 20k, 40k, ..). This scheme avoids fragmentation due to weirdly-sized holes, but keep in mind that no compaction takes place, so this kind of fragmentation must be worked around manually if necessary.
The pool internally allocates memory on the C heap, i.e. outside of any haskell/GC heap.
Uses a buddy allocation strategy internally.
- data Pool
- create :: CSize -> CSize -> IO Pool
- allocate :: Pool -> CSize -> IO (IO (), Ptr a)
- allocateForeign :: Pool -> CSize -> IO (ForeignPtr a)
- data PoolData
- debugShowPoolFillsData :: PoolData -> String
- debugTracePoolFills :: Pool -> IO ()
- getPtrFragmentation :: PoolData -> Ptr a -> Maybe Float
- unsafeGetPoolDataSnapshot :: Pool -> IO PoolData
type
interface
:: CSize | base size. |
-> CSize | block exponent; each internal block holds (2**block_exp) * base_size. Must be at least 1. |
-> IO Pool |
Create an empty pool. A pool internally allocates several relatively
large blocks via malloc
and returns chunks of these when requested via
allocate
.
Note that the rts does not "see" these allocations in any way. I.e. memory allocated in the pool does not count towards heap space in the rts and is not captured by heap profiling.
:: Pool | pool to allocate in |
-> CSize | number of bytes to allocate. |
-> IO (IO (), Ptr a) | the ptr to the memory allocated in the pool, plus a deallaction action. |
Allocate memory inside the specified pool. The amount allocated is rounded up to the next power-of-two multiple of the base size.
The number of bytes to allocated is limited in both directions:
The minimum amount is 1 (0 is an error).
The maximum is the number of a bytes in a block as specified by the
arguments to
.create
No deallocation happens unless the provided deallocation action is executed.
(See allocateForeign
for a more automatic variant of this function.)
The deallocation action must not be called more than once.
:: Pool | pool to allocate in |
-> CSize | number of bytes to allocate. |
-> IO (ForeignPtr a) |
Similar to allocate
, but performs the deallocation automatically as
a finalizer on the returned ForeignPtr. This may lead to (arbitrary) delays
between dropping of the reference and actual freeing of pool memory, but
is much more convenient on usage side.
low-level and debugging functions
debugShowPoolFillsData :: PoolData -> String Source
Return a visual representation of allocation inside the pool. Both distribution of blocks and fragmentation inside each block is displayed.
debugTracePoolFills :: Pool -> IO () Source
Prints a visual representation of allocation inside the pool to stderr. Both distribution of blocks and fragmentation inside each block is displayed.
getPtrFragmentation :: PoolData -> Ptr a -> Maybe Float Source
if Ptr is not allocated in this pool, returns Nothing.
Otherwise returns a rather rough estimate of the usage for the block that
the pointer is allocated in. For example if it returns (Just 0.75), at least
25% of the block is free (the other bound should be.. 50% i think. But the
error depends in a nontrivial fashion on the value.
Use unsafeGetPoolDataSnapshot
to obtain the first argument.
unsafeGetPoolDataSnapshot :: Pool -> IO PoolData Source
Retrieve a snapshot of the internal data of a pool. This currently exists
soly as an argument to getPtrFragmentation
.