Oftentimes it is necessary to use scratch Image3D's and Field3D's. However, the continual allocation and deallocation of large chunks of memory can be time consuming. Therefore, we make this process more efficient by using the PyCA Memory Manager. Instead of initializing Image3D's and Field3D's, we use the equivalent ManagedImage3D's and ManagedField3D's. The only difference is that when a Managed Image/Field's memory is allocated, it is allocated using memory stored in the MemoryManager, and when a Image/Field is destructed, it's memory is returned to the memory manager.
The memory manager is initialized with a grid and will allocate N pools of memory with the grid size.
import PyCA.Core as ca
grid = ca.GridInfo(ca.Vec3Di(64, 64, 32))
mType = ca.MEM_DEVICE
# Initialize memory manager by allocating 4 64x64x32 pools of memory on the GPU
ca.ThreadMemoryManager.init(grid, mType, 4)
To use the memory manager, we create a ManagedImage3D (using 1 pool of memory) or ManagedField3D (using 3 pools of memory). If we go over our initially allotted number of memory pools, the memory manager will automatically increase its number of pools. However, it will never decrease it's size (which would defeat the purpose). For Example:
TempIm1 = ca.ManagedImage3D(grid, mType) #using 1/4 pools
TempIm2 = ca.ManagedImage3D(grid, mType) #using 2/4 pools
TempVF1 = ca.ManagedField3D(grid, mType) #using 5/5 pools
TempVF2 = ca.ManagedField3D(grid, mType) #using 8/8 pools
del(TempIm1) #using 7/8 pools
TempVF3 = ca.ManagedField3D(grid, mType) #using 10/10 pools
del(TempVF1) #using 7/10 pools
TempIm3 = ca.ManagedImage3D(grid, mType) #using 8/10 pools
The thread memory manager is globally defined and doesn't need to be passed into functions. We can see the max number of pools by declaring a local instance of the memory manger and using the getNumPools
method.
global_mm = ca.ThreadMemoryManager.instance()
print 'Total number of mem pools:', global_mm.getNumPools()
Total number of mem pools: 10
When creating ManagedImage3D's and ManagedField3D's, we are not required to use identical grids as the grid defined by the memory manager. In fact, our spacing and origin have no effect, as they have no effect on the memory requirements. However, our grids may not be larger than the grid of the initialized memory manager.
grid1 = ca.GridInfo(ca.Vec3Di(32,64,64)) #Allowed
grid2 = ca.GridInfo(ca.Vec3Di(100,100,1)) #Allowed
grid3 = ca.GridInfo(ca.Vec3Di(1, 1, 1)) #Allowed
grid4 = ca.GridInfo(ca.Vec3Di(64, 64, 64)) #Not Allowed
TempIm1 = ca.ManagedImage3D(grid1, mType)
TempIm2 = ca.ManagedImage3D(grid2, mType)
TempIm3 = ca.ManagedImage3D(grid3, mType)
TempIm4 = ca.ManagedImage3D(grid4, mType) #Will throw an Exception
--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) <ipython-input-5-36eb0d6a96d9> in <module>() ----> 1 TempIm4 = ca.ManagedImage3D(grid4, mType) /local/crottman/software/pyca-bin/python_module/PyCA/Core.pyc in __init__(self, *args) 2268 __init__(PyCA::ManagedImage3D self, GridInfo grid, PyCA::MemoryType mType, MemoryManager mm) -> ManagedImage3D 2269 """ -> 2270 this = _Core.new_ManagedImage3D(*args) 2271 try: self.this.append(this) 2272 except: self.this = this RuntimeError: PyCA::ManagedImage3D::ManagedImage3D(PyCA::GridInfo const &,PyCA::MemoryType): PyCAException : From /local/crottman/git/PyCA/Code/Cxx/src/base/MemoryManager.cxx:137 : Grid too large
Although you can create ManagedImage3D's and ManagedField3D's with grids smaller than the memroy manager's grid, it may not be wise to do so especially if the new grid size is significantly smaller than the memory manager's grid size. For example, if you initialized the memory manager with a 256x256x256 sized grid and created 10 ManagedImage3D's with a 1x1x1 sized grid, you would be allocating much more memory than necessary (since the memory manager would allocate 10 256x256x256 memory pools).
You are only allowed to initialize one global thread memory manager. However, if you have multiple grids that you need managed, you can create additional memory managers.
newgrid = ca.GridInfo(ca.Vec3Di(50, 50, 1))
mType = ca.MEM_DEVICE
mem_man_2 = ca.MemoryManager(grid, mType, 1)
The main difference in using this memory manager to create a ManagedImage3D or a ManagedField3D is that you need to include the specific memory manger in the Image/Field's initialization. If this is not specified, it will create a Managed Image/Field from the thread memory manager.
TempIm = ca.ManagedImage3D(newgrid, mType, mem_man_2)
TempVF = ca.ManagedField3D(newgrid, mType, mem_man_2)
print 'Total number of mem pools:', mem_man_2.getNumPools()
Total number of mem pools: 4
Local memory managers will be deleted by Python's garbage collector. If you want to delete the thread memory manager, you can delete it by calling the destructor. When you do this, a message will print out to the terminal telling you the maximum temporary pools were used.
del(mem_man_2) #delete the local memory manager
ca.ThreadMemoryManager.destroy() #delete the thread memory manager