nidas  v1.2-1520
SamplePool.h
Go to the documentation of this file.
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4; -*-
2 // vim: set shiftwidth=4 softtabstop=4 expandtab:
3 /*
4  ********************************************************************
5  ** NIDAS: NCAR In-situ Data Acquistion Software
6  **
7  ** 2004, Copyright University Corporation for Atmospheric Research
8  **
9  ** This program is free software; you can redistribute it and/or modify
10  ** it under the terms of the GNU General Public License as published by
11  ** the Free Software Foundation; either version 2 of the License, or
12  ** (at your option) any later version.
13  **
14  ** This program is distributed in the hope that it will be useful,
15  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  ** GNU General Public License for more details.
18  **
19  ** The LICENSE.txt file accompanying this software contains
20  ** a copy of the GNU General Public License. If it is not found,
21  ** write to the Free Software Foundation, Inc.,
22  ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  **
24  ********************************************************************
25 */
26 
27 #ifndef NIDAS_CORE_SAMPLEPOOL_H
28 #define NIDAS_CORE_SAMPLEPOOL_H
29 
31 #include "SampleLengthException.h"
32 #include <nidas/util/Logger.h>
33 
34 #include <cassert>
35 #include <cstring> // memcpy()
36 #include <vector>
37 #include <list>
38 #include <iostream>
39 
40 namespace nidas { namespace core {
41 
43 {
44 public:
45  virtual ~SamplePoolInterface() {}
46  virtual int getNSamplesAlloc() const = 0;
47  virtual int getNSamplesOut() const = 0;
48  virtual int getNSmallSamplesIn() const = 0;
49 
50  virtual int getNMediumSamplesIn() const = 0;
51 
52  virtual int getNLargeSamplesIn() const = 0;
53 
54 };
55 
57 {
58 public:
59  static SamplePools* getInstance();
60 
61  static void deleteInstance();
62 
71  std::list<SamplePoolInterface*> getPools() const;
72 
73  void addPool(SamplePoolInterface* pool);
74 
75  void removePool(SamplePoolInterface* pool);
76 
77 private:
79 
80  ~SamplePools();
81 
83 
85 
87 
88  std::list<SamplePoolInterface*> _pools;
89 };
90 
97 template <typename SampleType>
99 {
100 public:
101 
105  static SamplePool *getInstance();
106 
110  static void deleteInstance();
111 
115  SampleType *getSample(unsigned int len) throw(SampleLengthException);
116 
120  void putSample(const SampleType *);
121 
122  int getNSamplesAlloc() const { return _nsamplesAlloc; }
123 
124  int getNSamplesOut() const { return _nsamplesOut; }
125 
126  int getNSmallSamplesIn() const { return _nsmall; }
127 
128  int getNMediumSamplesIn() const { return _nmedium; }
129 
130  int getNLargeSamplesIn() const { return _nlarge; }
131 
132 private:
133 
134  SamplePool();
135 
136  ~SamplePool();
137 
139 
141 
142  SampleType *getSample(SampleType** vec,int *veclen, unsigned int len)
143  throw(SampleLengthException);
144  void putSample(const SampleType *,SampleType*** vecp,int *veclen, int* nalloc);
145 
146  SampleType** _smallSamples;
147  SampleType** _mediumSamples;
148  SampleType** _largeSamples;
149 
153 
155 
159  const static unsigned int SMALL_SAMPLE_MAXSIZE = 64;
160 
164  const static unsigned int MEDIUM_SAMPLE_MAXSIZE = 512;
165 
169  SamplePool(const SamplePool&);
170 
175 
176 public:
177  int _nsmall;
178  int _nmedium;
179  int _nlarge;
180 
182 
184 
185 };
186 
187 /* static */
188 template<class SampleType>
190 
191 /* static */
192 template<class SampleType>
194 
195 /* static */
196 template<class SampleType>
198 {
199  if (!_instance) {
200  nidas::util::Synchronized pooler(_instanceLock);
201  if (!_instance) {
202  _instance = new SamplePool<SampleType>();
203  SamplePools::getInstance()->addPool(_instance);
204  }
205  }
206  return _instance;
207 }
208 
209 /* static */
210 template<class SampleType>
212 {
213  nidas::util::Synchronized pooler(_instanceLock);
214  delete _instance;
215  _instance = 0;
216 }
217 
218 template<class SampleType>
220  _smallSamples(0), _mediumSamples(0), _largeSamples(0),
221  _smallSize(0), _mediumSize(0), _largeSize(0),
222  _poolLock(),
223  _nsmall(0),_nmedium(0),_nlarge(0),_nsamplesOut(0),_nsamplesAlloc(0)
224 {
225  // Initial size of pool of small samples around 16K bytes
226  _smallSize = 16384 / (sizeof(SampleType) + SMALL_SAMPLE_MAXSIZE * SampleType::sizeofDataType());
227  // When we expand the size of the pool, we expand by 50%
228  // so minimum size should be at least 2.
229  if (_smallSize < 2) _smallSize = 2;
230 
232  if (_mediumSize < 2) _mediumSize = 2;
233 
234  _largeSize = _mediumSize / 2;
235  if (_largeSize < 2) _largeSize = 2;
236 
237  _smallSamples = new SampleType*[_smallSize];
238  _mediumSamples = new SampleType*[_mediumSize];
239  _largeSamples = new SampleType*[_largeSize];
240 #ifdef DEBUG
241  DLOG(("nsmall=%d, nmedium=%d, nlarge=%d",_smallSize,_mediumSize, _largeSize));
242 #endif
243 }
244 
245 template<class SampleType>
247  int i;
248  for (i = 0; i < _nsmall; i++) delete _smallSamples[i];
249  delete [] _smallSamples;
250  for (i = 0; i < _nmedium; i++) delete _mediumSamples[i];
251  delete [] _mediumSamples;
252  for (i = 0; i < _nlarge; i++) delete _largeSamples[i];
253  delete [] _largeSamples;
255 }
256 
257 template<class SampleType>
258 SampleType* SamplePool<SampleType>::getSample(unsigned int len)
260 {
261 
262  nidas::util::Synchronized pooler(_poolLock);
263 
264  // Shouldn't get back more than I've dealt out
265  // If we do, that's an indication that reference counting
266  // is screwed up.
267 
268  assert(_nsamplesOut >= 0);
269 
270  // conservation of sample numbers:
271  // total number allocated must equal:
272  // number in the pool (_nsmall + _nmedium + _nlarge), plus
273  // number held by others.
274  assert(_nsamplesAlloc == _nsmall + _nmedium + _nlarge + _nsamplesOut);
275 
276  // get a sample from the appropriate pool, unless is is empty
277  // and there are 2 or more available from the next larger pool.
278  if (len < SMALL_SAMPLE_MAXSIZE && (_nsmall > 0 ||
279  (_nmedium + _nlarge) < 4))
280  return getSample((SampleType**)_smallSamples,&_nsmall,len);
281  else if (len < MEDIUM_SAMPLE_MAXSIZE && (_nmedium > 0 || _nlarge < 2))
282  return getSample((SampleType**)_mediumSamples,&_nmedium,len);
283  else return getSample((SampleType**)_largeSamples,&_nlarge,len);
284 }
285 
286 template<class SampleType>
287 SampleType* SamplePool<SampleType>::getSample(SampleType** vec,
288  int *n, unsigned int len) throw(SampleLengthException)
289 {
290 
291  SampleType *sample;
292 #ifdef DEBUG
293  std::cerr << "getSample, this=" << std::hex << this <<
294  " pool=" << vec << std::dec <<
295  " *n=" << *n << std::endl;
296 #endif
297  int i = *n - 1;
298 
299  if (i >= 0) {
300  sample = vec[i];
301  if (sample->getAllocLength() < len) sample->allocateData(len);
302 #ifndef NDEBUG
303  else if (sample->getAllocLength() > len) {
304  // If the sample has been previously allocated, and its length
305  // is at least one more than we need, set the one-past-the-end
306  // data value to a noticable value. Then if a buggy process method
307  // reads past the end of a sample, they'll get a value that should
308  // raise questions about the results, rather than something
309  // that might go unnoticed.
310 
311  // valgrind won't complain in these situations unless one reads
312  // past the allocated size.
313 
314  // For character data (sizeof(T) == 1), we'll use up to
315  // 4 '\x80's as the weird value.
316  // For larger sizes, we'll use floatNAN. This will convert to
317  // 0 for integer samples.
318 
319  extern const float floatNAN;
320 
321  if (sample->sizeofDataType() == 1) {
322  static const char weird[4] = { '\x80','\x80','\x80','\x80' };
323  int nb = std::min(4U,sample->getAllocLength()-len);
324  memcpy((char*)sample->getVoidDataPtr()+len,weird,nb);
325  }
326  else sample->setDataValue(len,floatNAN); // NAN converted to the data type.
327  }
328 #endif
329  sample->setDataLength(len);
330  *n = i;
331  sample->holdReference();
332  _nsamplesOut++;
333  return sample;
334  }
335 
336  sample = new SampleType();
337  sample->allocateData(len);
338  sample->setDataLength(len);
339  _nsamplesAlloc++;
340  _nsamplesOut++;
341  return sample;
342 
343 }
344 
345 template<class SampleType>
346 void SamplePool<SampleType>::putSample(const SampleType *sample) {
347 
348  nidas::util::Synchronized pooler(_poolLock);
349 
350  assert(_nsamplesOut >= 0);
351  assert(_nsamplesAlloc == _nsmall + _nmedium + _nlarge + _nsamplesOut);
352 
353  unsigned int len = sample->getAllocLength();
354  if (len < SMALL_SAMPLE_MAXSIZE) {
355 #ifdef DEBUG
356  DLOG(("put small sample, len=%d,bytelen=%d,n=%d,size=%d",len,sample->getAllocByteLength(),_nsmall,_smallSize));
357 #endif
358  putSample(sample,(SampleType***)&_smallSamples,&_nsmall,&_smallSize);
359  }
360  else if (len < MEDIUM_SAMPLE_MAXSIZE) {
361 #ifdef DEBUG
362  DLOG(("put medium sample, len=%d,bytelen=%d,n=%d,size=%d",len,sample->getAllocByteLength(),_nmedium,_mediumSize));
363 #endif
364  putSample(sample,(SampleType***)&_mediumSamples,&_nmedium,&_mediumSize);
365  }
366  else {
367 #ifdef DEBUG
368  DLOG(("put large sample, len=%d,bytelen=%d,n=%d,size=%d",len,sample->getAllocByteLength(),_nlarge,_largeSize));
369 #endif
370  putSample(sample,(SampleType***)&_largeSamples,&_nlarge,&_largeSize);
371  }
372 }
373 
374 template<class SampleType>
375 void SamplePool<SampleType>::putSample(const SampleType *sample,
376  SampleType ***vec,int *n, int *nalloc)
377 {
378 
379  // increase by 50%
380  if (*n == *nalloc) {
381  // cerr << "reallocing, n=" << *n << " nalloc=" << *nalloc << endl;
382  // increase by 50%
383  int newalloc = *nalloc + (*nalloc >> 1);
384 #ifdef DEBUG
385  DLOG(("*nalloc=%d, newalloc=%d",*nalloc,newalloc));
386 #endif
387  SampleType **newvec = new SampleType*[newalloc];
388  ::memcpy(newvec,*vec,*nalloc * sizeof(SampleType*));
389  delete [] *vec;
390  *vec = newvec;
391  *nalloc = newalloc;
392  }
393 
394  (*vec)[(*n)++] = (SampleType*) sample;
395  _nsamplesOut--;
396 }
397 
398 }} // namespace nidas namespace core
399 
400 #endif
SampleType * getSample(unsigned int len)
Get a sample of at least len elements from the pool.
Definition: SamplePool.h:258
virtual int getNSamplesAlloc() const =0
Synchronized is used a simple guard object for critical sections.
Definition: ThreadSupport.h:544
virtual int getNMediumSamplesIn() const =0
nidas::util::Mutex _poolLock
Definition: SamplePool.h:154
void putSample(const SampleType *)
Return a sample to the pool.
Definition: SamplePool.h:346
int getNSmallSamplesIn() const
Definition: SamplePool.h:126
SampleType ** _smallSamples
Definition: SamplePool.h:146
~SamplePool()
Definition: SamplePool.h:246
SamplePools()
Definition: SamplePool.h:78
int _nsamplesAlloc
Definition: SamplePool.h:183
static SamplePool * getInstance()
Get a pointer to the singleton instance.
Definition: SamplePool.h:197
void removePool(SamplePoolInterface *pool)
Definition: SamplePool.cc:86
Definition: SamplePool.h:42
virtual int getNSamplesOut() const =0
static void deleteInstance()
Definition: SamplePool.cc:53
const float floatNAN
Value of a float NAN for general use.
Definition: Sample.cc:31
static SamplePool * _instance
Definition: SamplePool.h:138
virtual int getNLargeSamplesIn() const =0
static const unsigned int SMALL_SAMPLE_MAXSIZE
maximum number of elements in a small sample
Definition: SamplePool.h:159
int _nsamplesOut
Definition: SamplePool.h:181
~SamplePools()
Definition: SamplePool.cc:62
int _mediumSize
Definition: SamplePool.h:151
int getNLargeSamplesIn() const
Definition: SamplePool.h:130
SampleType ** _largeSamples
Definition: SamplePool.h:148
int _largeSize
Definition: SamplePool.h:152
Definition: SampleLengthException.h:35
int getNMediumSamplesIn() const
Definition: SamplePool.h:128
Sample * getSample(sampleType type, unsigned int len)
A convienence method for getting a sample of an enumerated type from a pool.
Definition: Sample.cc:70
int getNSamplesAlloc() const
Definition: SamplePool.h:122
SampleType ** _mediumSamples
Definition: SamplePool.h:147
static SamplePools * getInstance()
Definition: SamplePool.cc:43
int len
Definition: sing.cc:934
int _nmedium
Definition: SamplePool.h:178
static void deleteInstance()
Singleton cleanup on program exit.
Definition: SamplePool.h:211
Header file for the nidas::util logging facility.
static const unsigned int MEDIUM_SAMPLE_MAXSIZE
maximum number of elements in a medium sized sample
Definition: SamplePool.h:164
std::list< SamplePoolInterface * > getPools() const
Get a copy of the current list of SamplePools.
Definition: SamplePool.cc:74
int _nlarge
Definition: SamplePool.h:179
static SamplePools * _instance
Definition: SamplePool.h:82
Definition: SamplePool.h:56
std::list< SamplePoolInterface * > _pools
Definition: SamplePool.h:88
static nidas::util::Mutex _instanceLock
Definition: SamplePool.h:140
void addPool(SamplePoolInterface *pool)
Definition: SamplePool.cc:80
A pool of Samples.
Definition: SamplePool.h:98
static nidas::util::Mutex _instanceLock
Definition: SamplePool.h:84
int getNSamplesOut() const
Definition: SamplePool.h:124
nidas::util::Mutex _poolsLock
Definition: SamplePool.h:86
int _nsmall
Definition: SamplePool.h:177
virtual ~SamplePoolInterface()
Definition: SamplePool.h:45
virtual int getNSmallSamplesIn() const =0
#define DLOG(MSG)
Definition: Logger.h:306
A C++ wrapper for a POSIX mutex.
Definition: ThreadSupport.h:154
int _smallSize
Definition: SamplePool.h:150
SamplePool()
Definition: SamplePool.h:219
SamplePool & operator=(const SamplePool &)
No assignment.