ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc3.c
Revision: 2.1
Committed: Sat Jun 9 07:16:47 2012 UTC (11 years, 10 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created rcontrib program (eventually to replace rtcontrib)

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2     static const char RCSid[] = "$Id$";
3     #endif
4     /*
5     * Accumulate ray contributions for a set of materials
6     * Controlling process for multiple children
7     */
8    
9     #include "rcontrib.h"
10     #include "platform.h"
11     #include "rtprocess.h"
12     #include "selcall.h"
13    
14     /* Modifier contribution queue (results waiting to be output) */
15     typedef struct s_binq {
16     int ndx; /* index for this entry */
17     int n2add; /* number left to add */
18     struct s_binq *next; /* next in queue */
19     MODCONT *mca[1]; /* contrib. array (extends struct) */
20     } BINQ;
21    
22     static BINQ *out_bq = NULL; /* output bin queue */
23     static BINQ *free_bq = NULL; /* free queue entries */
24    
25     static SUBPROC kida[MAXPROCESS]; /* child processes */
26    
27    
28     /* Get new (empty) bin queue entry */
29     static BINQ *
30     new_binq()
31     {
32     BINQ *bp = free_bq;
33     int i;
34    
35     if (bp != NULL) { /* something already available? */
36     free_bq = bp->next;
37     bp->next = NULL;
38     bp->n2add = accumulate-1;
39     return(bp);
40     }
41     /* else allocate fresh */
42     bp = (BINQ *)malloc(sizeof(BINQ)+(nmods-1)*sizeof(MODCONT *));
43     if (bp == NULL)
44     goto memerr;
45     for (i = nmods; i--; ) {
46     MODCONT *mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
47     bp->mca[i] = (MODCONT *)malloc(sizeof(MODCONT) +
48     sizeof(DCOLOR)*(mp->nbins-1));
49     if (bp->mca[i] == NULL)
50     goto memerr;
51     memcpy(bp->mca[i], mp, sizeof(MODCONT)-sizeof(DCOLOR));
52     /* memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*mp->nbins); */
53     }
54     bp->ndx = 0;
55     bp->n2add = accumulate-1;
56     bp->next = NULL;
57     return(bp);
58     memerr:
59     error(SYSTEM, "out of memory in new_binq()");
60     return(NULL);
61     }
62    
63    
64     /* Free a bin queue entry */
65     static void
66     free_binq(BINQ *bp)
67     {
68     int i;
69    
70     if (bp == NULL) { /* signal to release our free list */
71     while ((bp = free_bq) != NULL) {
72     free_bq = bp->next;
73     for (i = nmods; i--; )
74     free(bp->mca[i]);
75     /* Note: we don't own bp->mca[i]->binv */
76     free(bp);
77     }
78     return;
79     }
80     /* clear sums for next use */
81     /* for (i = nmods; i--; )
82     memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*bp->mca[i]->nbins);
83     */
84     bp->ndx = 0;
85     bp->next = free_bq; /* push onto free list */
86     free_bq = bp;
87     }
88    
89    
90     /* Add modifier values to accumulation record in queue and clear */
91     void
92     queue_modifiers()
93     {
94     MODCONT *mpin, *mpout;
95     int i, j;
96    
97     if ((accumulate > 0) | (out_bq == NULL))
98     error(CONSISTENCY, "bad call to queue_modifiers()");
99    
100     for (i = nmods; i--; ) {
101     mpin = (MODCONT *)lu_find(&modconttab,modname[i])->data;
102     mpout = out_bq->mca[i];
103     for (j = mpout->nbins; j--; )
104     addcolor(mpout->cbin[j], mpin->cbin[j]);
105     memset(mpin->cbin, 0, sizeof(DCOLOR)*mpin->nbins);
106     }
107     }
108    
109    
110     /* Sum one modifier record into another (doesn't update n2add) */
111     static void
112     add_modbin(BINQ *dst, BINQ *src)
113     {
114     int i, j;
115    
116     for (i = nmods; i--; ) {
117     MODCONT *mpin = src->mca[i];
118     MODCONT *mpout = dst->mca[i];
119     for (j = mpout->nbins; j--; )
120     addcolor(mpout->cbin[j], mpin->cbin[j]);
121     }
122     }
123    
124    
125     /* Queue output, catching up with and freeing FIFO entries when possible */
126     static int
127     queue_output(BINQ *bp)
128     {
129     int nout = 0;
130     BINQ *b_last, *b_cur;
131     int i;
132    
133     if (accumulate <= 0) { /* just accumulating? */
134     if (out_bq == NULL) {
135     bp->next = NULL;
136     out_bq = bp;
137     } else {
138     add_modbin(out_bq, bp);
139     free_binq(bp);
140     }
141     return(0);
142     }
143     b_last = NULL; /* else insert in output queue */
144     for (b_cur = out_bq; b_cur != NULL && b_cur->ndx < bp->ndx;
145     b_cur = b_cur->next)
146     b_last = b_cur;
147     if (b_last != NULL) {
148     bp->next = b_cur;
149     b_last->next = bp;
150     } else {
151     bp->next = out_bq;
152     out_bq = bp;
153     }
154     if (accumulate > 1) { /* merge accumulation entries */
155     b_cur = out_bq;
156     while (b_cur->next != NULL) {
157     if (b_cur->n2add <= 0 ||
158     (b_cur->ndx-1)/accumulate !=
159     (b_cur->next->ndx-1)/accumulate) {
160     b_cur = b_cur->next;
161     continue;
162     }
163     add_modbin(b_cur, b_cur->next);
164     b_cur->n2add--;
165     b_last = b_cur->next;
166     b_cur->next = b_last->next;
167     b_last->next = NULL;
168     free_binq(b_last);
169     }
170     }
171     /* output ready results */
172     while (out_bq != NULL && (out_bq->ndx == lastdone+1) & !out_bq->n2add) {
173     b_cur = out_bq; /* pop off first entry */
174     out_bq = b_cur->next;
175     b_cur->next = NULL;
176     for (i = 0; i < nmods; i++) /* output record */
177     mod_output(b_cur->mca[i]);
178     end_record();
179     free_binq(b_cur); /* free this entry */
180     lastdone += accumulate;
181     ++nout;
182     }
183     return(nout);
184     }
185    
186    
187     /* Put a zero record in results queue */
188     void
189     zero_record(int ndx)
190     {
191     BINQ *bp = new_binq();
192     int i;
193    
194     for (i = nmods; i--; )
195     memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*bp->mca[i]->nbins);
196     bp->ndx = ndx;
197     queue_output(bp);
198     }
199    
200    
201     /* callback to set output spec to NULL (stdout) */
202     static int
203     set_stdout(const LUENT *le, void *p)
204     {
205     (*(MODCONT *)le->data).outspec = NULL;
206     return(0);
207     }
208    
209    
210     /* Start child processes if we can */
211     int
212     in_rchild()
213     {
214     #ifdef _WIN32
215     error(WARNING, "multiprocessing unsupported -- running solo");
216     nproc = 1;
217     return(1);
218     #else
219     /* try to fork ourselves */
220     while (nchild < nproc) {
221     int p0[2], p1[2];
222     int pid;
223     /* prepare i/o pipes */
224     if (pipe(p0) < 0 || pipe(p1) < 0)
225     error(SYSTEM, "pipe() call failed!");
226     pid = fork(); /* fork parent process */
227     if (pid == 0) { /* if in child, set up & return true */
228     close(p0[1]); close(p1[0]);
229     dup2(p0[0], 0); close(p0[0]);
230     dup2(p1[1], 1); close(p1[1]);
231     inpfmt = (sizeof(RREAL)==sizeof(double)) ? 'd' : 'f';
232     outfmt = 'd';
233     header = 0;
234     waitflush = xres = 1;
235     yres = 0;
236     raysleft = 0;
237     account = accumulate = 1;
238     lu_doall(&modconttab, set_stdout, NULL);
239     nchild = -1;
240     return(1); /* child return value */
241     }
242     if (pid < 0)
243     error(SYSTEM, "fork() call failed!");
244     /* connect our pipes */
245     close(p0[0]); close(p1[1]);
246     kida[nchild].r = p1[0];
247     kida[nchild].w = p0[1];
248     kida[nchild].pid = pid;
249     kida[nchild].running = -1;
250     ++nchild;
251     }
252     return(0); /* parent return value */
253     #endif
254     }
255    
256    
257     /* Close child processes */
258     void
259     end_children()
260     {
261     int status;
262    
263     while (nchild-- > 0)
264     if ((status = close_process(&kida[nchild])) > 0) {
265     sprintf(errmsg,
266     "rendering process returned bad status (%d)",
267     status);
268     error(WARNING, errmsg);
269     }
270     }
271    
272    
273     /* Wait for the next available child */
274     static int
275     next_child_nq(int force_wait)
276     {
277     fd_set readset, errset;
278     int i, j, n, nr;
279    
280     if (!force_wait) /* see if there's one free */
281     for (i = nchild; i--; )
282     if (kida[i].running < 0)
283     return(i);
284     /* prepare select() call */
285     FD_ZERO(&readset); FD_ZERO(&errset);
286     n = nr = 0;
287     for (i = nchild; i--; ) {
288     if (kida[i].running > 0) {
289     FD_SET(kida[i].r, &readset);
290     ++nr;
291     }
292     FD_SET(kida[i].r, &errset);
293     if (kida[i].r >= n)
294     n = kida[i].r + 1;
295     }
296     if (!nr) /* nothing going on */
297     return(-1);
298     if (nr > 1) { /* call select if multiple busy */
299     errno = 0;
300     if (select(n, &readset, NULL, &errset, NULL) < 0)
301     error(SYSTEM, "select call error in next_child_nq()");
302     } else
303     FD_ZERO(&errset);
304     n = -1; /* read results from child(ren) */
305     for (i = nchild; i--; ) {
306     BINQ *bq;
307     if (FD_ISSET(kida[i].r, &errset))
308     error(USER, "rendering process died");
309     if (!FD_ISSET(kida[i].r, &readset))
310     continue;
311     bq = new_binq(); /* get results holder */
312     bq->ndx = kida[i].running;
313     /* read from child */
314     for (j = 0; j < nmods; j++) {
315     n = sizeof(DCOLOR)*bq->mca[j]->nbins;
316     nr = readbuf(kida[i].r, (char *)bq->mca[j]->cbin, n);
317     if (nr != n)
318     error(SYSTEM, "read error from render process");
319     }
320     queue_output(bq); /* put results in output queue */
321     kida[i].running = -1; /* mark child as available */
322     n = i;
323     }
324     return(n); /* last available child */
325     }
326    
327    
328     /* Run parental oversight loop */
329     void
330     parental_loop()
331     {
332     static int ignore_warning_given = 0;
333     FVECT orgdir[2];
334     double d;
335     /* load rays from stdin & process */
336     #ifdef getc_unlocked
337     flockfile(stdin); /* avoid lock/unlock overhead */
338     #endif
339     while (getvec(orgdir[0]) == 0 && getvec(orgdir[1]) == 0) {
340     d = normalize(orgdir[1]);
341     /* asking for flush? */
342     if ((d == 0.0) & (accumulate != 1)) {
343     if (!ignore_warning_given++)
344     error(WARNING,
345     "dummy ray(s) ignored during accumulation\n");
346     continue;
347     }
348     if ((d == 0.0) | (lastray+1 < lastray)) {
349     while (next_child_nq(1) >= 0)
350     ;
351     lastdone = lastray = 0;
352     }
353     if (d == 0.0) {
354     if ((yres <= 0) | (xres <= 0))
355     waitflush = 1; /* flush right after */
356     zero_record(++lastray);
357     } else { /* else assign */
358     int avail = next_child_nq(0);
359     if (writebuf(kida[avail].w, (char *)orgdir,
360     sizeof(FVECT)*2) != sizeof(FVECT)*2)
361     error(SYSTEM, "pipe write error");
362     kida[avail].running = ++lastray;
363     }
364     if (raysleft && !--raysleft)
365     break; /* preemptive EOI */
366     }
367     while (next_child_nq(1) >= 0) /* empty results queue */
368     ;
369     /* output accumulated record */
370     if (accumulate <= 0 || account < accumulate) {
371     int i;
372     if (account < accumulate) {
373     error(WARNING, "partial accumulation in final record");
374     accumulate -= account;
375     }
376     for (i = 0; i < nmods; i++)
377     mod_output(out_bq->mca[i]);
378     end_record();
379     }
380     if (raysleft)
381     error(USER, "unexpected EOF on input");
382     free_binq(NULL); /* clean up */
383     lu_done(&ofiletab);
384     }