add doxygen docs and convert MyPage template class from header only to header plus implementation

This commit is contained in:
Axel Kohlmeyer
2020-09-06 22:25:54 -04:00
parent 485a169ef2
commit 4ca36d9526
5 changed files with 317 additions and 194 deletions

View File

@ -410,24 +410,27 @@ WARN_LOGFILE = "../doxygen-warn.log"
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = @LAMMPS_SOURCE_DIR@/utils.cpp \
@LAMMPS_SOURCE_DIR@/utils.h \
@LAMMPS_SOURCE_DIR@/library.cpp \
@LAMMPS_SOURCE_DIR@/library.h \
@LAMMPS_SOURCE_DIR@/lammps.cpp \
@LAMMPS_SOURCE_DIR@/lammps.h \
@LAMMPS_SOURCE_DIR@/lmptype.h \
@LAMMPS_SOURCE_DIR@/pointers.h \
@LAMMPS_SOURCE_DIR@/atom.cpp \
@LAMMPS_SOURCE_DIR@/atom.h \
@LAMMPS_SOURCE_DIR@/input.cpp \
@LAMMPS_SOURCE_DIR@/input.h \
@LAMMPS_SOURCE_DIR@/tokenizer.cpp \
@LAMMPS_SOURCE_DIR@/tokenizer.h \
@LAMMPS_SOURCE_DIR@/text_file_reader.cpp \
@LAMMPS_SOURCE_DIR@/text_file_reader.h \
@LAMMPS_SOURCE_DIR@/potential_file_reader.cpp \
@LAMMPS_SOURCE_DIR@/potential_file_reader.h \
INPUT = @LAMMPS_SOURCE_DIR@/utils.cpp \
@LAMMPS_SOURCE_DIR@/utils.h \
@LAMMPS_SOURCE_DIR@/library.cpp \
@LAMMPS_SOURCE_DIR@/library.h \
@LAMMPS_SOURCE_DIR@/lammps.cpp \
@LAMMPS_SOURCE_DIR@/lammps.h \
@LAMMPS_SOURCE_DIR@/lmptype.h \
@LAMMPS_SOURCE_DIR@/pointers.h \
@LAMMPS_SOURCE_DIR@/atom.cpp \
@LAMMPS_SOURCE_DIR@/atom.h \
@LAMMPS_SOURCE_DIR@/input.cpp \
@LAMMPS_SOURCE_DIR@/input.h \
@LAMMPS_SOURCE_DIR@/tokenizer.cpp \
@LAMMPS_SOURCE_DIR@/tokenizer.h \
@LAMMPS_SOURCE_DIR@/text_file_reader.cpp \
@LAMMPS_SOURCE_DIR@/text_file_reader.h \
@LAMMPS_SOURCE_DIR@/potential_file_reader.cpp \
@LAMMPS_SOURCE_DIR@/potential_file_reader.h \
@LAMMPS_SOURCE_DIR@/my_page.cpp \
@LAMMPS_SOURCE_DIR@/my_page.h \
@LAMMPS_SOURCE_DIR@/my_pool_chunk.h \
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded

View File

@ -53,7 +53,7 @@ command, e.g. ``src/force.cpp`` and the :cpp:class:`LAMMPS_NS::Force`
class. They are discussed in the next section.
A small number of C++ classes and utility functions are implemented with
only a ``.h`` file. Examples are the Pointer class and the mergesort function.
only a ``.h`` file. Examples are the Pointer class or the MyPool class.
LAMMPS class topology
=====================
@ -1102,3 +1102,12 @@ A file that would be parsed by the reader code fragment looks like this:
:project: progguide
:members:
----------
Memory pool classes
===================
.. doxygenclass:: LAMMPS_NS::MyPage
:project: progguide
:members:

View File

@ -1975,6 +1975,7 @@ MxN
myCompute
myIndex
mylammps
MyPool
mysocket
myTemp
myVec

267
src/my_page.cpp Normal file
View File

@ -0,0 +1,267 @@
/* -*- 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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
usage:
request one datum at a time, repeat, clear
request chunks of datums in each get() or vget(), repeat, clear
chunk size can vary from request to request
chunk size can be known in advance or registered after usage via vgot()
inputs:
template T = one datum, e.g. int, double, struct, int[3]
for int[3], access datum as ivec[i][2]
methods:
T *get() = return ptr to one datum
T *get(N) = return ptr to N datums, N < maxchunk required
T *vget() = return ptr to maxchunk datums, use as needed, then call vgot()
all gets return NULL if error encountered
vgot(N) = used N datums of previous vget(), N < maxchunk required
void init(maxchunk, pagesize, pagedelta)
define allocation params and allocate first page(s)
call right after constructor
can call again to reset allocation params and free previous pages
maxchunk = max # of datums in one chunk, default = 1
pagesize = # of datums in one page, default = 1024
should be big enough to store multiple chunks
pagedelta = # of pages to allocate at a time, default = 1
return 1 if bad params
void reset() = clear pages w/out freeing
int size() = return total size of allocated pages in bytes
int status() = return error status
0 = ok, 1 = chunksize > maxchunk, 2 = allocation error
------------------------------------------------------------------------- */
#include "my_page.h"
#include <cstdlib>
#if defined(LMP_USER_INTEL) && !defined(LAMMPS_MEMALIGN) && !defined(_WIN32)
#define LAMMPS_MEMALIGN 64
#endif
using namespace LAMMPS_NS;
/** \class LAMMPS_NS::MyPage
* \brief Templated class for storing chunks of datums in pages.
*
* The chunks are not returnable (i.e. cannot be freed individually).
* One can only reset and start over. The purpose of this
* class is to replace many small mallocs with a few large
* mallocs. Since the pages are never freed, they can be re-used
* without having to re-allocate them.
*
* The settings *maxchunk*, *pagesize*, and *pagedelta* contol
* the memory allocation strategy. The *maxchunk* value represents
* the expected largest number of items per chunk. If there is
* less space left on the current page, a new page is allocated
* for the next chunk. The *pagesize* value represents how many
* items can fit on a single page. It should have space for multiple
* chunks of size *maxchunk*. The combination of these two
* parameters determines how much memory is wasted by either switching
* to the next page too soon or allocating too large pages that never
* get properly used. It is an error, if a requested chunk is larger
* than *maxchunk*. The *pagedelta* parameter determines how many
* pages are allocated in one go. In combination with the *pagesize*
* setting, this determines how often blocks of memory get allocated
* (fewer allocations will result in faster execution).
*
* This class is the "workhorse" for the memory management of
* neighbor lists. */
/** Create a class instance
*
* Need to call init() before use to define allocation settings */
template <class T>
MyPage<T>::MyPage() : ndatum(0), nchunk(0), pages(nullptr), page(nullptr),
npage(0), ipage(-1), index(-1), maxchunk(-1),
pagesize(-1), pagedelta(1), errorflag(0) {};
/** Free all allocated pages of this class instance */
template <class T>
MyPage<T>::~MyPage() {
for (int i = 0; i < npage; i++) free(pages[i]);
free(pages);
}
/** (Re-)initialize the set of pages and allocation parameters.
*
* This also frees all previously allocated storage and allocates
* the first page(s).
*
* \param user_maxchunk Expected maximum number of items for one chunk
* \param user_pagesize Number of items on a single memory page
* \param user_page_delta Number of pages to allocate with one malloc
* \return 1 if there was an error or 0 if successful */
template<class T>
int MyPage<T>::init(int user_maxchunk, int user_pagesize,
int user_pagedelta) {
maxchunk = user_maxchunk;
pagesize = user_pagesize;
pagedelta = user_pagedelta;
if (maxchunk <= 0 || pagesize <= 0 || pagedelta <= 0) return 1;
if (maxchunk > pagesize) return 1;
// free any previously allocated pages
for (int i = 0; i < npage; i++) free(pages[i]);
free(pages);
// initial page allocation
ndatum = nchunk = 0;
pages = NULL;
npage = 0;
allocate();
if (errorflag) return 2;
ipage = index = 0;
page = pages[ipage];
return 0;
}
/** Pointer to location that can store one item.
*
* This will allocate more pages as needed.
*
* \return memory location or null pointer, if memory allocation failed */
template <class T>
T *MyPage<T>::get() {
ndatum++;
nchunk++;
if (index < pagesize) return &page[index++];
ipage++;
if (ipage == npage) {
allocate();
if (errorflag) return NULL;
}
page = pages[ipage];
index = 0;
return &page[index++];
}
/** Pointer to location that can store N items.
*
* This will allocate more pages as needed.
* If the parameter *N* is larger than the *maxchunk*
* setting an error is flagged.
*
* \param n number of items for which storage is requested
* \return memory location or null pointer, if error or allocation failed */
template <class T>
T *MyPage<T>::get(int n) {
if (n > maxchunk) {
errorflag = 1;
return NULL;
}
ndatum += n;
nchunk++;
if (index+n <= pagesize) {
int start = index;
index += n;
return &page[start];
}
ipage++;
if (ipage == npage) {
allocate();
if (errorflag) return NULL;
}
page = pages[ipage];
index = n;
return &page[0];
}
/** Get pointer to location that can store *maxchunk* items.
*
* This will return the same pointer as the previous call to
* this function unless vgot() is called afterwards to record
* how many items of the chunk were actually used.
*
* \return pointer to chunk of memory or null pointer if run out of memory */
template <class T>
T *MyPage<T>::vget() {
if (index+maxchunk <= pagesize) return &page[index];
ipage++;
if (ipage == npage) {
allocate();
if (errorflag) return NULL;
}
page = pages[ipage];
index = 0;
return &page[index];
}
/** Mark *N* items as used of the chunk reserved with a preceding call to vget().
*
* This will advance the internal pointer inside the current memory page.
* It is not necessary to call this function for *N* = 0, that is the reserved
* storage was not used. A following call to vget() will then reserve the
* same location again. It is an error if *N* > *maxchunk*.
*
* \param n Number of iterms used in previously reserved chunk */
template <class T>
void MyPage<T>::vgot(int n) {
if (n > maxchunk) errorflag = 1;
ndatum += n;
nchunk++;
index += n;
}
/** Reset state of memory pool without freeing any memory */
template <class T>
void MyPage<T>::reset() {
ndatum = nchunk = 0;
index = ipage = 0;
page = pages[ipage];
}
/* ---------------------------------------------------------------------- */
template <class T>
void MyPage<T>::allocate() {
npage += pagedelta;
pages = (T **) realloc(pages,npage*sizeof(T *));
if (!pages) {
errorflag = 2;
return;
}
for (int i = npage-pagedelta; i < npage; i++) {
#if defined(LAMMPS_MEMALIGN)
void *ptr;
if (posix_memalign(&ptr, LAMMPS_MEMALIGN, pagesize*sizeof(T)))
errorflag = 2;
pages[i] = (T *) ptr;
#else
pages[i] = (T *) malloc(pagesize*sizeof(T));
if (!pages[i]) errorflag = 2;
#endif
}
}
// explicit instantiations
#include "REPLICA/fix_hyper_local.h"
namespace LAMMPS_NS {
template class MyPage<int>;
template class MyPage<long>;
template class MyPage<long long>;
template class MyPage<double>;
template class MyPage<FixHyperLocal::OneCoeff>;
}

View File

@ -12,37 +12,7 @@
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
MyPage = templated class for storing chunks of datums in pages
chunks are not returnable, can only reset and start over
replaces many small mallocs with a few large mallocs
pages are never freed, so can reuse w/out reallocs
usage:
request one datum at a time, repeat, clear
request chunks of datums in each get() or vget(), repeat, clear
chunk size can vary from request to request
chunk size can be known in advance or registered after usage via vgot()
inputs:
template T = one datum, e.g. int, double, struct, int[3]
for int[3], access datum as ivec[i][2]
methods:
T *get() = return ptr to one datum
T *get(N) = return ptr to N datums, N < maxchunk required
T *vget() = return ptr to maxchunk datums, use as needed, then call vgot()
all gets return NULL if error encountered
vgot(N) = used N datums of previous vget(), N < maxchunk required
void init(maxchunk, pagesize, pagedelta)
define allocation params and allocate first page(s)
call right after constructor
can call again to reset allocation params and free previous pages
maxchunk = max # of datums in one chunk, default = 1
pagesize = # of datums in one page, default = 1024
should be big enough to store multiple chunks
pagedelta = # of pages to allocate at a time, default = 1
return 1 if bad params
void reset() = clear pages w/out freeing
int size() = return total size of allocated pages in bytes
int status() = return error status
0 = ok, 1 = chunksize > maxchunk, 2 = allocation error
templated class for storing chunks of datums in pages
------------------------------------------------------------------------- */
#ifndef LAMMPS_MY_PAGE_H
@ -52,7 +22,6 @@ methods:
#define LAMMPS_MEMALIGN 64
#endif
#include <cstdlib>
namespace LAMMPS_NS {
template<class T>
@ -60,139 +29,33 @@ class MyPage {
public:
int ndatum; // total # of stored datums
int nchunk; // total # of stored chunks
MyPage() {
ndatum = nchunk = 0;
pages = NULL;
npage = 0;
errorflag = 0;
}
// (re)initialize allocation params
// also allocate first page(s)
MyPage();
virtual ~MyPage();
int init(int user_maxchunk = 1, int user_pagesize = 1024,
int user_pagedelta = 1) {
maxchunk = user_maxchunk;
pagesize = user_pagesize;
pagedelta = user_pagedelta;
int user_pagedelta = 1);
T *get();
T *get(int n);
if (maxchunk <= 0 || pagesize <= 0 || pagedelta <= 0) return 1;
if (maxchunk > pagesize) return 1;
T *vget();
void vgot(int n);
// free any previously allocated pages
void reset();
for (int i = 0; i < npage; i++) free(pages[i]);
free(pages);
// initial page allocation
ndatum = nchunk = 0;
pages = NULL;
npage = 0;
allocate();
if (errorflag) return 2;
ipage = index = 0;
page = pages[ipage];
return 0;
}
// free all allocated pages
~MyPage() {
for (int i = 0; i < npage; i++) free(pages[i]);
free(pages);
}
// get ptr to one datum
// return NULL if run out of memory
T *get() {
ndatum++;
nchunk++;
if (index < pagesize) return &page[index++];
ipage++;
if (ipage == npage) {
allocate();
if (errorflag) return NULL;
}
page = pages[ipage];
index = 0;
return &page[index++];
}
// get ptr to location that can store N datums
// error if N > maxchunk
// return NULL if run out of memory
T *get(int n) {
if (n > maxchunk) {
errorflag = 1;
return NULL;
}
ndatum += n;
nchunk++;
if (index+n <= pagesize) {
int start = index;
index += n;
return &page[start];
}
ipage++;
if (ipage == npage) {
allocate();
if (errorflag) return NULL;
}
page = pages[ipage];
index = n;
return &page[0];
}
// get ptr to location that can store maxchunk datums
// will return same ptr as previous call if vgot() not called
// return NULL if run out of memory
T *vget() {
if (index+maxchunk <= pagesize) return &page[index];
ipage++;
if (ipage == npage) {
allocate();
if (errorflag) return NULL;
}
page = pages[ipage];
index = 0;
return &page[index];
}
// increment by N = # of values stored in loc returned by vget()
// OK to not call if vget() ptr was not used
// error if N > maxchunk
void vgot(int n) {
if (n > maxchunk) errorflag = 1;
ndatum += n;
nchunk++;
index += n;
}
// clear all pages, without freeing any memory
void reset() {
ndatum = nchunk = 0;
index = ipage = 0;
page = pages[ipage];
}
// return total size of allocated pages
/** Return total size of allocated pages
*
* \return total storage used in bytes */
int size() const {
return npage*pagesize*sizeof(T);
}
// return error status
/** Return error status
*
* \return 0 if no error, 1 requested chunk size > maxchunk, 2 if malloc failed */
int status() const {
return errorflag;
}
int status() const { return errorflag; }
private:
T **pages; // list of allocated pages
@ -208,27 +71,7 @@ class MyPage {
int errorflag; // flag > 0 if error has occurred
// 1 = chunk size exceeded maxchunk
// 2 = memory allocation error
void allocate() {
npage += pagedelta;
pages = (T **) realloc(pages,npage*sizeof(T *));
if (!pages) {
errorflag = 2;
return;
}
for (int i = npage-pagedelta; i < npage; i++) {
#if defined(LAMMPS_MEMALIGN)
void *ptr;
if (posix_memalign(&ptr, LAMMPS_MEMALIGN, pagesize*sizeof(T)))
errorflag = 2;
pages[i] = (T *) ptr;
#else
pages[i] = (T *) malloc(pagesize*sizeof(T));
if (!pages[i]) errorflag = 2;
#endif
}
}
void allocate();
};
}