small updates to MyPage and convert MyPoolChunk similar to MyPage
This commit is contained in:
244
src/my_pool_chunk.cpp
Normal file
244
src/my_pool_chunk.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
/* -*- c++ -*- ----------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
http://lammps.sandia.gov, Sandia National Laboratories
|
||||
Steve Plimpton, sjplimp@sandia.gov
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "my_pool_chunk.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#if defined(LMP_USER_INTEL) && !defined(LAMMPS_MEMALIGN) && !defined(_WIN32)
|
||||
#define LAMMPS_MEMALIGN 64
|
||||
#endif
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
/** \class LAMMPS_NS::MyPoolChunk
|
||||
* \brief Templated class for storing chunks of datums in pages
|
||||
*
|
||||
* The size of the chunk may vary from call to call between the
|
||||
* *minchunk* and *maxchunk* setting. Chunks may be returned
|
||||
* to the pool for re-use. Chunks can be reserved in *nbin*
|
||||
* different sizes between *minchunk* and *maxchunk*.
|
||||
* The *chunksperpage* setting specifies how many chunks are stored
|
||||
* on any page and the *pagedelta* setting determines how many
|
||||
* pages are allocated in one go. Pages are never freed, so they
|
||||
* can be re-used without re-allocation.
|
||||
*
|
||||
* \note
|
||||
* This is a template class with explicit instantiation. If the class
|
||||
* is used with a new data type a new explicit instantiation may need
|
||||
* to be added at the end of the file ``src/my_pool_chunk.cpp`` to
|
||||
* avoid symbol lookup errors. */
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
MyPoolChunk = templated class for storing chunks of datums in pages
|
||||
chunks can be returned to pool for reuse
|
||||
chunks come in nbin different fixed sizes so can reuse
|
||||
replaces many small mallocs with a few large mallocs
|
||||
pages are never freed, so can reuse w/out reallocs
|
||||
usage:
|
||||
continuously get() and put() chunks as needed
|
||||
NOTE: could add a clear() if retain info on mapping of pages to bins
|
||||
inputs:
|
||||
template T = one datum, e.g. int, double, struct
|
||||
minchunk = min # of datums in one chunk, def = 1
|
||||
maxchunk = max # of datums in one chunk, def = 1
|
||||
nbin = # of bins between minchunk and maxchunk
|
||||
chunkperpage = # of chunks in one page, def = 1024
|
||||
pagedelta = # of pages to allocate at a time, def = 1
|
||||
methods:
|
||||
T *get(index) = return ptr/index to unused chunk of size maxchunk
|
||||
T *get(N,index) = return ptr/index to unused chunk of size N
|
||||
minchunk <= N <= maxchunk required
|
||||
put(index) = return indexed chunk to pool (same index returned by get)
|
||||
int size() = return total size of allocated pages in bytes
|
||||
public variables:
|
||||
ndatum = total # of stored datums
|
||||
nchunk = total # of stored chunks
|
||||
size = total size of all allocated pages in daums
|
||||
errorflag = flag for various error conditions
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
/** Create a class instance and set memory pool parameters */
|
||||
template <class T>
|
||||
MyPoolChunk<T>::MyPoolChunk(int user_minchunk, int user_maxchunk, int user_nbin,
|
||||
int user_chunkperpage, int user_pagedelta) {
|
||||
minchunk = user_minchunk;
|
||||
maxchunk = user_maxchunk;
|
||||
nbin = user_nbin;
|
||||
chunkperpage = user_chunkperpage;
|
||||
pagedelta = user_pagedelta;
|
||||
|
||||
errorflag = 0;
|
||||
if (minchunk <= 0 || minchunk > maxchunk) errorflag = 1;
|
||||
if (user_nbin <= 0 || chunkperpage <= 0 || pagedelta <= 0) errorflag = 1;
|
||||
|
||||
freehead = new int[nbin];
|
||||
chunksize = new int[nbin];
|
||||
if (!freehead || !chunksize) errorflag = 1;
|
||||
if (errorflag) return;
|
||||
|
||||
// insure nbin*binsize spans minchunk to maxchunk inclusive
|
||||
|
||||
binsize = (maxchunk-minchunk+1) / nbin;
|
||||
if (minchunk + nbin*binsize <= maxchunk) binsize++;
|
||||
|
||||
freelist = nullptr;
|
||||
for (int ibin = 0; ibin < nbin; ibin++) {
|
||||
freehead[ibin] = -1;
|
||||
chunksize[ibin] = minchunk + (ibin+1)*binsize - 1;
|
||||
if (chunksize[ibin] > maxchunk) chunksize[ibin] = maxchunk;
|
||||
}
|
||||
|
||||
ndatum = nchunk = 0;
|
||||
pages = nullptr;
|
||||
whichbin = nullptr;
|
||||
npage = 0;
|
||||
}
|
||||
|
||||
/** Destroy class instance and free all allocated memory */
|
||||
template <class T>
|
||||
MyPoolChunk<T>::~MyPoolChunk() {
|
||||
delete [] freehead;
|
||||
delete [] chunksize;
|
||||
if (npage) {
|
||||
free(freelist);
|
||||
for (int i = 0; i < npage; i++) free(pages[i]);
|
||||
free(pages);
|
||||
free(whichbin);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return pointer/index of unused chunk of size maxchunk
|
||||
*
|
||||
* \param index Index of chunk in memory pool
|
||||
* \return Pointer to requested chunk of storage */
|
||||
|
||||
template <class T>
|
||||
T *MyPoolChunk<T>::get(int &index) {
|
||||
int ibin = nbin-1;
|
||||
if (freehead[ibin] < 0) {
|
||||
allocate(ibin);
|
||||
if (errorflag) return nullptr;
|
||||
}
|
||||
|
||||
ndatum += maxchunk;
|
||||
nchunk++;
|
||||
index = freehead[ibin];
|
||||
int ipage = index/chunkperpage;
|
||||
int ientry = index % chunkperpage;
|
||||
freehead[ibin] = freelist[index];
|
||||
return &pages[ipage][ientry*chunksize[ibin]];
|
||||
}
|
||||
|
||||
/** Return pointer/index of unused chunk of size N
|
||||
*
|
||||
* \param n Size of chunk
|
||||
* \param index Index of chunk in memory pool
|
||||
* \return Pointer to requested chunk of storage */
|
||||
|
||||
template <class T>
|
||||
T *MyPoolChunk<T>::get(int n, int &index) {
|
||||
if (n < minchunk || n > maxchunk) {
|
||||
errorflag = 3;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ibin = (n-minchunk) / binsize;
|
||||
if (freehead[ibin] < 0) {
|
||||
allocate(ibin);
|
||||
if (errorflag) return nullptr;
|
||||
}
|
||||
|
||||
ndatum += n;
|
||||
nchunk++;
|
||||
index = freehead[ibin];
|
||||
int ipage = index/chunkperpage;
|
||||
int ientry = index % chunkperpage;
|
||||
freehead[ibin] = freelist[index];
|
||||
return &pages[ipage][ientry*chunksize[ibin]];
|
||||
}
|
||||
|
||||
/** Put indexed chunk back into memory pool via free list
|
||||
*/
|
||||
// index = -1 if no allocated chunk
|
||||
|
||||
template <class T>
|
||||
void MyPoolChunk<T>::put(int index) {
|
||||
if (index < 0) return;
|
||||
int ipage = index/chunkperpage;
|
||||
int ibin = whichbin[ipage];
|
||||
nchunk--;
|
||||
ndatum -= chunksize[ibin];
|
||||
freelist[index] = freehead[ibin];
|
||||
freehead[ibin] = index;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
void MyPoolChunk<T>::allocate(int ibin) {
|
||||
int oldpage = npage;
|
||||
npage += pagedelta;
|
||||
freelist = (int *) realloc(freelist,npage*chunkperpage*sizeof(int));
|
||||
pages = (T **) realloc(pages,npage*sizeof(T *));
|
||||
whichbin = (int *) realloc(whichbin,npage*sizeof(int));
|
||||
if (!freelist || !pages) {
|
||||
errorflag = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate pages with appropriate chunksize for ibin
|
||||
|
||||
for (int i = oldpage; i < npage; i++) {
|
||||
whichbin[i] = ibin;
|
||||
#if defined(LAMMPS_MEMALIGN)
|
||||
void *ptr;
|
||||
if (posix_memalign(&ptr, LAMMPS_MEMALIGN,
|
||||
chunkperpage*chunksize[ibin]*sizeof(T)))
|
||||
errorflag = 2;
|
||||
pages[i] = (T *) ptr;
|
||||
#else
|
||||
pages[i] = (T *) malloc(chunkperpage*chunksize[ibin]*sizeof(T));
|
||||
size += chunkperpage*chunksize[ibin];
|
||||
if (!pages[i]) errorflag = 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
// reset free list for unused chunks on new pages
|
||||
|
||||
freehead[ibin] = oldpage*chunkperpage;
|
||||
for (int i = freehead[ibin]; i < npage*chunkperpage; i++) freelist[i] = i+1;
|
||||
freelist[npage*chunkperpage-1] = -1;
|
||||
}
|
||||
|
||||
/** Return total size of allocated pages
|
||||
*
|
||||
* \return total storage used in bytes */
|
||||
|
||||
template <class T>
|
||||
double MyPoolChunk<T>::size() const {
|
||||
double bytes = npage*chunkperpage*sizeof(int);
|
||||
bytes += npage*sizeof(T *);
|
||||
bytes += npage*sizeof(int);
|
||||
for (int i=0; i < npage; ++i)
|
||||
bytes += chunkperpage*chunksize[i]*sizeof(T);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
template class MyPoolChunk<int>;
|
||||
template class MyPoolChunk<double>;
|
||||
}
|
||||
Reference in New Issue
Block a user