Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "Exec Item Pools"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
(Added a code example for the ITEMGC_AFTERCOUNT policy. Added the Function Reference section.)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
= Introduction =
+
== Introduction ==
   
An item pool is a special memory pool that can only allocate and deallocate predefined slabs of memory. Every allocation from this pool is exactly the same size. There are no exceptions to this rule. Allocation and deallocation of these items is typically extremely fast unless the pool needs to be enlarged or garbage collection takes place. Item pools are commonly called "slab allocators" although the latter usually also refers to a kind of allocation that leaves data intact between calls.
+
An item pool is a special [[Exec Memory Pools|memory pool]] that can only allocate and deallocate predefined slabs of memory. Every allocation from this pool is exactly the same size; there are no exceptions to this rule. Allocation and deallocation of these items is typically extremely fast unless the pool needs to be enlarged or garbage collection takes place. Item pools are commonly called "slab allocators" although the latter usually also refers to a kind of allocation that leaves data intact between calls.
   
 
An item pool should be used whenever an application wants to allocate a large number of equally sized objects. For example, an application allocating a couple thousand Rectangle structures, or list items, could use an item pool for that to dramatically reduce the allocation time and memory fragmentation.
 
An item pool should be used whenever an application wants to allocate a large number of equally sized objects. For example, an application allocating a couple thousand Rectangle structures, or list items, could use an item pool for that to dramatically reduce the allocation time and memory fragmentation.
Line 7: Line 7:
 
Many applications frequently allocate very similar pieces of memory, like list nodes, rectangles, or similar structures. If these items are sufficiently large, their constant allocation and deallocation will produce a potentially large amount of fragmented memory nodes.
 
Many applications frequently allocate very similar pieces of memory, like list nodes, rectangles, or similar structures. If these items are sufficiently large, their constant allocation and deallocation will produce a potentially large amount of fragmented memory nodes.
   
= Creating an Item Pool =
+
== Creating an Item Pool ==
   
 
You create an item pool by calling AllocSysObject() with the ASOT_ITEMPOOL object type and the item size, memory type, garbage collection policy and other options.
 
You create an item pool by calling AllocSysObject() with the ASOT_ITEMPOOL object type and the item size, memory type, garbage collection policy and other options.
Line 37: Line 37:
 
Take note that all you know about an item pool is its address. Do not poke around it trying to figure out its organization. It's private for a reason!
 
Take note that all you know about an item pool is its address. Do not poke around it trying to figure out its organization. It's private for a reason!
   
== Garbage Collection Policy ==
+
=== Garbage Collection Policy ===
   
Each item pool has a garbage collection policy associated with it. The garbage collection policy can have a negative impact on the allocation/deallocation speed of an item pool so it is important to choose the policy which is best for your specific application.
+
Each item pool has a garbage collection policy associated with it. Note that the garbage collection policy can have a negative impact on the allocation/deallocation speed of an item pool, so it is important to choose the policy which is best for your specific application.
   
 
Here is an example with garbage collection disabled and the maximum number of items set to 2000. This kind of item pool would allocate items very quickly with an upper bound so that it will not eat too much memory.
 
Here is an example with garbage collection disabled and the maximum number of items set to 2000. This kind of item pool would allocate items very quickly with an upper bound so that it will not eat too much memory.
Line 54: Line 54:
 
In this case, the application is responsible for manually performing garbage collection using the ItemPoolGC() function.
 
In this case, the application is responsible for manually performing garbage collection using the ItemPoolGC() function.
   
  +
The second example defines the ITEMGC_AFTERCOUNT policy for the item pool. With this policy in place, garbage collection will automatically be performed after a given number of items have been deallocated. This number is specified via the ASOITEM_GCParameter tag:
= Allocating Memory from an Item Pool =
 
  +
  +
<syntaxhighlight>
  +
APTR item_pool = IExec->AllocSysObjectTags(ASOT_ITEMPOOL,
  +
ASOITEM_MFlags, MEMF_PRIVATE | MEMF_CLEAR,
  +
ASOITEM_ItemSize, sizeof(struct Rectangle),
  +
ASOITEM_MaxSize, 2000,
  +
ASOITEM_GCPolicy, ITEMGC_AFTERCOUNT, /* perform garbage collection */
  +
ASOITEM_GCParameter, 500, /* after 500 items have been deallocated */
  +
TAG_END);
  +
</syntaxhighlight>
  +
  +
== Allocating Memory from an Item Pool ==
   
 
Memory is obtained from an item pool by calling ItemPoolAlloc(). ItemPoolAlloc() requires only a pointer to the item pool and nothing more. That is because the size of every item is exactly the same as defined by the ASOITEM_ItemSize tag during pool creation. If successful, ItemPoolAlloc() returns a pointer to the memory.
 
Memory is obtained from an item pool by calling ItemPoolAlloc(). ItemPoolAlloc() requires only a pointer to the item pool and nothing more. That is because the size of every item is exactly the same as defined by the ASOITEM_ItemSize tag during pool creation. If successful, ItemPoolAlloc() returns a pointer to the memory.
   
 
<syntaxhighlight>
 
<syntaxhighlight>
struct Rectangle *rect = IExec->ItemPoolAlloc(item_pool);
+
struct Rectangle *rect = (struct Rectangle*) IExec->ItemPoolAlloc(item_pool);
   
 
if (rect != NULL)
 
if (rect != NULL)
Line 75: Line 87:
 
The optional item constructor, specified with the ASOITEM_Constructor tag, is called immediately after an item is successfully allocated. If the MEMF_CLEAR was specified, the item will have been cleared before the constructor is called.
 
The optional item constructor, specified with the ASOITEM_Constructor tag, is called immediately after an item is successfully allocated. If the MEMF_CLEAR was specified, the item will have been cleared before the constructor is called.
   
= Freeing Memory from an Item Pool =
+
== Freeing Memory from an Item Pool ==
   
 
Memory is returned for use in an item pool by calling ItemPoolFree(). ItemPoolFree() requires a pointer to the item pool and the item to be freed.
 
Memory is returned for use in an item pool by calling ItemPoolFree(). ItemPoolFree() requires a pointer to the item pool and the item to be freed.
Line 87: Line 99:
 
The optional item destructor, specified with the ASOITEM_Destructor tag, is called immediately before an item is freed.
 
The optional item destructor, specified with the ASOITEM_Destructor tag, is called immediately before an item is freed.
   
= Controlling an Item Pool =
+
== Controlling an Item Pool ==
   
 
The application programmer can exercise more control of an item pool than is possible with the more generic [[Exec_Memory_Pools|Memory Pools]].
 
The application programmer can exercise more control of an item pool than is possible with the more generic [[Exec_Memory_Pools|Memory Pools]].
Line 99: Line 111:
 
It may also be desirable to change certain item pool behavior as an application continues to execute. The ItemPoolControl() function may be used to alter the:
 
It may also be desirable to change certain item pool behavior as an application continues to execute. The ItemPoolControl() function may be used to alter the:
 
* maximum number of items (ASOITEM_MaxSize)
 
* maximum number of items (ASOITEM_MaxSize)
* garbage collection policy (ASOITEM_GCPolicy and ASOITEM_GCParam)
+
* garbage collection policy (ASOITEM_GCPolicy and ASOITEM_GCParameter)
 
* item contructor and destructor (ASOITEM_Constructor and ASOITEM_Destructor)
 
* item contructor and destructor (ASOITEM_Constructor and ASOITEM_Destructor)
   
Line 114: Line 126:
 
In this example, the garbage collection policy and maximum number of items allowed in the item pool are being changed.
 
In this example, the garbage collection policy and maximum number of items allowed in the item pool are being changed.
   
= Concurrent Access =
+
== Concurrent Access ==
   
 
Item pools may be protected from concurrent access by specifying the ASOITEM_Protected tag when creating the pool.
 
Item pools may be protected from concurrent access by specifying the ASOITEM_Protected tag when creating the pool.
Line 127: Line 139:
   
 
In this case, the memory is being shared between two Tasks or Processes so it must be of type MEMF_SHARED. By specifying that the item pool is protected we are guaranteed all operations performed on the item pool are thread safe.
 
In this case, the memory is being shared between two Tasks or Processes so it must be of type MEMF_SHARED. By specifying that the item pool is protected we are guaranteed all operations performed on the item pool are thread safe.
  +
  +
== Function Reference ==
  +
  +
The following table gives a brief description of the Exec functions that control item pools. See the SDK/Autodocs for more details about each call.
  +
  +
{| class="wikitable"
  +
! Function
  +
! Description
  +
|-
  +
| ItemPoolAlloc()
  +
| Allocate an item from a pool.
  +
|-
  +
| ItemPoolControl()
  +
| Control attributes in an item pool.
  +
|-
  +
| ItemPoolFlush()
  +
| Delete all items in an item pool.
  +
|-
  +
| ItemPoolFree()
  +
| Return an item to its pool for reuse.
  +
|-
  +
| ItemPoolGC()
  +
| Perform garbage collection in an item pool.
  +
|}

Latest revision as of 09:43, 2 April 2015

Introduction

An item pool is a special memory pool that can only allocate and deallocate predefined slabs of memory. Every allocation from this pool is exactly the same size; there are no exceptions to this rule. Allocation and deallocation of these items is typically extremely fast unless the pool needs to be enlarged or garbage collection takes place. Item pools are commonly called "slab allocators" although the latter usually also refers to a kind of allocation that leaves data intact between calls.

An item pool should be used whenever an application wants to allocate a large number of equally sized objects. For example, an application allocating a couple thousand Rectangle structures, or list items, could use an item pool for that to dramatically reduce the allocation time and memory fragmentation.

Many applications frequently allocate very similar pieces of memory, like list nodes, rectangles, or similar structures. If these items are sufficiently large, their constant allocation and deallocation will produce a potentially large amount of fragmented memory nodes.

Creating an Item Pool

You create an item pool by calling AllocSysObject() with the ASOT_ITEMPOOL object type and the item size, memory type, garbage collection policy and other options.

The item pool is created with an initial amount of item storage space and automatically extends when that space runs out. To control the maximum number of allocations allowed use the ASOITEM_MaxSize tag.

The memory type is one of MEMF_PRIVATE or MEMF_SHARED. The MEMF_ANY type may be used to indicate that either of these memory types is suitable. If your application requires memory of different types (for example, private memory and shared memory), it must create a pool for each type.

Setting MEMF_CLEAR in the memory flags will result in clearing each allocated item (prior to calling any defined constructor hook) so it might introduce a certain overhead.

If successful, AllocSysObject() returns the address of the item pool.

APTR item_pool = IExec->AllocSysObjectTags(ASOT_ITEMPOOL,
  ASOITEM_MFlags, MEMF_PRIVATE | MEMF_CLEAR,
  ASOITEM_ItemSize, sizeof(struct Rectangle),
  TAG_END);
 
if (item_pool != NULL)
{
  // ...
}
else
  IDOS->Printf("Pool could not be created.\n");

The example above attempts to create an item pool with an item size of sizeof(struct Rectangle).

Take note that all you know about an item pool is its address. Do not poke around it trying to figure out its organization. It's private for a reason!

Garbage Collection Policy

Each item pool has a garbage collection policy associated with it. Note that the garbage collection policy can have a negative impact on the allocation/deallocation speed of an item pool, so it is important to choose the policy which is best for your specific application.

Here is an example with garbage collection disabled and the maximum number of items set to 2000. This kind of item pool would allocate items very quickly with an upper bound so that it will not eat too much memory.

APTR item_pool = IExec->AllocSysObjectTags(ASOT_ITEMPOOL,
  ASOITEM_MFlags, MEMF_PRIVATE | MEMF_CLEAR,
  ASOITEM_ItemSize, sizeof(struct Rectangle),
  ASOITEM_MaxSize, 2000,
  ASOITEM_GCPolicy, ITEMGC_NONE,
  TAG_END);

In this case, the application is responsible for manually performing garbage collection using the ItemPoolGC() function.

The second example defines the ITEMGC_AFTERCOUNT policy for the item pool. With this policy in place, garbage collection will automatically be performed after a given number of items have been deallocated. This number is specified via the ASOITEM_GCParameter tag:

APTR item_pool = IExec->AllocSysObjectTags(ASOT_ITEMPOOL,
  ASOITEM_MFlags, MEMF_PRIVATE | MEMF_CLEAR,
  ASOITEM_ItemSize, sizeof(struct Rectangle),
  ASOITEM_MaxSize, 2000,
  ASOITEM_GCPolicy, ITEMGC_AFTERCOUNT,   /* perform garbage collection            */
  ASOITEM_GCParameter, 500,              /* after 500 items have been deallocated */
  TAG_END);

Allocating Memory from an Item Pool

Memory is obtained from an item pool by calling ItemPoolAlloc(). ItemPoolAlloc() requires only a pointer to the item pool and nothing more. That is because the size of every item is exactly the same as defined by the ASOITEM_ItemSize tag during pool creation. If successful, ItemPoolAlloc() returns a pointer to the memory.

struct Rectangle *rect = (struct Rectangle*) IExec->ItemPoolAlloc(item_pool);
 
if (rect != NULL)
{
  // ...
}
else
  IDOS->Printf("Memory could not be allocated.\n");

You must not make any assumptions about the contents of a newly created item other than having it cleared when MEMF_CLEAR is specified. Most notably, the content of an item may change when it is re-allocated.

Items within an item pool are not necessarily packed closely together. The system may adjust the item size for better cache coherency or other factors.

The optional item constructor, specified with the ASOITEM_Constructor tag, is called immediately after an item is successfully allocated. If the MEMF_CLEAR was specified, the item will have been cleared before the constructor is called.

Freeing Memory from an Item Pool

Memory is returned for use in an item pool by calling ItemPoolFree(). ItemPoolFree() requires a pointer to the item pool and the item to be freed.

IExec->ItemPoolFree(item_pool, rect);

In this example, the "rect" pointer must point to an item which was previously allocated with ItemPoolAlloc(). Items can never be reused or otherwise referenced after being freed.

The optional item destructor, specified with the ASOITEM_Destructor tag, is called immediately before an item is freed.

Controlling an Item Pool

The application programmer can exercise more control of an item pool than is possible with the more generic Memory Pools.

Explicit flushing on an item pool is possible without actually deleting the item pool by using the ItemPoolFlush() function. In this example, the item pool will have all its items freed.

IExec->ItemPoolFlush(item_pool);

It may also be desirable to change certain item pool behavior as an application continues to execute. The ItemPoolControl() function may be used to alter the:

  • maximum number of items (ASOITEM_MaxSize)
  • garbage collection policy (ASOITEM_GCPolicy and ASOITEM_GCParameter)
  • item contructor and destructor (ASOITEM_Constructor and ASOITEM_Destructor)
uint32 num_set = IExec->ItemPoolControl(item_pool,
  ASOITEM_GCPolicy, ITEMGC_AFTERCOUNT,
  ASOITEM_MaxSize, 4000,
  TAG_END);
 
if (num_set != 2)
  IDOS->Printf("Item pool changes did not work!\n");

In this example, the garbage collection policy and maximum number of items allowed in the item pool are being changed.

Concurrent Access

Item pools may be protected from concurrent access by specifying the ASOITEM_Protected tag when creating the pool.

APTR item_pool = IExec->AllocSysObjectTags(ASOT_ITEMPOOL,
  ASOITEM_MFlags, MEMF_SHARED,
  ASOITEM_ItemSize, sizeof(struct Rectangle),
  ASOITEM_Protected, TRUE,
  TAG_END);

In this case, the memory is being shared between two Tasks or Processes so it must be of type MEMF_SHARED. By specifying that the item pool is protected we are guaranteed all operations performed on the item pool are thread safe.

Function Reference

The following table gives a brief description of the Exec functions that control item pools. See the SDK/Autodocs for more details about each call.

Function Description
ItemPoolAlloc() Allocate an item from a pool.
ItemPoolControl() Control attributes in an item pool.
ItemPoolFlush() Delete all items in an item pool.
ItemPoolFree() Return an item to its pool for reuse.
ItemPoolGC() Perform garbage collection in an item pool.