nidas v1.2.3
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
32#include <nidas/util/Logger.h>
33
34#include <cassert>
35#include <cstring> // memcpy()
36#include <vector>
37#include <list>
38#include <iostream>
39
40namespace nidas { namespace core {
41
43{
44public:
45 virtual int getNSamplesAlloc() const = 0;
46 virtual int getNSamplesOut() const = 0;
47 virtual int getNSmallSamplesIn() const = 0;
48 virtual int getNMediumSamplesIn() const = 0;
49 virtual int getNLargeSamplesIn() const = 0;
50
58 virtual void deletePoolInstance() = 0;
59
60protected:
68
69};
70
72{
73public:
74 static SamplePools* getInstance();
75
76 static void deleteInstance();
77
86 std::list<SamplePoolInterface*> getPools() const;
87
88 void addPool(SamplePoolInterface* pool);
89
91
92private:
94
96
98
100
102
103 std::list<SamplePoolInterface*> _pools;
104};
105
112template <typename SampleType>
114{
115public:
116
120 static SamplePool *getInstance();
121
125 static void deleteInstance();
126
135
139 SampleType *getSample(unsigned int len);
140
144 void putSample(const SampleType *);
145
146 int getNSamplesAlloc() const { return _nsamplesAlloc; }
147
148 int getNSamplesOut() const { return _nsamplesOut; }
149
150 int getNSmallSamplesIn() const { return _nsmall; }
151
152 int getNMediumSamplesIn() const { return _nmedium; }
153
154 int getNLargeSamplesIn() const { return _nlarge; }
155
156private:
157
158 SamplePool();
159
160 ~SamplePool();
161
163
165
166 SampleType *getSample(SampleType** vec,int *veclen, unsigned int len);
167 void putSample(const SampleType *,SampleType*** vecp,int *veclen, int* nalloc);
168
169 SampleType** _smallSamples;
170 SampleType** _mediumSamples;
171 SampleType** _largeSamples;
172
176
178
182 const static unsigned int SMALL_SAMPLE_MAXSIZE = 64;
183
187 const static unsigned int MEDIUM_SAMPLE_MAXSIZE = 512;
188
193
198
199public:
203
205
207
208};
209
210/* static */
211template<class SampleType>
212 SamplePool<SampleType>* SamplePool<SampleType>::_instance = 0;
213
214/* static */
215template<class SampleType>
217
218/* static */
219template<class SampleType>
220SamplePool<SampleType> *SamplePool<SampleType>::getInstance()
221{
222 if (!_instance) {
223 nidas::util::Synchronized pooler(_instanceLock);
224 if (!_instance) {
225 _instance = new SamplePool<SampleType>();
226 SamplePools::getInstance()->addPool(_instance);
227 }
228 }
229 return _instance;
230}
231
232/* static */
233template<class SampleType>
235{
236 nidas::util::Synchronized pooler(_instanceLock);
237 delete _instance;
238 _instance = 0;
239}
240
241template<class SampleType>
243 _smallSamples(0), _mediumSamples(0), _largeSamples(0),
244 _smallSize(0), _mediumSize(0), _largeSize(0),
245 _poolLock(),
246 _nsmall(0),_nmedium(0),_nlarge(0),_nsamplesOut(0),_nsamplesAlloc(0)
247{
248 // Initial size of pool of small samples around 16K bytes
249 _smallSize = 16384 / (sizeof(SampleType) + SMALL_SAMPLE_MAXSIZE * SampleType::sizeofDataType());
250 // When we expand the size of the pool, we expand by 50%
251 // so minimum size should be at least 2.
252 if (_smallSize < 2) _smallSize = 2;
253
255 if (_mediumSize < 2) _mediumSize = 2;
256
258 if (_largeSize < 2) _largeSize = 2;
259
260 _smallSamples = new SampleType*[_smallSize];
261 _mediumSamples = new SampleType*[_mediumSize];
262 _largeSamples = new SampleType*[_largeSize];
263#ifdef DEBUG
264 DLOG(("nsmall=%d, nmedium=%d, nlarge=%d",_smallSize,_mediumSize, _largeSize));
265#endif
266}
267
268template<class SampleType>
270 int i;
271 for (i = 0; i < _nsmall; i++) delete _smallSamples[i];
272 delete [] _smallSamples;
273 for (i = 0; i < _nmedium; i++) delete _mediumSamples[i];
274 delete [] _mediumSamples;
275 for (i = 0; i < _nlarge; i++) delete _largeSamples[i];
276 delete [] _largeSamples;
277 SamplePools::getInstance()->removePool(this);
278}
279
280template<class SampleType>
281SampleType* SamplePool<SampleType>::getSample(unsigned int len)
282{
283
285
286 // Shouldn't get back more than I've dealt out
287 // If we do, that's an indication that reference counting
288 // is screwed up.
289
290 assert(_nsamplesOut >= 0);
291
292 // conservation of sample numbers:
293 // total number allocated must equal:
294 // number in the pool (_nsmall + _nmedium + _nlarge), plus
295 // number held by others.
296 assert(_nsamplesAlloc == _nsmall + _nmedium + _nlarge + _nsamplesOut);
297
298 // get a sample from the appropriate pool, unless is is empty
299 // and there are 2 or more available from the next larger pool.
300 if (len < SMALL_SAMPLE_MAXSIZE && (_nsmall > 0 ||
301 (_nmedium + _nlarge) < 4))
302 return getSample((SampleType**)_smallSamples,&_nsmall,len);
303 else if (len < MEDIUM_SAMPLE_MAXSIZE && (_nmedium > 0 || _nlarge < 2))
304 return getSample((SampleType**)_mediumSamples,&_nmedium,len);
305 else return getSample((SampleType**)_largeSamples,&_nlarge,len);
306}
307
308template<class SampleType>
309SampleType* SamplePool<SampleType>::getSample(SampleType** vec,
310 int *n, unsigned int len)
311{
312
313 SampleType *sample;
314#ifdef DEBUG
315 std::cerr << "getSample, this=" << std::hex << this <<
316 " pool=" << vec << std::dec <<
317 " *n=" << *n << std::endl;
318#endif
319 int i = *n - 1;
320
321 if (i >= 0) {
322 sample = vec[i];
323 if (sample->getAllocLength() < len) sample->allocateData(len);
324#ifndef NDEBUG
325 else if (sample->getAllocLength() > len) {
326 // If the sample has been previously allocated, and its length
327 // is at least one more than we need, set the one-past-the-end
328 // data value to a noticable value. Then if a buggy process method
329 // reads past the end of a sample, they'll get a value that should
330 // raise questions about the results, rather than something
331 // that might go unnoticed.
332
333 // valgrind won't complain in these situations unless one reads
334 // past the allocated size.
335
336 // For character data (sizeof(T) == 1), we'll use up to
337 // 4 '\x80's as the weird value.
338 // For larger sizes, we'll use floatNAN. This will convert to
339 // 0 for integer samples.
340
341 extern const float floatNAN;
342
343 if (sample->sizeofDataType() == 1) {
344 static const char weird[4] = { '\x80','\x80','\x80','\x80' };
345 int nb = std::min(4U,sample->getAllocLength()-len);
346 memcpy((char*)sample->getVoidDataPtr()+len,weird,nb);
347 }
348 else sample->setDataValue(len,floatNAN); // NAN converted to the data type.
349 }
350#endif
351 sample->setDataLength(len);
352 *n = i;
353 sample->holdReference();
354 _nsamplesOut++;
355 return sample;
356 }
357
358 sample = new SampleType();
359 sample->allocateData(len);
360 sample->setDataLength(len);
361 _nsamplesAlloc++;
362 _nsamplesOut++;
363 return sample;
364
365}
366
367template<class SampleType>
368void SamplePool<SampleType>::putSample(const SampleType *sample) {
369
371
372 assert(_nsamplesOut >= 0);
373 assert(_nsamplesAlloc == _nsmall + _nmedium + _nlarge + _nsamplesOut);
374
375 unsigned int len = sample->getAllocLength();
376 if (len < SMALL_SAMPLE_MAXSIZE) {
377#ifdef DEBUG
378 DLOG(("put small sample, len=%d,bytelen=%d,n=%d,size=%d",len,sample->getAllocByteLength(),_nsmall,_smallSize));
379#endif
380 putSample(sample,(SampleType***)&_smallSamples,&_nsmall,&_smallSize);
381 }
382 else if (len < MEDIUM_SAMPLE_MAXSIZE) {
383#ifdef DEBUG
384 DLOG(("put medium sample, len=%d,bytelen=%d,n=%d,size=%d",len,sample->getAllocByteLength(),_nmedium,_mediumSize));
385#endif
386 putSample(sample,(SampleType***)&_mediumSamples,&_nmedium,&_mediumSize);
387 }
388 else {
389#ifdef DEBUG
390 DLOG(("put large sample, len=%d,bytelen=%d,n=%d,size=%d",len,sample->getAllocByteLength(),_nlarge,_largeSize));
391#endif
392 putSample(sample,(SampleType***)&_largeSamples,&_nlarge,&_largeSize);
393 }
394}
395
396template<class SampleType>
397void SamplePool<SampleType>::putSample(const SampleType *sample,
398 SampleType ***vec,int *n, int *nalloc)
399{
400
401 // increase by 50%
402 if (*n == *nalloc) {
403 // cerr << "reallocing, n=" << *n << " nalloc=" << *nalloc << endl;
404 // increase by 50%
405 int newalloc = *nalloc + (*nalloc >> 1);
406#ifdef DEBUG
407 DLOG(("*nalloc=%d, newalloc=%d",*nalloc,newalloc));
408#endif
409 SampleType **newvec = new SampleType*[newalloc];
410 ::memcpy(newvec,*vec,*nalloc * sizeof(SampleType*));
411 delete [] *vec;
412 *vec = newvec;
413 *nalloc = newalloc;
414 }
415
416 (*vec)[(*n)++] = (SampleType*) sample;
417 _nsamplesOut--;
418}
419
420}} // namespace nidas namespace core
421
422#endif
Header file for the nidas::util logging facility.
Definition SamplePool.h:43
virtual int getNSmallSamplesIn() const =0
virtual int getNSamplesAlloc() const =0
virtual int getNLargeSamplesIn() const =0
virtual int getNMediumSamplesIn() const =0
virtual void deletePoolInstance()=0
SamplePool singletons for various types and sizes are created and added to the SamplePools class thro...
virtual ~SamplePoolInterface()
Define a virtual but protected desctructor, so a SamplePoolInterface subclass cannot be deleted throu...
Definition SamplePool.h:67
virtual int getNSamplesOut() const =0
A pool of Samples.
Definition SamplePool.h:114
void deletePoolInstance()
Implementation from SamplePoolInterface which deletes the instance for this particular SamplePoolInte...
Definition SamplePool.h:131
static SamplePool * _instance
Definition SamplePool.h:162
int getNLargeSamplesIn() const
Definition SamplePool.h:154
static const unsigned int SMALL_SAMPLE_MAXSIZE
maximum number of elements in a small sample
Definition SamplePool.h:182
static SamplePool * getInstance()
Get a pointer to the singleton instance.
Definition SamplePool.h:220
int _nlarge
Definition SamplePool.h:202
SampleType ** _largeSamples
Definition SamplePool.h:171
SamplePool()
Definition SamplePool.h:242
static const unsigned int MEDIUM_SAMPLE_MAXSIZE
maximum number of elements in a medium sized sample
Definition SamplePool.h:187
int _smallSize
Definition SamplePool.h:173
SamplePool & operator=(const SamplePool &)
No assignment.
static nidas::util::Mutex _instanceLock
Definition SamplePool.h:164
void putSample(const SampleType *)
Return a sample to the pool.
Definition SamplePool.h:368
int _nsamplesOut
Definition SamplePool.h:204
int getNSamplesOut() const
Definition SamplePool.h:148
int _nsmall
Definition SamplePool.h:200
SamplePool(const SamplePool &)
No copying.
nidas::util::Mutex _poolLock
Definition SamplePool.h:177
int getNMediumSamplesIn() const
Definition SamplePool.h:152
int _largeSize
Definition SamplePool.h:175
static void deleteInstance()
Singleton cleanup on program exit.
Definition SamplePool.h:234
int getNSamplesAlloc() const
Definition SamplePool.h:146
~SamplePool()
Definition SamplePool.h:269
int getNSmallSamplesIn() const
Definition SamplePool.h:150
int _mediumSize
Definition SamplePool.h:174
int _nmedium
Definition SamplePool.h:201
SampleType ** _mediumSamples
Definition SamplePool.h:170
SampleType ** _smallSamples
Definition SamplePool.h:169
SampleType * getSample(unsigned int len)
Get a sample of at least len elements from the pool.
Definition SamplePool.h:281
int _nsamplesAlloc
Definition SamplePool.h:206
Definition SamplePool.h:72
SamplePools()
Definition SamplePool.h:93
void removePool(SamplePoolInterface *pool)
Definition SamplePool.cc:86
static nidas::util::Mutex _instanceLock
Definition SamplePool.h:99
std::list< SamplePoolInterface * > getPools() const
Get a copy of the current list of SamplePools.
Definition SamplePool.cc:74
nidas::util::Mutex _poolsLock
Definition SamplePool.h:101
~SamplePools()
Definition SamplePool.cc:62
std::list< SamplePoolInterface * > _pools
Definition SamplePool.h:103
static SamplePools * _instance
Definition SamplePool.h:97
static void deleteInstance()
Definition SamplePool.cc:53
static SamplePools * getInstance()
Definition SamplePool.cc:43
void addPool(SamplePoolInterface *pool)
Definition SamplePool.cc:80
virtual void allocateData(unsigned int val)=0
Allocate a number of bytes of data.
void holdReference() const
Increment the reference count for this sample.
Definition Sample.h:340
A C++ wrapper for a POSIX mutex.
Definition ThreadSupport.h:161
Synchronized is used a simple guard object for critical sections.
Definition ThreadSupport.h:575
#define DLOG(MSG)
Definition Logger.h:316
const float floatNAN
Value of a float NAN for general use.
Definition Sample.cc:31
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
Root namespace for the NCAR In-Situ Data Acquisition Software.
Definition A2DConverter.h:31
int len
Definition sing.cc:948