ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RcontribSimulManager.h
Revision: 2.5
Committed: Wed Nov 6 18:28:52 2024 UTC (5 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +2 -1 lines
Log Message:
perf(rxtrace,rxpict,rxpiece,rxcontrib): Improved exit strategy in children

File Contents

# Content
1 /* RCSid $Id: RcontribSimulManager.h,v 2.4 2024/11/01 23:05:01 greg Exp $ */
2 /*
3 * RcontribSimulManager.h
4 *
5 * Rcontrib simulation manager class declaration
6 *
7 * Created by Greg Ward on 10/11/2024.
8 */
9
10 #ifndef RcontribSimulManager_h
11 #define RcontribSimulManager_h
12
13 #include "RtraceSimulManager.h"
14 #include "RdataShare.h"
15 #include "lookup.h"
16 #include "rtprocess.h"
17
18 /*
19 * As with other single-object classes, many global variable affect
20 * behavior. Besides rendering parameters, there are spectral parameters
21 * and output dimensions taken from the environment.
22 *
23 * NOTE: "record" and "row" are used interchangeably throughout.
24 */
25
26 extern char RCCONTEXT[]; // global rcontrib context
27
28 extern int contrib; // computing contributions?
29
30 extern int xres, yres; // global resolution settings
31
32 class RcontribSimulManager; // need forward decl
33
34 /// Shared data object for record output (includes header; may be write-only)
35 class RcontribOutput {
36 RcontribOutput * next; // next in sorted list
37 char * ofname; // output file name
38 uint32 rowCountPos; // row count position in header
39 void * rowp; // current row memory
40 bool NewHeader(const RcontribSimulManager *rcp);
41 int CheckHeader(const RcontribSimulManager *rcp);
42 public:
43 RdataShare * rData; // data sharing object
44 size_t rowBytes; // byte count per row
45 const char * omod; // single modifier (or NULL)
46 int32 obin; // single output bin (or -1)
47 uint32 begData; // start of data (type-aligned)
48 int32 curRow; // current output row
49 uint32 nRows; // total number of rows
50 RcontribOutput(const char *fnm = NULL) {
51 next = NULL;
52 omod = NULL;
53 obin = -1;
54 rData = NULL;
55 ofname = savqstr(fnm);
56 rowBytes = 0;
57 nRows = 0;
58 rowp = NULL; curRow = -1;
59 }
60 ~RcontribOutput() {
61 DoneRow();
62 delete rData;
63 delete next;
64 freeqstr(ofname);
65 }
66 /// Return output channel name
67 const char * GetName() const {
68 if (rData) return rData->GetName();
69 return ofname;
70 }
71 /// Update output row count
72 bool SetRowsDone(int r) {
73 if (!rData | (0 >= r) | (r > nRows)) return false;
74 char * rbuf = (char *)rData->GetMemory(rowCountPos, 17, 0);
75 sprintf(rbuf, "%-16d", r);
76 rbuf[16] = '\n'; // replaces nul byte
77 return rData->ReleaseMemory(rbuf, RDSwrite);
78 }
79 /// Get buffer for indicated row (contents may be random)
80 void * GetRow(int r) {
81 if (!rData | (r < 0)) return NULL;
82 if (r != curRow) {
83 DoneRow();
84 if (r < nRows)
85 rowp = rData->GetMemory(begData + r*rowBytes,
86 rowBytes, 0);
87 if (rowp) curRow = r;
88 }
89 return rowp;
90 }
91 /// Current row with byte offset
92 void * InsertionP(int coffset) const {
93 if (!rowp | (coffset < 0) | (coffset >= rowBytes))
94 return NULL;
95 return (char *)rowp + coffset;
96 }
97 /// Release current row, writing contents
98 void DoneRow() {
99 if (rowp) rData->ReleaseMemory(rowp, RDSwrite);
100 rowp = NULL; curRow = -1;
101 }
102 /// Get next in list
103 const RcontribOutput * Next() const {
104 return next;
105 }
106 RcontribOutput * Next() {
107 return next;
108 }
109 /// RcontribSimulManager gets full access
110 friend class RcontribSimulManager;
111 };
112
113 typedef double DCOLORV; // color accumulator type
114
115 /// Modifier channel for recording contributions (no constructor/destructor)
116 struct RcontribMod;
117
118 /// Allocate rcontrib accumulator
119 extern RcontribMod * NewRcMod(const char *prms = NULL, const char *binexpr = NULL, int ncbins = 1);
120 /// Free an RcontribMod
121 extern lut_free_t FreeRcMod;
122
123 /*
124 * General RcontribSimulManager class operation:
125 *
126 * 1) Call LoadOctree(), then alter the header as desired
127 * 2) Set number of spectral samples (NCSAMP) and call SetDataFormat()
128 * 3) Call AddModifier() and AddModFile() to indicate tracked modifiers
129 * 4) Set outOp and cdsF according to desired output/recovery
130 * 5) Call PrepOutput() to open output channels
131 * 6) Call SetThreadCount() to fork children if desired
132 * 7) Set accum to the number of ray samples per record
133 * 8) Call ComputeRecord() with accum ray samples
134 * 9) Continue until GetRowMax() records have been sent
135 * 10) Call Cleanup()
136 *
137 * The order of some of these calls may be changed. Technically, the octree
138 * may be loaded anytime before PrepOutput() is called. Also, SetThreadCount()
139 * may be called anytime after PrepOutput() and interleaved with
140 * calls to ComputeRecord(). The accum setting may be changed at any time.
141 * Finally, it is possible to restart the output using ResetRow(), and
142 * a zero argument will rewind to the beginning, whence all records
143 * may be recalculated. The previous output rows are not zeroed or deleted,
144 * but are overwritten as the calculation proceeds from the new starting point.
145 * However, the output file(s) will indicate in the NROWS= line in the header
146 * that only the newly calculated rows are present.
147 *
148 * It is not possible to write to standard output, but the output
149 * model is quite flexible thanks to the RdataShare polymorphic class.
150 * The current default output class creates a shared, memory-mapped file,
151 * which is the most efficient object on most systems.
152 *
153 * ASCII output is not supported, so full data recovery is.
154 */
155
156 /// Output channel opening options: new/exclusive, overwrite if exists, or recover data
157 enum RCOutputOp {RCOnew=0, RCOforce, RCOrecover};
158
159 /// Converts above to RdataShare open flags (may be adjusted by calling program)
160 extern int RSDOflags[];
161
162 /// Call-back function type to create named data channel (freed using "delete" operator)
163 typedef RdataShare * RcreateDataShareF(const char *name, RCOutputOp op, size_t siz);
164
165 /// Our default data share function
166 extern RcreateDataShareF defDataShare;
167
168 /// Modifiable ray-tracing flags for rcontrib
169 #define RCmask (RTlimDist|RTimmIrrad)
170
171 /// rcontrib-like simulation manager (at most one such object)
172 class RcontribSimulManager : protected RtraceSimulManager {
173 protected:
174 static RayReportCall RctCall; // our callback for traced rays
175 ABitMap rowsDone; // bit mask of completed rows
176 uint32 rInPos; // which row (record) is next on input?
177 uby8 nChan; // NCSAMP setting for this calculation
178 char dtyp; // data type ('f', 'd', or 'c')
179 uint16 dsiz; // N-component element size in bytes
180 RcontribOutput * outList; // ordered list of output channels
181 LUTAB modLUT; // modifier lookup table
182 SUBPROC * kid; // array of child processes
183 int32 * kidRow; // row assigned to each child
184 int nkids; // child process count (-1 in child)
185 bool UpdateRowsDone(int r);
186 int GetChild(bool forceWait = false);
187 bool StartKids(int n2go);
188 int StopKids(int n2end = 0);
189 void RunChild();
190 public:
191 RCOutputOp outOp; // output operation
192 RcreateDataShareF * cdsF; // data share creator
193 uint32 accum; // # rays to accumulate per record
194 RcontribSimulManager(const char *octn = NULL)
195 : RtraceSimulManager(NULL, NULL, octn) {
196 rInPos = 0;
197 nChan = 0;
198 dtyp = 'f';
199 dsiz = 0;
200 outList = NULL;
201 memset(&modLUT, 0, sizeof(modLUT));
202 modLUT.hashf = lu_shash;
203 modLUT.keycmp = strcmp;
204 modLUT.freek = efree;
205 modLUT.freed = FreeRcMod;
206 kid = NULL; kidRow = NULL; nkids = 0;
207 rtFlags = RTtraceSources;
208 SetTraceCall(&RctCall, this);
209 outOp = RCOnew;
210 cdsF = &defDataShare;
211 accum = 1;
212 }
213 ~RcontribSimulManager() {
214 Cleanup();
215 }
216 /// Check modifiable ray-tracing computation flag(s)
217 bool HasFlag(int fl) const {
218 return ((rtFlags & RCmask & fl) != 0);
219 }
220 /// Set/reset modifiable ray-tracing computation flag(s)
221 bool SetFlag(int fl, bool val = true) {
222 if (!(fl &= RCmask)) return false;
223 if (val) rtFlags |= fl;
224 else rtFlags &= ~fl;
225 return true;
226 }
227 /// Load octree and prepare renderer
228 bool LoadOctree(const char *octn) {
229 return RtraceSimulManager::LoadOctree(octn);
230 }
231 /// Prepare header from previous input (or clear)
232 bool NewHeader(const char *inspec=NULL) {
233 return RtraceSimulManager::NewHeader(inspec);
234 }
235 /// Add a string to header (adds newline if none)
236 bool AddHeader(const char *str) {
237 return RtraceSimulManager::AddHeader(str);
238 }
239 /// Append program line to header
240 bool AddHeader(int ac, char *av[]) {
241 return RtraceSimulManager::AddHeader(ac, av);
242 }
243 /// Get current header length in bytes
244 int GetHeadLen() const {
245 return RtraceSimulManager::GetHeadLen();
246 }
247 /// Get header lines if any
248 const char * GetHeadStr() const {
249 return RtraceSimulManager::GetHeadStr();
250 }
251 /// Look for specific header keyword, return value
252 const char * GetHeadStr(const char *key, bool inOK = false) const {
253 return RtraceSimulManager::GetHeadStr(key, inOK);
254 }
255 /// Set output format ('f', 'd', or 'c'), call before mods
256 bool SetDataFormat(int ty);
257 /// Get current format (and element size in bytes)
258 int GetFormat(int *siz = NULL) const {
259 if (siz) *siz = dsiz;
260 return dtyp;
261 }
262 /// Add a modifier and arguments, create output(s)
263 bool AddModifier(const char *modn, const char *outspec,
264 const char *prms = NULL,
265 const char *binval = NULL, int bincnt = 1);
266 /// Add a file of modifiers with associated arguments
267 bool AddModFile(const char *modfn, const char *outspec,
268 const char *prms = NULL,
269 const char *binval = NULL, int bincnt = 1);
270 /// Get named rcontrib output (or list)
271 const RcontribOutput * GetOutput(const char *nm = NULL) const {
272 if (!nm) return outList;
273 const RcontribOutput * op = outList;
274 while (op && strcmp(op->GetName(), nm))
275 op = op->next;
276 return op;
277 }
278 /// Open output channels and return # completed rows
279 int PrepOutput();
280 /// Are we ready to compute some records?
281 bool Ready() const {
282 return (rowsDone.Length() > 0) & (accum > 0);
283 }
284 /// Set number of computation threads (0 => #cores)
285 int SetThreadCount(int nt = 0);
286 /// Check thread count (1 means no multi-processing)
287 int NThreads() const {
288 return nkids + !nkids;
289 }
290 /// What is maximum row?
291 int GetRowMax() const {
292 if (!outList) return yres * (xres + !xres);
293 return outList->nRows;
294 }
295 /// Get current row count (# rows sent for computation)
296 int GetRowCount() const {
297 return rInPos;
298 }
299 /// Get # rows completed
300 int GetRowFinished() const {
301 if (!nkids) return rInPos;
302 uint32 nDone = rowsDone.Find(0, false);
303 if (nDone == ABMend)
304 return rowsDone.Length();
305 return nDone;
306 }
307 /// Rewind calculation (previous results unchanged)
308 bool ResetRow(int r);
309 /// Add a ray/bundle to compute next record (n=accum)
310 int ComputeRecord(const FVECT orig_direc[]);
311 /// Finish pending rays if multi-processing
312 bool FlushQueue() {
313 if (nkids <= 0) return true;
314 while (GetChild(true) >= 0)
315 ;
316 return true;
317 }
318 /// Close octree, free data, return status
319 int Cleanup(bool everything = false) {
320 if (nkids < 0) return 0; // skip 4 child
321 if (rowsDone.Length()) {
322 SetThreadCount(1);
323 cow_doneshare();
324 rowsDone.NewBitMap(0);
325 }
326 lu_done(&modLUT);
327 delete outList; outList = NULL;
328 nChan = 0;
329 return RtraceSimulManager::Cleanup(everything);
330 }
331 };
332
333 #endif /* RcontribSimulManager_h */