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