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.2 by greg, Thu Mar 27 16:35:00 2025 UTC vs.
Revision 2.10 by greg, Thu Oct 30 02:48:54 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 26 | 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 68 | Line 77 | iheadline(char *s, void *p)
77                  ncomp = ncompval(s);
78                  return(1);
79          }
71        if (isexpos(s)) {
72                if (fabs(1. - exposval(s)) > 0.04)
73                        fputs("Warning - ignoring EXPOSURE setting\n", stderr);
74                return(1);
75        }
80          if (formatval(fmt, s)) {
81                  for (in_type = DTend; --in_type > DTfromHeader; )
82                          if (!strcmp(fmt, cm_fmt_id[in_type]))
# Line 84 | 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 114 | 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 132 | 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 151 | 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)) {
184 <                if (strcmp(fmt, cm_fmt_id[in_type]))
185 <                        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 219 | 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 228 | Line 300 | open_output(char *ospec, int fno)
300          if (!ospec) {
301                  ospec = "<stdout>";
302                  fp = stdout;
231                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);
238 <        } 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          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 273 | 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 294 | 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 318 | 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 334 | Line 436 | solo_process(void)
436                                                  dst[i] += cval[i]*iscan[x*ncomp + i];
437                          }
438                          fclose(finp);
439 <                }                       /* write out accumulated column result... */
338 <                if (out_spec) {         /* ...to file or command */
339 <                        if (cmtx->ncols > 1 && !hasFormat(out_spec)) {
340 <                                fputs("Sequential result must go to stdout\n", stderr);
341 <                                return(0);
342 <                        }
343 <                        sprintf(fbuf, out_spec, c);
344 <                        fout = open_output(fbuf, c-(cmtx->ncols==1));
345 <                } else {                /* ...to stdout */
346 <                        if ((out_type == DTfloat) & (cmtx->ncols > 1)) {
347 <                                fputs("Float outputs must have separate destinations\n",
348 <                                                stderr);
349 <                                return(0);
350 <                        }
351 <                        strcpy(fbuf, "<stdout>");
352 <                        fout = open_output(NULL, c-(cmtx->ncols==1));
353 <                }
354 <                if (!fout)
355 <                        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 364 | 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 381 | 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)
# Line 389 | Line 477 | scramble(int n)
477          int     i;
478  
479          if (!scarr) {
480 <                fprintf(stderr, "Out of memory in scramble(%d)\n", n);
480 >                fprintf(stderr, "%s: out of memory in scramble(%d)\n", gargv[0], n);
481                  exit(1);
482          }
483          for (i = n; i--; )
# Line 408 | Line 496 | scramble(int n)
496   int
497   multi_process(void)
498   {
411 #if defined(_WIN32) || defined(_WIN64)
412        fputs("Bad call to multi_process()\n", stderr);
413        return(0);
414 #else
499          int     coff = nprocs;
500          int     odd = 0;
501 +        float   *osum = NULL;
502 +        int     *syarr = NULL;
503          char    fbuf[512];
418        float   *osum;
419        int     *syarr;
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 */
510 >        fflush(NULL);                   /* parent births helper subprocs */
511 >        while (--coff > 0) {
512                  int     pid = fork();
513                  if (pid < 0) {
514 <                        fputs("fork() call failed!\n", stderr);
514 >                        fprintf(stderr, "%s: fork() call failed!\n", gargv[0]);
515                          return(0);
516                  }
517 <                if (pid == 0) break;    /* child gets to work */
517 >                if (!pid) break;        /* new child gets to work */
518          }
519 <        osum = (float *)calloc((size_t)xres*yres, sizeof(float)*ncomp);
520 <        if (!osum) {
521 <                fprintf(stderr, "Cannot allocate %dx%d %d-component accumulator\n",
522 <                                xres, yres, ncomp);
523 <                return(0);
519 >        if (!row0 | (out_type != DTfloat)) {
520 >                osum = (float *)calloc((size_t)xres*yres, sizeof(float)*ncomp);
521 >                if (!osum) {
522 >                        fprintf(stderr, "%s: cannot allocate %dx%d %d-component accumulator\n",
523 >                                        gargv[0], xres, yres, ncomp);
524 >                        return(0);
525 >                }
526          }
527          srandom(113*coff + 5669);       /* randomize row access for this process */
528          syarr = scramble(yres);
529                                          /* run through our unique set of columns */
530          for (c = coff; c < cmtx->ncols; c += nprocs) {
531 +                int     rc = rowN - row0;
532 +                void    *omap = NULL;
533 +                size_t  omaplen = 0;
534 +                long    dstart;
535                  FILE    *fout;
536                  int     y;
537 <                int     rc = cmtx->nrows;
538 <                if (c > coff)           /* clear accumulator? */
539 <                        memset(osum, 0, sizeof(float)*ncomp*xres*yres);
537 >                                        /* create/load output */
538 >                sprintf(fbuf, out_spec, c);
539 >                if (row0) {             /* making another pass? */
540 >                        fout = open_iofile(fbuf, c);
541 >                        if (!fout) return(0);
542 >                        if (out_type == DTfloat) {
543 >                                dstart = ftell(fout);
544 >                                if ((dstart < 0) | (dstart % sizeof(float))) {
545 >                                        fprintf(stderr, "%s: bad seek/alignment\n", fbuf);
546 >                                        return(0);
547 >                                }
548 >                                omaplen = dstart + sizeof(float)*ncomp*xres*yres;
549 >                                omap = mmap(NULL, omaplen, PROT_READ|PROT_WRITE,
550 >                                                MAP_FILE|MAP_SHARED, fileno(fout), 0);
551 >                                if (omap == MAP_FAILED) {
552 >                                        fprintf(stderr, "%s: cannot map file '%s'\n",
553 >                                                        gargv[0], fbuf);
554 >                                        return(0);
555 >                                }
556 >                                osum = (float *)((char *)omap + dstart);
557 >                        } else if (!reload_data(osum, fout))
558 >                                return(0);
559 >                } else {                /* else new output (clobber prev. files) */
560 >                        fout = open_output(fbuf, c);
561 >                        if (!fout) return(0);
562 >                        if (c > coff)   /* clear accumulator? */
563 >                                memset(osum, 0, sizeof(float)*ncomp*xres*yres);
564 >                }
565                  while (rc-- > 0) {      /* map & sum each input file */
566 <                        const int       r = odd ? rc : cmtx->nrows-1 - rc;
566 >                        const int       r = odd ? row0 + rc : rowN-1 - rc;
567                          const rmx_dtype *cval = rmx_val(cmtx, r, c);
568 <                        long            dstart;
453 <                        size_t          maplen;
568 >                        size_t          imaplen;
569                          void            *imap;
570                          FILE            *finp;
571                          float           *dst;
# Line 460 | Line 575 | multi_process(void)
575                          if (i < 0)      /* this coefficient is zero, skip */
576                                  continue;
577                          sprintf(fbuf, in_spec, r);
578 <                        finp = open_input(fbuf);
578 >                        finp = open_iofile(fbuf, -1);
579                          if (!finp)
580                                  return(0);
581                          dstart = ftell(finp);
# Line 473 | Line 588 | multi_process(void)
588                                  return(0);
589                          }
590                          i = in_type==DTfloat ? ncomp*(int)sizeof(float) : ncomp+1;
591 <                        maplen = dstart + yres*xres*i;
592 <                        imap = mmap(NULL, maplen, PROT_READ,
591 >                        imaplen = dstart + (size_t)yres*xres*i;
592 >                        imap = mmap(NULL, imaplen, PROT_READ,
593                                          MAP_FILE|MAP_SHARED, fileno(finp), 0);
594 <                        fclose(finp);           /* will load from map (randomly) */
594 >                        fclose(finp);           /* will read from map (randomly) */
595                          if (imap == MAP_FAILED) {
596                                  fprintf(stderr, "%s: unable to map input file\n", fbuf);
597                                  return(0);
# Line 501 | Line 616 | multi_process(void)
616                                          dst[i] += cval[i]*(cvp[i]+(rmx_dtype).5)*fe;
617                                  }
618                              }
619 <                        munmap(imap, maplen);
620 <                }                       /* write out accumulated column result */
506 <                sprintf(fbuf, out_spec, c);
507 <                fout = open_output(fbuf, c);
508 <                if (!fout)
509 <                        return(0);      /* assume error was reported */
619 >                        munmap(imap, imaplen);
620 >                }                       /* write accumulated column picture */
621                  if (out_type != DTfloat) {
622                          for (y = 0; y < yres; y++)
623                                  if (fwritesscan(osum + (size_t)y*xres*ncomp,
624                                                          ncomp, xres, fout) < 0)
625                                          goto writerr;
626 +                } else if (omap) {
627 +                        if (munmap(omap, omaplen) < 0)
628 +                                goto writerr;
629 +                        osum = NULL;
630                  } else if (fwrite(osum, sizeof(float)*ncomp, (size_t)xres*yres, fout) !=
631                                          (size_t)xres*yres)
632                          goto writerr;
633  
634                  if (fbuf[0] == '!') {
635                          if (pclose(fout) != 0) {
636 <                                fprintf(stderr, "Bad status from: %s\n", fbuf);
636 >                                fprintf(stderr, "%s: bad status from: %s\n", gargv[0], fbuf);
637                                  return(0);
638                          }
639                  } else if (fclose(fout) == EOF)
640                          goto writerr;
641                  odd = !odd;             /* go back & forth to milk page cache */
642          }
643 <        free(osum);
643 >        if (coff) _exit(0);             /* child exits here */
644 >                                        /* but parent waits for children */
645 >        if (osum) free(osum);
646          free(syarr);
647 <        if (coff)                       /* children return here... */
531 <                return(1);
532 <        c = 0;                          /* ...but parent waits for children */
647 >        c = 0;
648          while (++coff < nprocs) {
649                  int     st;
650 <                if (wait(&st) < 0)
650 >                if (wait(&st) < 0) {
651 >                        fprintf(stderr, "%s: warning - wait() call failed unexpectedly\n", gargv[0]);
652                          break;
653 +                }
654                  if (st) c = st;
655          }
656          return(c == 0);
657   writerr:
658          fprintf(stderr, "%s: write error\n", fbuf);
659          return(0);
543 #endif
660   }
661  
662 + #endif          /* ! Windows */
663 +
664   int
665   main(int argc, char *argv[])
666   {
667 +        double  cacheGB = 0;
668 +        int     rintvl;
669          int     a;
670  
671 +        gargc = argc;                   /* for header output */
672 +        gargv = argv;
673 +
674          for (a = 1; a < argc-1 && argv[a][0] == '-'; a++)
675                  switch (argv[a][1]) {
676                  case 'o':               /* output spec/format */
# Line 565 | Line 688 | main(int argc, char *argv[])
688                                  goto badopt;
689                          }
690                          break;
691 +                case 'm':               /* cache size in GigaBytes */
692 +                        cacheGB = atof(argv[++a]);
693 +                        break;
694                  case 'N':               /* number of desired processes */
695                  case 'n':               /* quietly supported alternate */
696                          nprocs = atoi(argv[++a]);
# Line 579 | Line 705 | badopt:                        fprintf(stderr, "%s: bad option: %s\n", argv
705          if ((argc-a < 1) | (argc-a > 2) || argv[a][0] == '-')
706                  goto userr;
707          in_spec = argv[a];
708 <        cmtx = rmx_load(argv[a+1], RMPnone);    /* may load from stdin */
708 >        cmtx = rmx_load(argv[a+1]);     /* loads from stdin if a+1==argc */
709          if (cmtx == NULL)
710                  return(1);              /* error reported */
711 +        cacheGB *= (cmtx->ncols > 1);
712 +        if (cacheGB > 0 && (!out_spec || *out_spec == '!')) {
713 +                fprintf(stderr, "%s: -m option incompatible with output to %s\n",
714 +                                argv[0], out_spec ? "command" : "stdout");
715 +                return(1);
716 +        }
717 +        if (nprocs > cmtx->ncols)
718 +                nprocs = cmtx->ncols;
719   #if defined(_WIN32) || defined(_WIN64)
720          if (nprocs > 1) {
721                  fprintf(stderr, "%s: warning - Windows only allows -N 1\n", argv[0]);
722                  nprocs = 1;
723          }
724   #else
591        if (nprocs > cmtx->ncols)
592                nprocs = cmtx->ncols;
725          if ((nprocs > 1) & !out_spec) {
726                  fprintf(stderr, "%s: multi-processing result cannot go to stdout\n",
727                                  argv[0]);
# Line 608 | Line 740 | badopt:                        fprintf(stderr, "%s: bad option: %s\n", argv
740          }
741          if (!get_iotypes())
742                  return(1);
743 <        if (!(nprocs == 1 ? solo_process() : multi_process()))
744 <                return(1);
743 >        if (cacheGB > 1e-4) {           /* figure out # of passes => rintvl */
744 >                size_t  inp_bytes = (in_type==DTfloat ? sizeof(float)*ncomp
745 >                                                : (size_t)(ncomp+1)) * xres*yres;
746 >                size_t  mem_bytes = sizeof(float)*ncomp*xres*yres;
747 >                int     npasses = (double)inp_bytes*cmtx->nrows /
748 >                                (cacheGB*(1L<<30) - (double)mem_bytes*nprocs) + 1;
749 >                if ((npasses <= 0) | (npasses*8 >= cmtx->nrows))
750 >                        npasses = 1;    /* let's not go there... */
751 >                rintvl = cmtx->nrows / npasses;
752 >                rintvl += (rintvl*npasses < cmtx->nrows);
753 >        } else
754 >                rintvl = cmtx->nrows;
755 >                                        /* make our passes */
756 >        for (row0 = 0; row0 < cmtx->nrows; row0 += rintvl) {
757 >                if ((rowN = row0 + rintvl) > cmtx->nrows)
758 >                        rowN = cmtx->nrows;
759 >                if (nprocs==1 ? !solo_process() : !multi_process())
760 >                        return(1);
761 >        }
762          return(0);
763   userr:
764 <        fprintf(stderr, "Usage: %s [-oc | -of][-o ospec][-N nproc] inpspec [mtx]\n",
764 >        fprintf(stderr, "Usage: %s [-oc | -of][-o ospec][-N nproc][-m cacheGB] inpspec [mtx]\n",
765                                  argv[0]);
766          return(1);
767   }

Diff Legend

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