HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GA_PageIterator.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GA_PageIterator.h ( GA Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __GA_PageIterator__
12 #define __GA_PageIterator__
13 
14 #include "GA_API.h"
15 #include "GA_Iterator.h"
16 #include "GA_Range.h"
17 #include "GA_SplittableRange.h"
18 #include "GA_Types.h"
19 
21 
22 #include <stddef.h>
23 
24 
26 {
27 public:
29  const UT_JobInfo *jobinfo=NULL)
30  : myRange(range)
31  , myJobInfo(jobinfo)
32  , myCurr(0)
33  , myPageCount(range.getPageCount())
34  {
35  if (myJobInfo)
36  myCurr = myJobInfo->nextTask();
37  }
39  : myRange(pit.myRange)
40  , myJobInfo(pit.myJobInfo)
41  , myCurr(pit.myCurr)
42  , myPageCount(pit.myPageCount)
43  {
44  }
46 
47  /// Assignment operator
49  {
50  myRange = src.myRange;
51  myJobInfo = src.myJobInfo;
52  myCurr = src.myCurr;
53  myPageCount = src.myPageCount;
54  return *this;
55  }
56  /// Equality operator
57  bool operator==(const GA_PageIterator &src) const
58  {
59  return myRange == src.myRange &&
60  myJobInfo == src.myJobInfo &&
61  myCurr == src.myCurr &&
62  myPageCount == src.myPageCount;
63  }
64  bool operator!=(const GA_PageIterator &src) const
65  { return !(*this == src); }
66 
67  /// @{
68  /// Return the offset for the beginning of the current page
70  {
71  return myRange.getFirstOffsetInPage(myCurr);
72  }
73  GA_Offset operator*() const { return getFirstOffsetInPage(); }
74  /// @}
75 
76  /// @{
77  /// Iterator interface
78  /// @warning The post-increment operator has a side-effect since the value
79  /// returned is the iterator @b after the increment (not before)
80  void rewind() { myCurr = 0; }
81  bool atEnd() const { return myCurr >= myPageCount; }
82  void advance()
83  {
84  if (myJobInfo)
85  myCurr = myJobInfo->nextTask();
86  else
87  myCurr++;
88  }
89  GA_PageIterator &operator++() { advance(); return *this; }
90  // No post inc as it is harmful.
91  /// @}
92 
93  /// @{
94  /// Begin iterating over the offsets in a page
95  auto begin() const { return GA_Iterator(
96  myRange.getPageElementRange(myCurr)); }
97  auto end() const { return myRange.end(); }
98  /// @}
99 
100 private:
101  GA_SplittableRange myRange;
102  const UT_JobInfo *myJobInfo;
103  GA_Size myCurr, myPageCount;
104 };
105 
106 /// Invokes a body across each block within a page iterator, avoiding
107 /// the double loop you normally needed.
108 /// Usage:
109 /// GA_PageIterator pit(...);
110 /// GAforEachPageBlock(pit, [&](GA_Offset start, GA_Offset end)
111 /// {
112 /// for (GA_Offset off = start; off < end; off++)
113 /// { /* work with off */ }
114 /// });
115 template <typename Body>
116 void
118  const Body &body)
119 {
121 
122  for ( ; !page_iterator.atEnd(); ++page_iterator)
123  {
124  for (GA_Iterator it(page_iterator.begin());
125  it.blockAdvance(start, end); )
126  {
127  body(start, end);
128  }
129  }
130 }
131 
132 /// Invokes the body approximately once per worker thread with
133 /// a shared atomic int to provide load-balanced iteration over the
134 /// pages in the range.
135 /// shouldthread allows you to easily disable threading, for example if
136 /// you know some cases are not threadsafe or you have a larger grain
137 /// size.
138 /// Body Signature: void body(GA_PageIterator page_iterator)
139 /// Usage:
140 /// GAparallelForEachPage(range, shouldthread, [&](GA_PageIterator pit)
141 /// {
142 /// /* Thread local data structures / scratchpads */
143 /// UT_IntArray scratchpad;
144 /// GA_ROPageHandleF pagehandle; /* page handles must be per thread */
145 /// GAforEachPageBlock(pit, [&](GA_Offset start, GA_Offset end)
146 /// {
147 /// pagehandle.setPage(start);
148 /// for (GA_Offset off = start; off < end; off++)
149 /// { /* Process off, using scratchpad */ }
150 /// });
151 /// });
152 ///
153 /// NOTE: Using [&] capture on GAparallelForEachPage will share the outer
154 /// scope's stack variables between threads - you must treat them as const
155 /// (and in particular, re-build pagehandles inside this loop. For non
156 /// trivial loops explicit binding may be safer.
157 template <typename Body>
158 void
159 GAparallelForEachPage(const GA_Range &range, bool shouldthread,
160  const Body &body)
161 {
162  GA_SplittableRange srange(range);
163 
164  int npages = srange.getPageCount();
165  if (npages == 0)
166  return;
167 
168  int nworkers(UT_Thread::getNumProcessors());
169  UT_ASSERT(nworkers >= 1);
170 
171  nworkers = SYSmin(nworkers, npages);
172  if (!shouldthread || nworkers == 1)
173  {
174  // Serial case
175  body(GA_PageIterator(srange));
176  return;
177  }
178 
179  // Split across number of workers, with each thread using the atomic int
180  // to query the next page to be run (similar to UT_ThreadedAlgorithm)
181  SYS_AtomicInt<int> nextpage(0);
182 
183  UTparallelFor(UT_BlockedRange<int>(0, nworkers),
184  [&](const UT_BlockedRange<int> &range)
185  {
186  // There should be only one job id in the range, but we
187  // use this construction anyways... (If there were more,
188  // the later ones would all trivially fail when they start
189  // up and nextTask...)
190  for (int jobid : range.items())
191  {
192  UT_JobInfo info(jobid, nworkers, nullptr, &nextpage);
193 
194  body(GA_PageIterator(srange, &info));
195  }
196  });
197 }
198 
199 /// Define macros roughly equivalent to FOR_INFOTASKS (in
200 /// UT_ThreadedAlgorithm). This will break up the full range into a load
201 /// balanced iteration over pages. For example:
202 /// GA_FOR_INFOTASKS(info, gdp->getPointRange(), it)
203 /// {
204 /// doSomething(it.getOrder()); // Use point number
205 /// doSomething(it.getOffset()); // Use point offset
206 /// }
207 #define GA_FOR_INFORANGE(info, full_range, IT_NAME) \
208  GA_SplittableRange lcl_prange(full_range); \
209  for (GA_PageIterator pit=lcl_prange.beginPages(info); \
210  !pit.atEnd(); ++pit) \
211  for (GA_Iterator IT_NAME = pit.begin(); !IT_NAME.atEnd(); ++IT_NAME)
212 
213 /// Like FOR_INFOTASKS_BOSS, iterate with an optional opInterrupt for every
214 /// block completed.
215 #define GA_FOR_INFORANGE_BOSS(info, full_range, IT_NAME, boss) \
216  GA_SplittableRange lcl_prange(full_range); \
217  for (GA_PageIterator pit=lcl_prange.beginPages(info); \
218  !pit.atEnd() && !boss->opInterrupt(); ++pit) \
219  for (GA_Iterator IT_NAME = pit.begin(); !IT_NAME.atEnd(); ++IT_NAME)
220 
221 /// Iterate over all points for the given info
222 #define GA_FOR_INFO_ALLPOINTS(gdp, info, IT_NAME) \
223  GA_SplittableRange lcl_prange(gdp->getPointRange()); \
224  for (GA_PageIterator pit=lcl_prange.beginPages(info); \
225  !pit.atEnd(); ++pit) \
226  for (GA_Iterator IT_NAME = pit.begin(); !IT_NAME.atEnd(); ++IT_NAME)
227 
228 /// Iterate over all points for the given info with a UT_Interrupt
229 #define GA_FOR_INFO_ALLPOINTS_BOSS(gdp, info, IT_NAME, boss) \
230  GA_SplittableRange lcl_prange(gdp->getPointRange()); \
231  for (GA_PageIterator pit=lcl_prange.beginPages(info); \
232  !pit.atEnd() && !boss->opInterrupt(); ++pit) \
233  for (GA_Iterator IT_NAME = pit.begin(); !IT_NAME.atEnd(); ++IT_NAME)
234 
235 
236 /// Iterate over all points for the given info with a UT_Interrupt
237 #define GA_FOR_INFO_GROUP_POINTS_BOSS(gdp, pointgrp, info, IT_NAME, boss) \
238  GA_SplittableRange lcl_prange(gdp->getPointRange(pointgrp)); \
239  for (GA_PageIterator pit=lcl_prange.beginPages(info); \
240  !pit.atEnd() && !boss->opInterrupt(); ++pit) \
241  for (GA_Iterator IT_NAME = pit.begin(); !IT_NAME.atEnd(); ++IT_NAME)
242 
243 
244 #endif
void UTparallelFor(const Range &range, const Body &body, const int subscribe_ratio=2, const int min_grain_size=1, const bool force_use_task_scope=true)
GLenum GLint * range
Definition: glcorearb.h:1925
**void GAforEachPageBlock(GA_PageIterator &page_iterator, const Body &body)
GA_PageIterator(const GA_PageIterator &pit)
Iteration over a range of elements.
Definition: GA_Iterator.h:29
auto end() const
GA_Size getPageCount() const
Return the number of pages.
bool blockAdvance(GA_Offset &start, GA_Offset &end)
GLuint start
Definition: glcorearb.h:475
GA_PageIterator & operator=(const GA_PageIterator &src)
Assignment operator.
#define GA_API
Definition: GA_API.h:14
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:235
A range of elements in an index-map.
Definition: GA_Range.h:42
GA_Size GA_Offset
Definition: GA_Types.h:641
GA_Offset getFirstOffsetInPage() const
bool atEnd() const
GA_Offset operator*() const
bool operator!=(const GA_PageIterator &src) const
GLuint GLuint end
Definition: glcorearb.h:475
static int getNumProcessors()
auto begin() const
GA_PageIterator(const GA_SplittableRange &range, const UT_JobInfo *jobinfo=NULL)
bool operator==(const GA_PageIterator &src) const
Equality operator.
auto items() const
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
re build pagehandles inside this loop For non *trivial loops binding may be safer *void GAparallelForEachPage(const GA_Range &range, bool shouldthread, const Body &body)
#define SYSmin(a, b)
Definition: SYS_Math.h:1539
Declare prior to use.
GA_PageIterator & operator++()
GLenum src
Definition: glcorearb.h:1793