blitz Version 1.0.2
Loading...
Searching...
No Matches
memblock.h
Go to the documentation of this file.
1// -*- C++ -*-
2/***************************************************************************
3 * blitz/memblock.h MemoryBlock<T> and MemoryBlockReference<T>
4 *
5 * $Id$
6 *
7 * Copyright (C) 1997-2011 Todd Veldhuizen <tveldhui@acm.org>
8 *
9 * This file is a part of Blitz.
10 *
11 * Blitz is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation, either version 3
14 * of the License, or (at your option) any later version.
15 *
16 * Blitz is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with Blitz. If not, see <http://www.gnu.org/licenses/>.
23 *
24 * Suggestions: blitz-devel@lists.sourceforge.net
25 * Bugs: blitz-support@lists.sourceforge.net
26 *
27 * For more information, please see the Blitz++ Home Page:
28 * https://sourceforge.net/projects/blitz/
29 *
30 ***************************************************************************/
31
32#ifndef BZ_MEMBLOCK_H
33#define BZ_MEMBLOCK_H
34
35#include <blitz/blitz.h>
36#include <blitz/simdtypes.h>
37#ifdef BZ_HAVE_BOOST_SERIALIZATION
38#include <boost/serialization/serialization.hpp>
39#include <boost/serialization/base_object.hpp>
40#include <boost/serialization/split_member.hpp>
41#include <boost/serialization/array.hpp>
42#include <boost/serialization/collection_size_type.hpp>
43#include <boost/serialization/nvp.hpp>
44#endif
45#include <stddef.h> // diffType
46
47namespace blitz {
48
54
55// This function makes it possible for users to make sure threadsafety
56// is enabled.
57inline bool isThreadsafe() {
58#ifdef BZ_THREADSAFE
59 return true;
60#else
61 return false;
62#endif
63};
64
65
66// Forward declaration of MemoryBlockReference
67template<typename T_type> class MemoryBlockReference;
68
69// Class MemoryBlock provides a reference-counted block of memory. This block
70// may be referred to by multiple vector, matrix and array objects. The memory
71// is automatically deallocated when the last referring object is destructed.
72// MemoryBlock may be subclassed to provide special allocators.
73template<typename P_type>
75
76 friend class MemoryBlockReference<P_type>;
77
78public:
79 typedef P_type T_type;
80
81protected:
82 explicit MemoryBlock(sizeType items)
83 {
84 // pad the length to vecWidth, if not already done
85 const int w = simdTypes<T_type>::vecWidth;
86 const int mod = items%w;
87 if (mod>0)
88 items += simdTypes<T_type>::vecWidth-mod;
89 BZASSERT(items%w==0);
90
91 length_ = items;
93
94 BZASSERT(dataBlockAddress_ != 0);
95
96 references_ = 1;
97 BZ_MUTEX_INIT(mutex)
98 }
99
103 {
104 length_ = length;
105 data_ = data;
107 references_ = 1;
108 BZ_MUTEX_INIT(mutex);
109 allocatedByUs_ = false;
110 }
111
112 virtual ~MemoryBlock()
113 {
115 {
116#ifdef BZ_DEBUG_LOG_ALLOCATIONS
117 cout << "MemoryBlock: freed " << setw(8) << length_
118 << " at " << ((void *)dataBlockAddress_) << endl;
119#endif
120
121 deallocate();
122 }
123
124 BZ_MUTEX_DESTROY(mutex)
125 }
126
127 // set mutex locking policy and return true if successful
128 bool doLock(bool lockingPolicy)
129 {
130#if defined(BZ_THREADSAFE) && !defined(BZ_THREADSAFE_USE_ATOMIC)
131 if (mutexLocking_ == lockingPolicy) { // already set
132 return true;
133 }
134 else if (references_ <= 1) { // no multiple references, safe to change
135 mutexLocking_ = lockingPolicy;
136 return true;
137 }
138 return false; // unsafe to change
139#elif defined(BZ_THREADSAFE_USE_ATOMIC)
140 // with locking we consider the request successful
141 return true;
142#else
143 // without threadsafety we return false if user wants to enable locking
144 return !lockingPolicy;
145#endif
146 }
147
148 /* Note that the the MemoryBlock will be created with reference
149 count 1, so there is no need to call addReference immediately
150 upon creating it. (The creator obviously does have to call
151 removeReference, though.) This avoids the initial mutex lock. */
153 {
154#ifdef BZ_DEBUG_LOG_REFERENCES
155 BZ_MUTEX_LOCK(mutex)
156 const int refcount = ++references_;
157 BZ_MUTEX_UNLOCK(mutex)
158
159 cout << "MemoryBlock: reffed " << setw(8) << length_
160 << " at " << ((void *)dataBlockAddress_) << " (r="
161 << refcount << ")" << endl;
162#else
163 BZ_MUTEX_LOCK(mutex)
164 ++references_;
165 BZ_MUTEX_UNLOCK(mutex)
166#endif
167 }
168
170 {
171 return data_;
172 }
173
174 const T_type* restrict data() const
175 {
176 return data_;
177 }
178
180 {
181 return dataBlockAddress_;
182 }
183
185 {
186 return length_;
187 }
188
190 {
191
192 BZ_MUTEX_LOCK(mutex)
193 const int refcount = --references_;
194 BZ_MUTEX_UNLOCK(mutex)
195
196#ifdef BZ_DEBUG_LOG_REFERENCES
197 cout << "MemoryBlock: dereffed " << setw(8) << length_
198 << " at " << ((void *)dataBlockAddress_) << " (r=" << refcount
199 << ")" << endl;
200#endif
201 return refcount;
202 }
203
204 int references() const
205 {
206 BZ_MUTEX_LOCK(mutex)
207 const int refcount = references_;
208 BZ_MUTEX_UNLOCK(mutex)
209
210 return refcount;
211 }
212
213protected:
216
217private: // Disabled member functions
219
221
224#ifdef BZ_HAVE_BOOST_SERIALIZATION
225 friend class boost::serialization::access;
226
227
231 template<class T_arch>
232 void save(T_arch& ar, const unsigned int version) const {
233#if defined(BZ_THREADSAFE) && !defined(BZ_THREADSAFE_USE_ATOMIC)
234 ar << mutexLocking_;
235#endif
236 const boost::serialization::collection_size_type count(length_);
237 ar << BOOST_SERIALIZATION_NVP(count);
238#ifdef BZ_DEBUG_LOG_ALLOCATIONS
239 cout << "MemoryBlock: serializing " << length_ << " data for MemoryBlock at "
240 << ((void*)this) << endl;
241#endif
242 if(length_>0)
243 ar << boost::serialization::make_array(data_, length_);
244 };
245
246 template<class T_arch>
247 void load(T_arch& ar, const unsigned int version) {
248#if defined(BZ_THREADSAFE) && !defined(BZ_THREADSAFE_USE_ATOMIC)
249 ar >> mutexLocking_;
250#endif
251 boost::serialization::collection_size_type count(length_);
252 ar >> BOOST_SERIALIZATION_NVP(count);
253 length_=count;
255
256#ifdef BZ_DEBUG_LOG_ALLOCATIONS
257 cout << "MemoryBlock: unserializing " << length_ << " data for MemoryBlock at "
258 << ((void*)this) << endl;
259#endif
260
261 if(length_>0)
262 ar >> boost::serialization::make_array(data_, length_);
263
264 // initialize the members that are not restored. Note that we
265 // must initialize references_ to 0 here because the
266 // unserialization always adds a reference since the creation of
267 // the MemoryBlock object happens by the boost::serialization
268 // magic.
269 references_ = 0;
270 BZ_MUTEX_INIT(mutex);
271 };
272
273 BOOST_SERIALIZATION_SPLIT_MEMBER()
274#endif
275
276
277private: // Data members
278#if defined(BZ_THREADSAFE) && !defined(BZ_THREADSAFE_USE_ATOMIC)
279 // with atomic reference counts, there is no locking
280 bool mutexLocking_;
281#endif
286
287 union {
291 };
292 union {
295 char * dBA_char_;
296 };
298
299 BZ_REFCOUNT_DECLARE(references_)
300 BZ_MUTEX_DECLARE(mutex)
301};
302
303
304
305
306template<typename P_type>
308
309public:
310 typedef P_type T_type;
311
312protected:
314
315private:
317
318#ifdef BZ_HAVE_BOOST_SERIALIZATION
319 friend class boost::serialization::access;
320
328 template<class T_arch>
329 void save(T_arch& ar, const unsigned int version) const {
330#ifdef BZ_DEBUG_LOG_ALLOCATIONS
331 cout << "MemoryBlockReference: serializing object at " << ((void*)this) << ", MemoryBlock at "
332 << ((void*)block_) <<endl;
333#endif
334 ar << block_;
335 ptrdiff_t ptroffset=0;
336 if(block_)
337 ptroffset = data_ - block_->data();
338 boost::serialization::collection_size_type
339 offset(*reinterpret_cast<size_t*>(&ptroffset));
340 ar << BOOST_SERIALIZATION_NVP(offset);
341 };
342
346 template<class T_arch>
347 void load(T_arch& ar, const unsigned int version) {
348#ifdef BZ_DEBUG_LOG_ALLOCATIONS
349 cout << "MemoryBlockReference: unserializing at " << ((void*)this) << endl;
350#endif
351 ar >> block_;
352 addReference();
353 boost::serialization::collection_size_type offset;
354 ar >> BOOST_SERIALIZATION_NVP(offset);
355 ptrdiff_t ptroffset = *reinterpret_cast<ptrdiff_t*>(&offset);
356 if(block_)
357 data_ = block_->data() + ptroffset;
358 else
359 data_ = 0;
360 };
361
362 BOOST_SERIALIZATION_SPLIT_MEMBER()
363#endif
364
365public:
366
368 {
369 block_ = 0;
370 // no block, so nothing to add reference to
371 data_ = 0;
372 }
373
375 {
376 block_ = ref.block_;
377 addReference();
378 data_ = ref.data_ + offset;
379 }
380
382 preexistingMemoryPolicy deletionPolicy)
383 {
384 // Create a memory block using already allocated memory.
385
386 // Note: if the deletionPolicy is duplicateData, this must
387 // be handled by the leaf class. In MemoryBlockReference,
388 // this is treated as neverDeleteData; the leaf class (e.g. Array)
389 // must duplicate the data.
390
391 if ((deletionPolicy == neverDeleteData)
392 || (deletionPolicy == duplicateData)) {
393 // in this case, we do not need a MemoryBlock to ref-count the data
394 block_ = 0;
395 }
396 else if (deletionPolicy == deleteDataWhenDone) {
397 block_ = new MemoryBlock<T_type>(length, data);
398
399#ifdef BZ_DEBUG_LOG_ALLOCATIONS
400 cout << "MemoryBlockReference: created MemoryBlock at "
401 << ((void*)block_) << endl;
402#endif
403 }
404 // creating a MemoryBlock automatically sets it to one
405 // reference, so we do no longer need to add a reference in
406 // the constructor.
407
408 data_ = data;
409 }
410
412 {
413 block_ = new MemoryBlock<T_type>(items);
414 // creating a MemoryBlock automatically sets it to one
415 // reference, so we do no longer need to add a reference in
416 // the constructor.
417 data_ = block_->data();
418
419#ifdef BZ_DEBUG_LOG_ALLOCATIONS
420 cout << "MemoryBlockReference: created MemoryBlock at "
421 << ((void*)block_) << endl;
422#endif
423 }
424
429
431 bool isVectorAligned(size_t offset) const
432 { return simdTypes<T_type>::isVectorAligned(data_ + offset); }
433
435 sizeType blockLength() const { return block_->length(); };
436
437protected:
438#ifdef BZ_TESTSUITE
439public:
440#endif
441 int numReferences() const
442 {
443 if (block_)
444 return block_->references();
445#ifdef BZ_DEBUG_LOG_REFERENCES
446 cout << "Invalid reference count for data at "<< data_ << endl;
447#endif
448 return -1;
449 }
450
451 bool lockReferenceCount(bool lockingPolicy) const
452 {
453 if (block_)
454 return block_->doLock(lockingPolicy);
455 // if we have no block, consider request successful
456#ifdef BZ_DEBUG_LOG_REFERENCES
457 cout << "No reference count locking for data at "<< data_ << endl;
458#endif
459 return true;
460 }
461
463 {
465 block_ = 0;
466 // no block, so nothing to add reference to
467 data_ = 0;
468 }
469
471 {
473 block_ = ref.block_;
474 addReference();
475 data_ = ref.data_ + offset;
476 }
477
478 void newBlock(sizeType items)
479 {
481 block_ = new MemoryBlock<T_type>(items);
482 // creating a memory block automatically sets it to one reference
483 data_ = block_->data();
484
485#ifdef BZ_DEBUG_LOG_ALLOCATIONS
486 cout << "MemoryBlockReference: created MemoryBlock at "
487 << ((void*)block_) << endl;
488#endif
489 }
490
491private:
493 {
494 const int refcount = removeReference();
495 if (refcount == 0)
496 {
497#ifdef BZ_DEBUG_LOG_ALLOCATIONS
498 cout << "MemoryBlockReference: no more refs, delete MemoryBlock object at "
499 << ((void*)block_) << endl;
500#endif
501
502 delete block_;
503 }
504 }
505
506 void addReference() const
507 {
508 if (block_) {
509#ifdef BZ_DEBUG_LOG_REFERENCES
510 cout << "MemoryBlockReference: reffing block at " << ((void*)block_)
511 << endl;
512#endif
514 }
515 else {
516#ifdef BZ_DEBUG_LOG_REFERENCES
517 cout << "MemoryBlockReference:: Skipping reference count for data at "<< data_ << endl;
518#endif
519 }
520 };
521
522 int removeReference() const
523 {
524 if (block_) {
525#ifdef BZ_DEBUG_LOG_REFERENCES
526 cout << "MemoryBlockReference: dereffing block at " << ((void*)block_)
527 << endl;
528#endif
529 return block_->removeReference();
530 }
531#ifdef BZ_DEBUG_LOG_REFERENCES
532 cout << "Skipping reference count for data at "<< data_ << endl;
533#endif
534 return -1;
535 };
536
539};
540
541
542}
543
544#include <blitz/memblock.cc>
545
546#endif // BZ_MEMBLOCK_H
#define BZ_MUTEX_DESTROY(name)
Definition blitz.h:193
#define BZ_MUTEX_UNLOCK(name)
Definition blitz.h:192
#define BZ_MUTEX_LOCK(name)
Definition blitz.h:191
#define BZ_MUTEX_INIT(name)
Definition blitz.h:190
#define BZ_MUTEX_DECLARE(name)
Definition blitz.h:189
#define BZ_REFCOUNT_DECLARE(name)
Definition blitz.h:156
Definition memblock.h:307
P_type T_type
Definition memblock.h:310
MemoryBlock< T_type > * block_
Definition memblock.h:316
int numReferences() const
Definition memblock.h:441
MemoryBlockReference()
Definition memblock.h:367
int removeReference() const
Definition memblock.h:522
~MemoryBlockReference()
Definition memblock.h:425
void changeToNullBlock()
Definition memblock.h:462
void blockRemoveReference()
Definition memblock.h:492
void addReference() const
Definition memblock.h:506
void newBlock(sizeType items)
Definition memblock.h:478
void operator=(const MemoryBlockReference< T_type > &)
Definition memblock.h:537
bool isVectorAligned(size_t offset) const
Returns true if the offset from data_ is vector aligned.
Definition memblock.h:431
bool lockReferenceCount(bool lockingPolicy) const
Definition memblock.h:451
MemoryBlockReference(MemoryBlockReference< T_type > &ref, sizeType offset=0)
Definition memblock.h:374
MemoryBlockReference(sizeType items)
Definition memblock.h:411
void changeBlock(MemoryBlockReference< T_type > &ref, sizeType offset=0)
Definition memblock.h:470
T_type *restrict data_
Definition memblock.h:313
MemoryBlockReference(sizeType length, T_type *data, preexistingMemoryPolicy deletionPolicy)
Definition memblock.h:381
sizeType blockLength() const
Returns the allocated length of the memory block.
Definition memblock.h:435
Definition memblock.h:74
bool doLock(bool lockingPolicy)
Definition memblock.h:128
simdTypes< T_type >::vecType *restrict dBA_tv_
Definition memblock.h:294
T_type *restrict data()
Definition memblock.h:169
T_type *restrict data_
Definition memblock.h:288
char *restrict data_char_
Definition memblock.h:290
T_type *& dataBlockAddress()
Definition memblock.h:179
MemoryBlock(sizeType length, T_type *data)
Constructor for a preallocated block that should be deleted when we are done?
Definition memblock.h:102
const T_type *restrict data() const
Definition memblock.h:174
int references() const
Definition memblock.h:204
void allocate(sizeType length)
void addReference()
Definition memblock.h:152
MemoryBlock(sizeType items)
Definition memblock.h:82
bool allocatedByUs_
Keeps track of whether the block was preallocated or not.
Definition memblock.h:285
MemoryBlock()
The default constructor is needed for serialization.
Definition memblock.h:223
int removeReference()
Definition memblock.h:189
T_type * dataBlockAddress_
Definition memblock.h:293
MemoryBlock(const MemoryBlock< T_type > &)
Definition memblock.h:218
simdTypes< T_type >::vecType *restrict data_tv_
Definition memblock.h:289
virtual ~MemoryBlock()
Definition memblock.h:112
P_type T_type
Definition memblock.h:79
sizeType length() const
Definition memblock.h:184
char * dBA_char_
Definition memblock.h:295
sizeType length_
Definition memblock.h:297
void operator=(const MemoryBlock< T_type > &)
Definition memblock.h:220
The TinyVector class is a one-dimensional, fixed length vector that implements the blitz expression t...
Definition tinyvec2.h:73
Helper class that defines the width of the simd instructions for a given type.
Definition simdtypes.h:31
static bool isVectorAligned(const T *restrict pointer)
Test if a pointer to T is simd aligned.
Definition simdtypes.h:46
#define restrict
Definition compiler.h:95
Definition array-impl.h:66
bool isThreadsafe()
Definition memblock.h:57
size_t sizeType
Definition blitz.h:110
preexistingMemoryPolicy
Definition memblock.h:49
@ deleteDataWhenDone
Definition memblock.h:51
@ duplicateData
Definition memblock.h:50
@ neverDeleteData
Definition memblock.h:52