OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
LField.hpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 /***************************************************************************
3  *
4  * The IPPL Framework
5  *
6  * This program was prepared by PSI.
7  * All rights in the program are reserved by PSI.
8  * Neither PSI nor the author(s)
9  * makes any warranty, express or implied, or assumes any liability or
10  * responsibility for the use of this software
11  *
12  * Visit www.amas.web.psi for more details
13  *
14  ***************************************************************************/
15 
16 // -*- C++ -*-
17 /***************************************************************************
18  *
19  * The IPPL Framework
20  *
21  *
22  * Visit http://people.web.psi.ch/adelmann/ for more details
23  *
24  ***************************************************************************/
25 
26 // include files
27 #include "Field/LField.h"
28 
29 #include "Utility/PAssert.h"
30 #include "Utility/IpplStats.h"
31 #include "Utility/Unique.h"
32 #include <cstdlib>
33 
34 // the number of bytes in a single cache line, this is generally set
35 // by configuration options, but gets a default value if none is given
36 #ifndef IPPL_CACHE_LINE_SIZE
37 #define IPPL_CACHE_LINE_SIZE 32
38 #endif
39 
40 // the number of "offset blocks" to use. We will add a small offset
41 // to the beginning of where in each malloced storage block the LField
42 // data is stored, to try to avoid having several blocks all map to
43 // the same cache line. This is the maximum number of blocks that we
44 // will add as an offset, where each block is the size of a cache line.
45 #ifndef IPPL_OFFSET_BLOCKS
46 #define IPPL_OFFSET_BLOCKS 16
47 #endif
48 
49 // a debugging output message macro
50 #ifdef DEBUG_LFIELD
51 #define LFIELDMSG(x) x
52 #else
53 #define LFIELDMSG(x)
54 #endif
55 
56 
58 //
59 // Initialize numeric types to zero.
60 // Everything else uses the default ctor.
61 //
63 
64 template<class T>
66 {
67  static void apply(T&) {}
68 };
69 
70 #define MAKE_INITIALIZER(T) \
71 template <> \
72 struct LFieldInitializer<T> \
73 { \
74  static void apply(T& x) { x=0; } \
75 };
76 
84 MAKE_INITIALIZER(long long)
85 
87 //
88 // Construct given the sizes.
89 // This builds it compressed.
90 //
92 
93 template<class T, unsigned Dim>
94 LField<T,Dim>::LField(const NDIndex<Dim>& owned,
95  const NDIndex<Dim>& allocated,
96  int vnode)
97 : vnode_m(vnode),
98  P(0),
99  Pinned(false),
100  Owned(owned),
101  Allocated(allocated),
102  Begin(owned, CompressedData),
103  End(CompressedData),
104  overlapCacheInited(false),
105  allocCompressIndex(0),
106  ownedCompressIndex(-1),
107  offsetBlocks(Unique::get() % IPPL_OFFSET_BLOCKS)
108 {
109 
110  // Give the LField some initial (compressed) value
112 
113  // If we are not actually doing compression, expand the storage out,
114  // and copy the initial value to all the elements
116  this->ReallyUncompress(true);
117 
118  //INCIPPLSTAT(incLFields);
119 }
120 
121 //UL: for pinned mempory allocation
122 template<class T, unsigned Dim>
124  const NDIndex<Dim>& allocated,
125  int vnode, bool p)
126  : vnode_m(vnode),
127  P(0),
128  Pinned(p),
129  Owned(owned),
130  Allocated(allocated),
131  Begin(owned, CompressedData),
132  End(CompressedData),
133  overlapCacheInited(false),
134  allocCompressIndex(0),
135  ownedCompressIndex(-1),
136  offsetBlocks(Unique::get() % IPPL_OFFSET_BLOCKS)
137 {
138 
139  // Give the LField some initial (compressed) value
141 
142  // If we are not actually doing compression, expand the storage out,
143  // and copy the initial value to all the elements
145  this->ReallyUncompress(true);
146 
147  //INCIPPLSTAT(incLFields);
148 }
149 
151 //
152 // Deep copy constructor.
153 //
155 
156 template<class T, unsigned Dim>
158  : vnode_m(lf.vnode_m),
159  P(0),
160  Pinned(false),
161  Owned(lf.Owned),
162  Allocated(lf.Allocated),
163  Begin(CompressedData),
164  End(CompressedData),
165  overlapCacheInited(false),
166  allocCompressIndex(lf.allocCompressIndex),
167  ownedCompressIndex(lf.ownedCompressIndex),
168  offsetBlocks(Unique::get() % IPPL_OFFSET_BLOCKS)
169 {
170 
171 
172 
173  if ( lf.IsCompressed() )
174  {
175  // Build a compressed iterator.
177 
178  // get the constant value in lf.
180  }
181  else
182  {
183  // Make sure we have something in this LField
184  PAssert_NE(lf.Allocated.size(), 0);
185 
186  // If it is not compressed, allocate storage
187  int n = lf.Allocated.size();
188  allocateStorage(n);
189 
190  // Copy the data over.
191  std::copy(lf.P, lf.P + n, P);
192 
193  // Build an iterator that counts over the real data.
195  }
196 
197  //INCIPPLSTAT(incLFields);
198 }
199 
200 
202 //
203 // Destructor: just free the memory, if it's there.
204 //
206 
207 template<class T, unsigned Dim>
209 {
210  deallocateStorage();
211 }
212 
213 
215 //
216 // Let the user tell us to try to compress.
217 // Return quickly if we already are compressed.
218 //
220 
221 template<class T, unsigned Dim>
222 bool
223 LField<T,Dim>::TryCompress(bool baseOnPhysicalCells)
224 {
225 
226 
227 
229  return false;
230 
231  LFIELDMSG(Inform dbgmsg("LField::TryCompress", INFORM_ALL_NODES));
232  LFIELDMSG(dbgmsg << "Trying to compress LField with domain = "<<getOwned());
233  LFIELDMSG(dbgmsg << ", baseOnPhysicalCells = " << baseOnPhysicalCells<<endl);
234 
235  if (baseOnPhysicalCells)
236  {
237  if (CanCompressBasedOnPhysicalCells())
238  {
239  CompressBasedOnPhysicalCells();
240  return true;
241  }
242  }
243  else
244  {
245  if (CanCompress() )
246  {
247  Compress();
248  return true;
249  }
250  }
251 
252  return false;
253 }
254 
255 
257 //
258 // Look through the data and figure out if it can be compressed
259 // to the given value.
260 //
262 
263 template<class T, unsigned Dim>
264 bool
266 {
267 
268 
269 
270  // Debugging macro
271  LFIELDMSG(Inform dbgmsg("CanCompress"));
272 
273  // We definitely can't do this if compression is disabled.
275  return false;
276 
277  // If it is already compressed, we can compress it to any value.
278  if (IsCompressed())
279  //return *Begin == val;
280  return true;
281 
282  // It is not currently compressed ... so go through and check
283  // to see if all the elements are the same as the given argument.
284 
285  int sz = getAllocated().size();
286  ADDIPPLSTAT(incCompressionCompareMax, sz);
287  T *ptr1 = P;
288  T *mid1 = P + allocCompressIndex;
289  T *end1 = P + sz;
290 
291  PAssert_GT(sz, 0);
292  PAssert(P != 0);
293  PAssert_GE(allocCompressIndex, 0);
294  PAssert_LT(allocCompressIndex, sz);
295 
296  // Quick short-cut check: compare to the last value in the
297  // array that did not match before.
298 
300  {
301  LFIELDMSG(dbgmsg << "Doing short-cut check, comparing " << *mid1);
302  LFIELDMSG(dbgmsg << " to " << val << " at last-alloc-domain-failed");
303  LFIELDMSG(dbgmsg << " index of " << allocCompressIndex << endl);
304  ADDIPPLSTAT(incCompressionCompares, 1);
305 
306  if (!(*mid1 == val))
307  {
308  LFIELDMSG(dbgmsg << "Short-cut check determined we cannot ");
309  LFIELDMSG(dbgmsg << "compress, by comparing " << *mid1<<" to ");
310  LFIELDMSG(dbgmsg << val << " at last-alloc-domain-failed index");
311  LFIELDMSG(dbgmsg << " of " << allocCompressIndex << endl);
312 
313  // It failed the test, so we can just keep the same index to
314  // check next time, and return.
315  return false;
316  }
317  }
318 
319  // Check from the beginning to the last-checked-index
320 
321  LFIELDMSG(dbgmsg << "Checking for compression for " << sz << " items, ");
322  LFIELDMSG(dbgmsg << "comparing to value = " << val << endl);
323 
325  {
326  // First check from last-failed-position to end, since we've
327  // already looked at *mid1 and should have that section of memory
328  // in cache
329  T *checkptr = mid1 + 1;
330  while (checkptr != end1)
331  {
332  if (!(*checkptr++ == val))
333  {
334  LFIELDMSG(dbgmsg << "Found that we cannot compress, after ");
335  LFIELDMSG(dbgmsg << (checkptr - mid1) << " compares (");
336  LFIELDMSG(dbgmsg << *(checkptr-1) << " != " << val << ")");
337  LFIELDMSG(dbgmsg << endl);
338  ADDIPPLSTAT(incCompressionCompares, (checkptr - mid1));
339  allocCompressIndex = (checkptr - ptr1) - 1;
340  return false;
341  }
342  }
343 
344  // Next, check from the first position to the last-failed-position.
345  checkptr = ptr1;
346  while (checkptr != mid1)
347  {
348  if (!(*checkptr++ == val))
349  {
350  LFIELDMSG(dbgmsg << "Found that we cannot compress, after ");
351  LFIELDMSG(dbgmsg << (checkptr - ptr1) + (end1 - mid1));
352  LFIELDMSG(dbgmsg << " compares (");
353  LFIELDMSG(dbgmsg << *(checkptr-1) << " != " << val << ")");
354  LFIELDMSG(dbgmsg << endl);
355  ADDIPPLSTAT(incCompressionCompares,
356  (checkptr - ptr1) + (end1 - mid1));
357  allocCompressIndex = (checkptr - ptr1) - 1;
358  return false;
359  }
360  }
361  }
362  else
363  {
364  while (ptr1 != end1)
365  {
366  if (!(*ptr1++ == val))
367  {
368  LFIELDMSG(dbgmsg << "Found that we cannot compress, after ");
369  LFIELDMSG(dbgmsg << (ptr1 - P) << " compares (");
370  LFIELDMSG(dbgmsg << *(ptr1-1) << " != " << val << ")");
371  LFIELDMSG(dbgmsg << endl);
372  ADDIPPLSTAT(incCompressionCompares, (ptr1 - P));
373  allocCompressIndex = (ptr1 - P) - 1;
374  return false;
375  }
376  }
377  }
378 
379  // If we are at this point, we did not find anything that did not
380  // match, so we can compress (woo hoo).
381 
382  LFIELDMSG(dbgmsg << "Found that we CAN compress, after " << sz);
383  LFIELDMSG(dbgmsg << " compares." << endl);
384  ADDIPPLSTAT(incCompressionCompares, sz);
385  allocCompressIndex = 0;
386  return true;
387 }
388 
389 
391 //
392 // Return true if this LField can be compressed based on physical
393 // cells only and false if it could not.
394 //
396 
397 template<class T, unsigned Dim>
399 {
400 
401 
402 
403  // Debugging macro
404 
405  LFIELDMSG(Inform dbgmsg("LField::CanCompressBasedOnPhysicalCells",
407 
408  // We definitely can't do this if compression is disabled.
410  return false;
411 
412  // If it is already compressed, we can compress it to any value.
413  if (IsCompressed())
414  return true;
415 
416  // Make an iterator over my owned domain. The cast is there because
417  // this version of begin() is not a const member function.
418 
419  iterator p = const_cast<LField<T,Dim>*>(this)->begin(getOwned());
420 
421  // Get the value to compare against, either the first item or
422  // an item from the last point where our compression check failed.
423 
424  T val = *p;
425  int sz = getOwned().size();
426  if (IpplInfo::extraCompressChecks && ownedCompressIndex > 0)
427  {
428  // There was a previous value, so get that one to compare against
429  PAssert_LT((unsigned int) ownedCompressIndex, getAllocated().size());
430  val = *(P + ownedCompressIndex);
431  LFIELDMSG(dbgmsg << "Checking owned cells using previous ");
432  LFIELDMSG(dbgmsg << "comparison value " << val << " from index = ");
433  LFIELDMSG(dbgmsg << ownedCompressIndex << " against " << sz);
434  LFIELDMSG(dbgmsg << " elements." << endl);
435  }
436  else
437  {
438  // We just use the first element, and will compare against
439  // the rest, so we know we can skip comparing to this first element.
440  ++p;
441  --sz;
442  LFIELDMSG(dbgmsg << "Checking owned cells using first element " << val);
443  LFIELDMSG(dbgmsg << " for comparison against " << sz << " items."<<endl);
444  }
445 
446  // Loop through the other physical cells until we encounter one that
447  // doesn't match the 1st cell. If this occurs, we can't compress.
448 
449  ADDIPPLSTAT(incCompressionCompareMax, sz - 1);
450  for (int i=0; i < sz; ++i, ++p)
451  {
452  if (!(*p == val))
453  {
454  LFIELDMSG(dbgmsg << "Found that we cannot compress, after ");
455  LFIELDMSG(dbgmsg << i + 1 << " compares." << endl);
456  ADDIPPLSTAT(incCompressionCompares, i + 1);
457  ownedCompressIndex = (&(*p)) - P;
458  LFIELDMSG(dbgmsg << "changed ownedCompressIndex to ");
459  LFIELDMSG(dbgmsg << ownedCompressIndex << endl);
460  return false;
461  }
462  }
463 
464  // Since we made it here, we can compress.
465 
466  LFIELDMSG(dbgmsg << "Found that we CAN compress, after ");
467  LFIELDMSG(dbgmsg << sz << " compares." << endl);
468  ADDIPPLSTAT(incCompressionCompares, sz);
469  ownedCompressIndex = (-1);
470  return true;
471 }
472 
473 
475 //
476 // Force a compression to a specified value. This version compresses
477 // the entire allocated domain. If this is called when compression
478 // is turned off, it instead copies the given value into the whole
479 // domain's storage, so that it at least makes the whole domain
480 // equal to the value.
481 //
483 
484 template<class T, unsigned Dim>
485 void
487 {
488 
489 
490 
491  LFIELDMSG(Inform dbgmsg("LField::Compress", INFORM_ALL_NODES));
492  LFIELDMSG(dbgmsg << "Compressing LField with domain = " << getOwned());
493  LFIELDMSG(dbgmsg << " to new value = " << val << ", already compressed = ");
494  LFIELDMSG(dbgmsg << (IsCompressed() ? 1 : 0) << endl);
495 
496  // When compression is disabled, interpret this to mean "assign every element
497  // of the LField to the specified value," which is equivalent to compressing
498  // the LField to the value then uncompressing it:
499 
501  {
502  for (iterator lit = begin(); lit != end(); ++lit)
503  *lit = val;
504 
505  return;
506  }
507 
508  // Compression is enabled if we're here, so save the compressed value and
509  // free up memory if necessary. We copy the value into the compressed
510  // value storage, and then if we're currently compressed, we free up
511  // that memory and update our iterators.
512 
513  CompressedData = val;
514  if (!IsCompressed())
515  {
516  Begin.Compress(CompressedData);
517  deallocateStorage();
518  }
519 
520  //INCIPPLSTAT(incCompresses);
521 }
522 
523 
525 //
526 // This function does a compressed based on physical cells only.
527 // It will compress to the value of the first element in the owned
528 // domain (instead of in the allocated domain). If compression is
529 // turned off, this does nothing, it does not even attempt to fill
530 // in the owned domain with a value.
531 //
533 
534 template<class T, unsigned Dim>
535 void
537 {
538 
539 
540 
541  // We do nothing in this case if compression is turned off.
542 
544  return;
545 
546  // Set compression value to first element in owned domain, and free up
547  // memory if necessary.
548 
549  CompressedData = *(begin(getOwned()));
550  if (!IsCompressed())
551  {
552  Begin.Compress(CompressedData);
553  deallocateStorage();
554  }
555 
556  //INCIPPLSTAT(incCompresses);
557 }
558 
559 
561 //
562 // We know this is compressed, so uncompress it.
563 //
565 
566 template<class T, unsigned Dim>
567 void LField<T,Dim>::ReallyUncompress(bool fill_domain)
568 {
569 
570 
571 
572  PAssert_NE(Allocated.size(), 0);
573 
574  // Allocate the data.
575 
576  int n = Allocated.size();
577  allocateStorage(n);
578 
579  LFIELDMSG(Inform dbgmsg("LField::ReallyUncompress", INFORM_ALL_NODES));
580  LFIELDMSG(dbgmsg << "Uncompressing LField with domain = " << getOwned());
581  LFIELDMSG(dbgmsg << ", fill_domain = " << (fill_domain ? 1 : 0) << endl);
582 
583  // Copy the constant value into the new space.
584 
585  if (fill_domain)
586  {
587  T val = *Begin;
588  for (int i=0; i<n; i++)
589  P[i] = val;
590  }
591 #ifdef IPPL_PURIFY
592  else
593  {
594  // To avoid Purify UMR's, fill with default value anyway
595  T val = T();
596  for (int i=0; i<n; i++)
597  P[i] = val;
598  }
599 #endif
600 
601  // Make the Begin iterator point to the new data.
602 
603  Begin = iterator(P,Owned,Allocated,CompressedData);
604 
605  // Indicate we've done one more decompress
606 
607  //INCIPPLSTAT(incDecompresses);
608 }
609 
610 
612 //
613 // get an iterator over a subrange.
614 //
616 
617 template<class T, unsigned Dim>
620 {
621  // Remove this profiling because this is too lightweight.
622  //
623  //
624  return iterator(P,domain,Allocated,CompressedData);
625 }
626 
627 
629 //
630 // Get an iterator over a subrange, when we might want to try to
631 // compress the data in the subrange without affecting the rest of
632 // the LField data.
633 //
635 
636 template<class T, unsigned Dim>
638 LField<T,Dim>::begin(const NDIndex<Dim>& domain, T& compstore)
639 {
640 
641  if (IsCompressed())
642  compstore = CompressedData;
643  return iterator(P,domain,Allocated,compstore);
644 }
645 
646 
648 //
649 // Swap the pointers between two LFields.
650 //
652 
653 template<class T, unsigned Dim>
654 void
656 {
657 
658 
659 
660  // Swap the pointers to the data.
661  {
662  T *temp=P;
663  P=a.P;
664  a.P=temp;
665  }
666 
667  // Swap the compressed data.
668  {
669  T temp = CompressedData;
670  CompressedData = a.CompressedData;
671  a.CompressedData = temp;
672  }
673 
674  // Swap the last-compared-for-compression indices
675  {
676  int temp = allocCompressIndex;
677  allocCompressIndex = a.allocCompressIndex;
678  a.allocCompressIndex = temp;
679  temp = ownedCompressIndex;
680  ownedCompressIndex = a.ownedCompressIndex;
681  a.ownedCompressIndex = temp;
682  }
683 
684  // Swap the offset block value
685  {
686  int temp = offsetBlocks;
687  offsetBlocks = a.offsetBlocks;
688  a.offsetBlocks = temp;
689  }
690 
691  // Reinitialize the begin iterators.
692  Begin = iterator(P,Owned,Allocated,CompressedData);
694 
695  // Make sure the domains agree.
696  PAssert(Owned == a.Owned);
697  PAssert(Allocated == a.Allocated);
698 
699  // Should we swap the overlap caches?
700 }
701 
702 
704 //
705 // Actualy allocate storage for the LField data, doing any special
706 // memory tricks needed for performance. Sets P pointer to new memory.
707 //
709 
710 // allocate memory for LField and if DKS is used and page-locked (pl) is +1 allocate
711 // page-locked memory for storage
712 template<class T, unsigned Dim>
713 void
715 {
716  PAssert(P == 0);
717  PAssert_GT(newsize, 0);
718  PAssert_GE(offsetBlocks, 0);
719 
720  // Determine how many blocks to offset the data, if we are asked to
721 
722  int extra = 0;
724  extra = offsetBlocks*IPPL_CACHE_LINE_SIZE / sizeof(T);
725 
726  // Allocate the storage, creating some extra to account for offset, and
727  // then add in the offset.
728 #ifdef IPPL_DIRECTIO
729  P = (T *)valloc(sizeof(T) * (newsize + extra));
730 #else
731  P = new T[newsize + extra];
732 #endif
733  P += extra;
734 
735  ADDIPPLSTAT(incLFieldBytes, (newsize+extra)*sizeof(T));
736 }
737 
738 
740 //
741 // Actually free the storage used in the LField, if any. Resets P to zero.
742 //
744 
745 template<class T, unsigned Dim>
746 void
748 {
749  if (P != 0)
750  {
751  // Determine how many blocks to offset the data, if we are asked to.
752  // If so, move the P pointer back.
753 
755  P -= (offsetBlocks*IPPL_CACHE_LINE_SIZE / sizeof(T));
756 
757  // Free the storage
758 
759 #ifdef IPPL_DIRECTIO
760  free(P);
761 #else
762  delete [] P;
763 #endif
764  // Reset our own pointer to zero
765 
766  P = 0;
767  }
768 }
769 
770 
772 //
773 // print an LField out
774 //
776 
777 template<class T, unsigned Dim>
778 void LField<T,Dim>::write(std::ostream& out) const
779 {
780 
781 
782  for (iterator p = begin(); p!=end(); ++p)
783  out << *p << " ";
784 }
785 
786 
787 /***************************************************************************
788  * $RCSfile: LField.cpp,v $ $Author: adelmann $
789  * $Revision: 1.1.1.1 $ $Date: 2003/01/23 07:40:26 $
790  * IPPL_VERSION_ID: $Id: LField.cpp,v 1.1.1.1 2003/01/23 07:40:26 adelmann Exp $
791  ***************************************************************************/
static bool extraCompressChecks
Definition: IpplInfo.h:306
void deallocateStorage()
Definition: LField.hpp:747
bool TryCompress(bool baseOnPhysicalCells=false)
Definition: LField.hpp:223
void swapData(LField< T, Dim > &a)
Definition: LField.hpp:655
bool CanCompressBasedOnPhysicalCells() const
Definition: LField.hpp:398
#define IPPL_CACHE_LINE_SIZE
Definition: LField.hpp:37
Definition: rbendmap.h:8
#define INFORM_ALL_NODES
Definition: Inform.h:38
#define LFIELDMSG(x)
Definition: LField.hpp:53
T CompressedData
Definition: LField.h:244
Definition: Unique.h:28
void write(std::ostream &) const
Definition: LField.hpp:778
void ReallyUncompress(bool fill_domain)
Definition: LField.hpp:567
T * P
Definition: LField.h:220
Definition: FFT.h:31
~LField()
Definition: LField.hpp:208
static void apply(T &)
Definition: LField.hpp:67
int ownedCompressIndex
Definition: LField.h:258
bool CanCompress() const
Definition: LField.h:140
const iterator & begin() const
Definition: LField.h:104
int allocCompressIndex
Definition: LField.h:257
#define PAssert_LT(a, b)
Definition: PAssert.h:121
static bool offsetStorage
Definition: IpplInfo.h:302
CompressedBrickIterator< T, Dim > iterator
Definition: LField.h:56
static bool noFieldCompression
Definition: IpplInfo.h:298
#define PAssert_GE(a, b)
Definition: PAssert.h:124
iterator Begin
Definition: LField.h:236
long offsetBlocks
Definition: LField.h:263
#define IPPL_OFFSET_BLOCKS
Definition: LField.hpp:46
int size(unsigned d) const
Definition: BrickIterator.h:48
NDIndex< Dim > Allocated
Definition: LField.h:232
bool IsCompressed() const
Definition: LField.h:128
NDIndex< Dim > Owned
Definition: LField.h:228
#define PAssert_GT(a, b)
Definition: PAssert.h:123
void CompressBasedOnPhysicalCells()
Definition: LField.hpp:536
#define ADDIPPLSTAT(stat, amount)
Definition: IpplStats.h:236
#define PAssert_NE(a, b)
Definition: PAssert.h:120
void Compress()
Definition: LField.h:155
#define PAssert(c)
Definition: PAssert.h:117
std::string::iterator iterator
Definition: MSLang.h:16
const unsigned Dim
void allocateStorage(int newsize)
Definition: LField.hpp:714
Definition: Inform.h:41
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
#define MAKE_INITIALIZER(T)
Definition: LField.hpp:70