ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/util/pvsum.c
(Generate patch)

Comparing ray/src/util/pvsum.c (file contents):
Revision 2.1 by greg, Thu Mar 27 01:26:55 2025 UTC vs.
Revision 2.9 by greg, Wed Oct 29 02:48:50 2025 UTC

# Line 10 | Line 10 | static const char RCSid[] = "$Id$";
10   #include "rtio.h"
11   #include "resolu.h"
12   #include "platform.h"
13 < #include "paths.h"
13 > #include "random.h"
14   #include "rmatrix.h"
15   #if !defined(_WIN32) && !defined(_WIN64)
16   #include <sys/mman.h>
17 + #include <sys/wait.h>
18   #endif
19  
20 + #define  VIEWSTR        "VIEW="         /* borrowed from common/view.h */
21 + #define  VIEWSTRL       5
22 +
23   int     nprocs = 1;                     /* # of calculation processes (Unix) */
24   int     in_type = DTfromHeader;         /* input data type */
25   int     out_type = DTfromHeader;        /* output data type */
# Line 25 | Line 29 | char   *out_spec = NULL;               /* output file specification *
29   int     iswapped = 0;                   /* input data is byte-swapped? */
30   int     ncomp = 3;                      /* # input components */
31   int     xres=0, yres=0;                 /* input image dimensions */
32 + char    viewspec[128] = "";             /* VIEW= line from first header */
33 + char    pixasp[48] = "";                /* PIXASPECT= line from header */
34  
35 < RMATRIX *cmtx = NULL;                   /* coefficient matrix */
35 > int     gargc;                          /* global argc */
36 > char    **gargv;                        /* global argv */
37  
38 + RMATRIX *cmtx;                          /* coefficient matrix */
39 + int     row0, rowN;                     /* rows for current pass */
40 +
41   /* does the given spec contain integer format? */
42   int
43   hasFormat(const char *s)
# Line 67 | Line 77 | iheadline(char *s, void *p)
77                  ncomp = ncompval(s);
78                  return(1);
79          }
70        if (isexpos(s)) {
71                if (fabs(1. - exposval(s)) > 0.04)
72                        fputs("Warning - ignoring EXPOSURE setting\n", stderr);
73                return(1);
74        }
80          if (formatval(fmt, s)) {
81                  for (in_type = DTend; --in_type > DTfromHeader; )
82                          if (!strcmp(fmt, cm_fmt_id[in_type]))
# Line 83 | Line 88 | iheadline(char *s, void *p)
88                  iswapped = (i != nativebigendian());
89                  return(1);
90          }
91 +        if (!strncmp(s, VIEWSTR, VIEWSTRL)) {
92 +                strcpy(viewspec, s);
93 +                return(1);
94 +        }
95 +        if (isaspect(s)) {
96 +                strcpy(pixasp, s);
97 +                return(1);
98 +        }
99          return(0);
100   }
101  
# Line 113 | Line 126 | get_iotypes(void)
126                  long    data_start = ftell(fp);         /* make sure input flat */
127                  off_t   dend = lseek(fileno(fp), 0, SEEK_END);
128                  if (dend < data_start + 4L*xres*yres) {
129 <                        fputs("Warning - multi-processing requires flat input files\n",
130 <                                        stderr);
129 >                        fprintf(stderr, "%s: warning - multi-processing requires flat input files\n",
130 >                                        gargv[0]);
131                          nprocs = 1;
132                  }
133          }
# Line 131 | Line 144 | get_iotypes(void)
144                  rmx_free(cmtx);
145                  cmtx = nmtx;
146          } else if (cmtx->ncomp != ncomp) {
147 <                fprintf(stderr, "operation %s needs %d components, has %d\n",
148 <                                cmtx->ncols == 1 ? "vector" : "matrix",
147 >                fprintf(stderr, "%s: operation %s needs %d components, has %d\n",
148 >                                gargv[0], cmtx->ncols == 1 ? "vector" : "matrix",
149                                  ncomp, cmtx->ncomp);
150                  return(0);
151          }
152          if ((in_type != DTrgbe) & (in_type != DTxyze) & (in_type != DTspec) &
153                          (in_type != DTfloat)) {
154 <                fprintf(stderr, "%s unsupported input data type: %s\n",
154 >                fprintf(stderr, "%s: unsupported input data type '%s'\n",
155                                  fbuf, cm_fmt_id[in_type]);
156                  return(0);
157          }
# Line 150 | Line 163 | get_iotypes(void)
163          return(1);
164   }
165  
166 + struct hdata {
167 +        int     xr, yr;         /* resolution */
168 +        int     fno;            /* frame # */
169 +        char    fmt[MAXFMTLEN]; /* format */
170 + };
171 +
172   /* check subsequent headers match initial file */
173   int
174   checkline(char *s, void *p)
175   {
176 <        int     *xyres = (int *)p;
177 <        char    fmt[MAXFMTLEN];
176 >        static int      exposWarned = 0;
177 >        struct hdata    *hp = (struct hdata *)p;
178  
179          if (!strncmp(s, "NCOLS=", 6)) {
180 <                xyres[0] = atoi(s+6);
181 <                if (xyres[0] <= 0)
180 >                hp->xr = atoi(s+6);
181 >                if (hp->xr <= 0)
182                          return(-1);
183                  return(1);
184          }
185          if (!strncmp(s, "NROWS=", 6)) {
186 <                xyres[1] = atoi(s+6);
187 <                if (xyres[1] <= 0)
186 >                hp->yr = atoi(s+6);
187 >                if (hp->yr <= 0)
188                          return(-1);
189                  return(1);
190          }
191 +        if (!strncmp(s, "FRAME=", 6)) {
192 +                hp->fno = atoi(s+6);
193 +                return(1);
194 +        }
195          if (isncomp(s)) {
196                  if (ncompval(s) != ncomp)
197                          return(-1);
198                  return(1);
199          }
200          if (isexpos(s)) {
201 <                if (fabs(1. - exposval(s)) > 0.04)
202 <                        fputs("Warning - ignoring EXPOSURE setting\n", stderr);
201 >                if (!exposWarned && fabs(1. - exposval(s)) > 0.04) {
202 >                        fprintf(stderr, "%s: warning - ignoring EXPOSURE setting(s)\n",
203 >                                        gargv[0]);
204 >                        exposWarned++;
205 >                }
206                  return(1);
207          }
208 <        if (formatval(fmt, s)) {
183 <                if (strcmp(fmt, cm_fmt_id[in_type]))
184 <                        return(-1);
208 >        if (formatval(hp->fmt, s))
209                  return(1);
210 <        }
210 >
211          return(0);
212   }
213  
214 < /* open and check input file */
214 > /* open and check input/output file, read/write mode if fno >= 0 */
215   FILE *
216 < open_input(char *fname)
216 > open_iofile(char *fname, int fno)
217   {
218 <        int     xyres[2];
219 <        FILE    *fp = fopen(fname, "rb");
218 >        struct hdata    hd;
219 >        FILE            *fp = fopen(fname, fno>=0 ? "r+b" : "rb");
220  
221          if (!fp) {
222 <                fprintf(stderr, "%s: cannot open for reading\n", fname);
222 >                fprintf(stderr, "%s: cannot open for reading%s\n",
223 >                                fname, fno>=0 ? "/writing" : "");
224                  return(NULL);
225          }
226 <        xyres[0] = xyres[1] = 0;
227 <        if (getheader(fp, checkline, xyres) < 0) {
226 >        hd.xr = hd.yr = 0;
227 >        hd.fno = -1;
228 >        hd.fmt[0] = '\0';
229 >        if (getheader(fp, checkline, &hd) < 0) {
230                  fprintf(stderr, "%s: bad/inconsistent header\n", fname);
231                  fclose(fp);
232                  return(NULL);
233          }
234 <        if ((xyres[0] <= 0) | (xyres[1] <= 0) &&
235 <                        !fscnresolu(&xyres[0], &xyres[1], fp)) {
234 >        if ((hd.fno >= 0) & (fno >= 0) & (hd.fno != fno)) {
235 >                fprintf(stderr, "%s: unexpected frame number (%d != %d)\n",
236 >                                fname, hd.fno, fno);
237 >                fclose(fp);
238 >                return(NULL);
239 >        }
240 >        if (strcmp(hd.fmt, cm_fmt_id[fno>=0 ? out_type : in_type])) {
241 >                fprintf(stderr, "%s: wrong format\n", fname);
242 >                fclose(fp);
243 >                return(NULL);
244 >        }
245 >        if ((hd.xr <= 0) | (hd.yr <= 0) &&
246 >                        !fscnresolu(&hd.xr, &hd.yr, fp)) {
247                  fprintf(stderr, "%s: missing resolution\n", fname);
248                  fclose(fp);
249                  return(NULL);
250          }
251 <        if ((xyres[0] != xres) | (xyres[1] != yres)) {
251 >        if ((hd.xr != xres) | (hd.yr != yres)) {
252                  fprintf(stderr, "%s: mismatched resolution\n", fname);
253                  fclose(fp);
254                  return(NULL);
# Line 218 | Line 256 | open_input(char *fname)
256          return(fp);
257   }
258  
259 + /* read in previous pixel data from output and rewind to data start */
260 + int
261 + reload_data(float *osum, FILE *fp)
262 + {
263 +        long    dstart;
264 +
265 +        if (!osum | !fp)
266 +                return(0);
267 +        if ((dstart = ftell(fp)) < 0) {
268 +                fprintf(stderr, "%s: ftell() error in reload_data()\n",
269 +                                gargv[0]);
270 +                return(0);
271 +        }
272 +        if (in_type == DTfloat) {
273 +                if (fread(osum, sizeof(float)*ncomp, (size_t)xres*yres, fp) !=
274 +                                (size_t)xres*yres) {
275 +                        fprintf(stderr, "%s: fread() error\n", gargv[0]);
276 +                        return(0);
277 +                }
278 +        } else {
279 +                int     y;
280 +                for (y = 0; y < yres; y++, osum += ncomp*xres)
281 +                        if (freadsscan(osum, ncomp, xres, fp) < 0) {
282 +                                fprintf(stderr, "%s: freadsscan() error\n", gargv[0]);
283 +                                return(0);
284 +                        }
285 +        }
286 +        if (fseek(fp, dstart, SEEK_SET) < 0) {
287 +                fprintf(stderr, "%s: fseek() error in reload_data()\n",
288 +                                gargv[0]);
289 +                return(0);
290 +        }
291 +        return(1);
292 + }
293 +
294   /* open output file or command (if !NULL) and write info header */
295   FILE *
296   open_output(char *ospec, int fno)
# Line 227 | Line 300 | open_output(char *ospec, int fno)
300          if (!ospec) {
301                  ospec = "<stdout>";
302                  fp = stdout;
230                SET_FILE_BINARY(fp);
303          } else if (ospec[0] == '!') {
304                  if (!(fp = popen(ospec+1, "w"))) {
305 <                        fprintf(stderr, "Cannot start: %s\n", ospec);
305 >                        fprintf(stderr, "%s: cannot start: %s\n", gargv[0], ospec);
306                          return(NULL);
307                  }
308 <                SET_FILE_BINARY(fp);
237 <        } else if (!(fp = fopen(ospec, "wb"))) {
308 >        } else if (!(fp = fopen(ospec, "w"))) {
309                  fprintf(stderr, "%s: cannot open for writing\n", ospec);
310                  return(NULL);
311          }
312 +        SET_FILE_BINARY(fp);
313          newheader("RADIANCE", fp);
314 <        fputnow(fp);
314 >        if (cmtx->info)                 /* prepend matrix metadata */
315 >                fputs(cmtx->info, fp);
316 >        else
317 >                fputnow(fp);
318 >        printargs(gargc, gargv, fp);    /* this command */
319          if (fno >= 0)
320                  fprintf(fp, "FRAME=%d\n", fno);
321 +        if (viewspec[0])
322 +                fputs(viewspec, fp);
323 +        if (pixasp[0])
324 +                fputs(pixasp, fp);
325          switch (out_type) {
326          case DTfloat:
327          case DTdouble:
# Line 269 | Line 349 | open_output(char *ospec, int fno)
349                  fprtresolu(xres, yres, fp);
350                  break;
351          default:
352 <                fputs("Unsupported output type!\n", stderr);
352 >                fprintf(stderr, "%s: unsupported output type!\n", gargv[0]);
353                  return(NULL);
354          }
355          if (fflush(fp) < 0) {
# Line 290 | Line 370 | solo_process(void)
370          int     c;
371  
372          if (!osum | !iscan) {
373 <                fprintf(stderr, "Cannot allocate %dx%d %d-component accumulator\n",
374 <                                xres, yres, ncomp);
373 >                fprintf(stderr, "%s: annot allocate %dx%d %d-component accumulator\n",
374 >                                gargv[0], xres, yres, ncomp);
375                  return(0);
376          }
377          if (sizeof(float) != sizeof(COLORV)) {
378 <                fputs("Code Error 1 in solo_process()\n", stderr);
378 >                fprintf(stderr, "%s: Code Error 1 in solo_process()\n", gargv[0]);
379                  return(0);
380          }
381 <        for (c = 0; c < cmtx->ncols; c++) {     /* run through each column/output */
381 >                                        /* run through each column/output */
382 >        for (c = 0; c < cmtx->ncols; c++) {
383 >                int     rc = rowN - row0;
384                  FILE    *fout;
385                  int     y;
386 <                int     rc = cmtx->nrows;
387 <                if (c > 0)              /* clear accumulator? */
386 >                                        /* open output (load if multipass) */
387 >                if (out_spec) {         /* file or command */
388 >                        if (cmtx->ncols > 1 && !hasFormat(out_spec)) {
389 >                                fprintf(stderr, "%s: sequential result must go to stdout\n",
390 >                                                gargv[0]);
391 >                                return(0);
392 >                        }
393 >                        sprintf(fbuf, out_spec, c);
394 >                        if (row0) {     /* another pass -- get prev. data */
395 >                                fout = open_iofile(fbuf, c);
396 >                                if (!reload_data(osum, fout))
397 >                                        return(0);
398 >                        } else          /* else new output (clobber prev. files) */
399 >                                fout = open_output(fbuf, c-(cmtx->ncols==1));
400 >                } else {                        /* else stdout */
401 >                        if ((out_type == DTfloat) & (cmtx->ncols > 1)) {
402 >                                fprintf(stderr, "%s: float outputs must have separate destinations\n",
403 >                                                gargv[0]);
404 >                                return(0);
405 >                        }
406 >                        strcpy(fbuf, "<stdout>");
407 >                        fout = open_output(NULL, c-(cmtx->ncols==1));
408 >                }
409 >                if (!fout)
410 >                        return(0);      /* assume error was reported */
411 >                if (!row0 & (c > 0))    /* clear accumulator? */
412                          memset(osum, 0, sizeof(float)*ncomp*xres*yres);
413                  while (rc-- > 0) {      /* run through each input file */
414 <                        const int       r = c&1 ? rc : cmtx->nrows-1 - rc;
414 >                        const int       r = c&1 ? row0 + rc : rowN-1 - rc;
415                          const rmx_dtype *cval = rmx_val(cmtx, r, c);
416                          FILE            *finp;
417                          int             i, x;
# Line 314 | Line 420 | solo_process(void)
420                          if (i < 0)      /* this coefficient is zero, skip */
421                                  continue;
422                          sprintf(fbuf, in_spec, r);
423 <                        finp = open_input(fbuf);
423 >                        finp = open_iofile(fbuf, -1);
424                          if (!finp)
425                                  return(0);
426                          for (y = 0; y < yres; y++) {
# Line 330 | Line 436 | solo_process(void)
436                                                  dst[i] += cval[i]*iscan[x*ncomp + i];
437                          }
438                          fclose(finp);
439 <                }                       /* write out accumulated column result... */
334 <                if (out_spec) {         /* ...to file or command */
335 <                        if (cmtx->ncols > 1 && !hasFormat(out_spec)) {
336 <                                fputs("Sequential result must go to stdout\n", stderr);
337 <                                return(0);
338 <                        }
339 <                        sprintf(fbuf, out_spec, c);
340 <                        fout = open_output(fbuf, c-(cmtx->ncols==1));
341 <                } else {                /* ...to stdout */
342 <                        if ((out_type == DTfloat) & (cmtx->ncols > 1)) {
343 <                                fputs("Float outputs must have separate destinations\n",
344 <                                                stderr);
345 <                                return(0);
346 <                        }
347 <                        strcpy(fbuf, "<stdout>");
348 <                        fout = open_output(NULL, c-(cmtx->ncols==1));
349 <                }
350 <                if (!fout)
351 <                        return(0);      /* assume error was reported */
439 >                }                       /* write accumulated picture */
440                  if (out_type != DTfloat) {
441                          for (y = 0; y < yres; y++)
442                                  if (fwritesscan(osum + (size_t)y*xres*ncomp,
# Line 360 | Line 448 | solo_process(void)
448  
449                  if (fbuf[0] == '!') {
450                          if (pclose(fout) != 0) {
451 <                                fprintf(stderr, "Bad status from: %s\n", fbuf);
451 >                                fprintf(stderr, "%s: bad status from: %s\n", gargv[0], fbuf);
452                                  return(0);
453                          }
454                  } else if (fout != stdout && fclose(fout) == EOF)
# Line 377 | Line 465 | writerr:
465          return(0);
466   }
467  
468 + #if defined(_WIN32) || defined(_WIN64)
469 + #define multi_process   solo_process
470 + #else
471 +
472 + /* allocate a scrambled index array of the specified length */
473 + int *
474 + scramble(int n)
475 + {
476 +        int     *scarr = (int *)malloc(sizeof(int)*n);
477 +        int     i;
478 +
479 +        if (!scarr) {
480 +                fprintf(stderr, "%s: out of memory in scramble(%d)\n", gargv[0], n);
481 +                exit(1);
482 +        }
483 +        for (i = n; i--; )
484 +                scarr[i] = i;
485 +                                        /* perform Fisher-Yates shuffle */
486 +        for (i = 0; i < n-1; i++) {
487 +                int     ix = irandom(n-i) + i;
488 +                int     ndx = scarr[i];
489 +                scarr[i] = scarr[ix];
490 +                scarr[ix] = ndx;
491 +        }
492 +        return(scarr);
493 + }
494 +
495   /* run calculation on multiple processes, using memory maps and fork() */
496   int
497   multi_process(void)
498   {
384 #if defined(_WIN32) || defined(_WIN64)
385        fputs("Bad call to multi_process()\n", stderr);
386        return(0);
387 #else
499          int     coff = nprocs;
500          int     odd = 0;
501 +        float   *osum = NULL;
502 +        int     *syarr = NULL;
503          char    fbuf[512];
391        float   *osum;
504          int     c;
505                                          /* sanity check */
506          if (sizeof(float) != sizeof(COLORV)) {
507 <                fputs("Code Error 1 in multi_process()\n", stderr);
507 >                fprintf(stderr, "%s: code Error 1 in multi_process()\n", gargv[0]);
508                  return(0);
509          }
510          while (--coff > 0) {            /* parent births children */
511                  int     pid = fork();
512                  if (pid < 0) {
513 <                        fputs("fork() call failed!\n", stderr);
513 >                        fprintf(stderr, "%s: fork() call failed!\n", gargv[0]);
514                          return(0);
515                  }
516                  if (pid == 0) break;    /* child gets to work */
517          }
518 <        osum = (float *)calloc((size_t)xres*yres, sizeof(float)*ncomp);
519 <        if (!osum) {
520 <                fprintf(stderr, "Cannot allocate %dx%d %d-component accumulator\n",
521 <                                xres, yres, ncomp);
522 <                return(0);
518 >        if (!row0 | (out_type != DTfloat)) {
519 >                osum = (float *)calloc((size_t)xres*yres, sizeof(float)*ncomp);
520 >                if (!osum) {
521 >                        fprintf(stderr, "%s: cannot allocate %dx%d %d-component accumulator\n",
522 >                                        gargv[0], xres, yres, ncomp);
523 >                        return(0);
524 >                }
525          }
526 +        srandom(113*coff + 5669);       /* randomize row access for this process */
527 +        syarr = scramble(yres);
528                                          /* run through our unique set of columns */
529          for (c = coff; c < cmtx->ncols; c += nprocs) {
530 +                int     rc = rowN - row0;
531 +                void    *omap = NULL;
532 +                size_t  omaplen = 0;
533 +                long    dstart;
534                  FILE    *fout;
535                  int     y;
536 <                int     rc = cmtx->nrows;
537 <                if (c > coff)           /* clear accumulator? */
538 <                        memset(osum, 0, sizeof(float)*ncomp*xres*yres);
536 >                                        /* create/load output */
537 >                sprintf(fbuf, out_spec, c);
538 >                if (row0) {             /* making another pass? */
539 >                        fout = open_iofile(fbuf, c);
540 >                        if (!fout) return(0);
541 >                        if (out_type == DTfloat) {
542 >                                dstart = ftell(fout);
543 >                                if ((dstart < 0) | (dstart % sizeof(float))) {
544 >                                        fprintf(stderr, "%s: bad seek/alignment\n", fbuf);
545 >                                        return(0);
546 >                                }
547 >                                omaplen = dstart + sizeof(float)*ncomp*xres*yres;
548 >                                omap = mmap(NULL, omaplen, PROT_READ|PROT_WRITE,
549 >                                                MAP_FILE|MAP_SHARED, fileno(fout), 0);
550 >                                if (omap == MAP_FAILED) {
551 >                                        fprintf(stderr, "%s: cannot map file '%s'\n",
552 >                                                        gargv[0], fbuf);
553 >                                        return(0);
554 >                                }
555 >                                osum = (float *)((char *)omap + dstart);
556 >                        } else if (!reload_data(osum, fout))
557 >                                return(0);
558 >                } else {                /* else new output (clobber prev. files) */
559 >                        fout = open_output(fbuf, c);
560 >                        if (!fout) return(0);
561 >                        if (c > coff)   /* clear accumulator? */
562 >                                memset(osum, 0, sizeof(float)*ncomp*xres*yres);
563 >                }
564                  while (rc-- > 0) {      /* map & sum each input file */
565 <                        const int       r = odd ? rc : cmtx->nrows-1 - rc;
565 >                        const int       r = odd ? row0 + rc : rowN-1 - rc;
566                          const rmx_dtype *cval = rmx_val(cmtx, r, c);
567 <                        long            dstart, n;
423 <                        size_t          maplen;
567 >                        size_t          imaplen;
568                          void            *imap;
569                          FILE            *finp;
570                          float           *dst;
571 <                        int             i;
571 >                        int             i, x;
572                          for (i = ncomp; i--; )
573                                  if (cval[i] != 0) break;
574                          if (i < 0)      /* this coefficient is zero, skip */
575                                  continue;
576                          sprintf(fbuf, in_spec, r);
577 <                        finp = open_input(fbuf);
577 >                        finp = open_iofile(fbuf, -1);
578                          if (!finp)
579                                  return(0);
580                          dstart = ftell(finp);
# Line 443 | Line 587 | multi_process(void)
587                                  return(0);
588                          }
589                          i = in_type==DTfloat ? ncomp*(int)sizeof(float) : ncomp+1;
590 <                        maplen = dstart + yres*xres*i;
591 <                        imap = mmap(NULL, maplen, PROT_READ,
590 >                        imaplen = dstart + (size_t)yres*xres*i;
591 >                        imap = mmap(NULL, imaplen, PROT_READ,
592                                          MAP_FILE|MAP_SHARED, fileno(finp), 0);
593 <                        fclose(finp);           /* will load from map */
593 >                        fclose(finp);           /* will read from map (randomly) */
594                          if (imap == MAP_FAILED) {
595                                  fprintf(stderr, "%s: unable to map input file\n", fbuf);
596                                  return(0);
597                          }
598 <                        dst = osum;             /* -> weighted image sum */
599 <                        if (in_type == DTfloat) {
600 <                            const float *fvp = (float *)((char *)imap + dstart);
601 <                            for (n = (long)yres*xres; n-- > 0;
602 <                                                        dst += ncomp, fvp += ncomp)
603 <                                for (i = ncomp; i--; )
604 <                                    dst[i] += cval[i]*fvp[i];
605 <                        } else {
462 <                            const COLRV *cvp = (COLRV *)((char *)imap + dstart);
463 <                            for (n = (long)yres*xres; n-- > 0;
464 <                                                        dst += ncomp, cvp += ncomp+1) {
465 <                                const rmx_dtype fe = cxponent[cvp[ncomp]];
466 <                                for (i = ncomp; i--; )
467 <                                    dst[i] += cval[i]*(cvp[i]+(rmx_dtype).5)*fe;
598 >                        if (in_type == DTfloat)
599 >                            for (y = yres; y-- > 0; ) {
600 >                                const float     *fvp = (float *)((char *)imap + dstart) +
601 >                                                        (size_t)ncomp*xres*syarr[y];
602 >                                dst = osum + (size_t)ncomp*xres*syarr[y];
603 >                                for (x = xres; x-- > 0; dst += ncomp, fvp += ncomp)
604 >                                    for (i = ncomp; i--; )
605 >                                        dst[i] += cval[i]*fvp[i];
606                              }
607 <                        }
608 <                        munmap(imap, maplen);
609 <                }                       /* write out accumulated column result */
610 <                sprintf(fbuf, out_spec, c);
611 <                fout = open_output(fbuf, c);
612 <                if (!fout)
613 <                        return(0);      /* assume error was reported */
607 >                        else
608 >                            for (y = yres; y-- > 0; ) {
609 >                                const COLRV     *cvp = (COLRV *)((char *)imap + dstart) +
610 >                                                        (ncomp+1L)*xres*syarr[y];
611 >                                dst = osum + (size_t)ncomp*xres*syarr[y];
612 >                                for (x = xres; x-- > 0; dst += ncomp, cvp += ncomp+1) {
613 >                                    const rmx_dtype     fe = cxponent[cvp[ncomp]];
614 >                                    for (i = ncomp; i--; )
615 >                                        dst[i] += cval[i]*(cvp[i]+(rmx_dtype).5)*fe;
616 >                                }
617 >                            }
618 >                        munmap(imap, imaplen);
619 >                }                       /* write accumulated column picture */
620                  if (out_type != DTfloat) {
621                          for (y = 0; y < yres; y++)
622                                  if (fwritesscan(osum + (size_t)y*xres*ncomp,
623                                                          ncomp, xres, fout) < 0)
624                                          goto writerr;
625 +                } else if (omap) {
626 +                        if (munmap(omap, omaplen) < 0)
627 +                                goto writerr;
628 +                        osum = NULL;
629                  } else if (fwrite(osum, sizeof(float)*ncomp, (size_t)xres*yres, fout) !=
630                                          (size_t)xres*yres)
631                          goto writerr;
632  
633                  if (fbuf[0] == '!') {
634                          if (pclose(fout) != 0) {
635 <                                fprintf(stderr, "Bad status from: %s\n", fbuf);
635 >                                fprintf(stderr, "%s: bad status from: %s\n", gargv[0], fbuf);
636                                  return(0);
637                          }
638                  } else if (fclose(fout) == EOF)
639                          goto writerr;
640                  odd = !odd;             /* go back & forth to milk page cache */
641          }
642 <        free(osum);
643 <        if (coff)                       /* children return here... */
644 <                return(1);
642 >        if (osum) free(osum);
643 >        free(syarr);
644 >        if (coff)                       /* child exits here... */
645 >                _exit(0);
646          c = 0;                          /* ...but parent waits for children */
647          while (++coff < nprocs) {
648                  int     st;
649 <                if (wait(&st) < 0)
649 >                if (wait(&st) < 0) {
650 >                        fprintf(stderr, "%s: warning - wait() call failed unexpectedly\n", gargv[0]);
651                          break;
652 +                }
653                  if (st) c = st;
654          }
655          return(c == 0);
656   writerr:
657          fprintf(stderr, "%s: write error\n", fbuf);
658          return(0);
508 #endif
659   }
660  
661 + #endif          /* ! Windows */
662 +
663   int
664   main(int argc, char *argv[])
665   {
666 +        double  cacheGB = 0;
667 +        int     rintvl;
668          int     a;
669  
670 +        gargc = argc;                   /* for header output */
671 +        gargv = argv;
672 +
673          for (a = 1; a < argc-1 && argv[a][0] == '-'; a++)
674                  switch (argv[a][1]) {
675                  case 'o':               /* output spec/format */
# Line 530 | Line 687 | main(int argc, char *argv[])
687                                  goto badopt;
688                          }
689                          break;
690 +                case 'm':               /* cache size in GigaBytes */
691 +                        cacheGB = atof(argv[++a]);
692 +                        break;
693                  case 'N':               /* number of desired processes */
694                  case 'n':               /* quietly supported alternate */
695                          nprocs = atoi(argv[++a]);
# Line 544 | Line 704 | badopt:                        fprintf(stderr, "%s: bad option: %s\n", argv
704          if ((argc-a < 1) | (argc-a > 2) || argv[a][0] == '-')
705                  goto userr;
706          in_spec = argv[a];
707 <        cmtx = rmx_load(argv[a+1], RMPnone);    /* may load from stdin */
707 >        cmtx = rmx_load(argv[a+1]);     /* loads from stdin if a+1==argc */
708          if (cmtx == NULL)
709                  return(1);              /* error reported */
710 +        cacheGB *= (cmtx->ncols > 1);
711 +        if (cacheGB > 0 && (!out_spec || *out_spec == '!')) {
712 +                fprintf(stderr, "%s: -m option incompatible with output to %s\n",
713 +                                argv[0], out_spec ? "command" : "stdout");
714 +                return(1);
715 +        }
716 +        if (nprocs > cmtx->ncols)
717 +                nprocs = cmtx->ncols;
718   #if defined(_WIN32) || defined(_WIN64)
719          if (nprocs > 1) {
720                  fprintf(stderr, "%s: warning - Windows only allows -N 1\n", argv[0]);
721                  nprocs = 1;
722          }
723   #else
556        if (nprocs > cmtx->ncols)
557                nprocs = cmtx->ncols;
724          if ((nprocs > 1) & !out_spec) {
725                  fprintf(stderr, "%s: multi-processing result cannot go to stdout\n",
726                                  argv[0]);
# Line 573 | Line 739 | badopt:                        fprintf(stderr, "%s: bad option: %s\n", argv
739          }
740          if (!get_iotypes())
741                  return(1);
742 <        if (!(nprocs == 1 ? solo_process() : multi_process()))
743 <                return(1);
742 >        if (cacheGB > 1e-4) {           /* figure out # of passes => rintvl */
743 >                size_t  inp_bytes = (in_type==DTfloat ? sizeof(float)*ncomp
744 >                                                : (size_t)(ncomp+1)) * xres*yres;
745 >                size_t  mem_bytes = sizeof(float)*ncomp*xres*yres;
746 >                int     npasses = (double)inp_bytes*cmtx->nrows /
747 >                                (cacheGB*(1L<<30) - (double)mem_bytes*nprocs) + 1;
748 >                if ((npasses <= 0) | (npasses*8 >= cmtx->nrows))
749 >                        npasses = 1;    /* let's not go there... */
750 >                rintvl = cmtx->nrows / npasses;
751 >                rintvl += (rintvl*npasses < cmtx->nrows);
752 >        } else
753 >                rintvl = cmtx->nrows;
754 >                                        /* make our passes */
755 >        for (row0 = 0; row0 < cmtx->nrows; row0 += rintvl) {
756 >                if ((rowN = row0 + rintvl) > cmtx->nrows)
757 >                        rowN = cmtx->nrows;
758 >                if (nprocs==1 ? !solo_process() : !multi_process())
759 >                        return(1);
760 >        }
761          return(0);
762   userr:
763 <        fprintf(stderr, "Usage: %s [-oc | -of][-o ospec][-N nproc] inpspec [mtx]\n",
763 >        fprintf(stderr, "Usage: %s [-oc | -of][-o ospec][-N nproc][-m cacheGB] inpspec [mtx]\n",
764                                  argv[0]);
765          return(1);
766   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)