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

Comparing ray/src/util/rcomb.c (file contents):
Revision 2.2 by greg, Mon Dec 18 23:04:05 2023 UTC vs.
Revision 2.18 by greg, Thu May 23 19:29:41 2024 UTC

# Line 3 | Line 3 | static const char RCSid[] = "$Id$";
3   #endif
4   /*
5   * General component matrix combiner, operating on a row at a time.
6 + *
7 + * Multi-processing mode under Unix creates children that each work
8 + * on one input row at a time, fed by the single parent.  Output to
9 + * a shared stdout is assured because each child waits for parent
10 + * to be ready with next input row before it outputs the previous result.
11 + * The assumption (checked in spawn_children()) is that the parent
12 + * will remain blocked until the child it is feeding has finished
13 + * flushing the previous row to stdout.  The final output row is
14 + * less guaranteed to be in order, so the parent sleeps for a few seconds
15 + * between each child pipe closure, in hopes that this allows enough
16 + * time for row output to finish in each process.
17   */
18  
8 #include <errno.h>
19   #include <math.h>
20   #include "platform.h"
21 + #include "rtprocess.h"
22   #include "rtio.h"
12 #include "resolu.h"
23   #include "rmatrix.h"
24   #include "calcomp.h"
15 #include "paths.h"
25  
26   #ifndef M_PI
27   #define M_PI    3.14159265358979323846
# Line 55 | Line 64 | int            cur_row;                        /* current input/output row */
64   int             cur_col;                        /* current input/output column */
65   int             cur_chan;                       /* if we're looping channels */
66  
67 + SUBPROC         *cproc = NULL;                  /* child process array */
68 + int             nchildren = 0;                  /* # of child processes */
69 + int             inchild = -1;                   /* our child ID (-1: parent) */
70 +
71   static int      checksymbolic(ROPMAT *rop);
72  
73   static int
# Line 186 | Line 199 | checksymbolic(ROPMAT *rop)
199   {
200          const int       nc = rop->imx.ncomp;
201          const int       dt = rop->imx.dtype;
202 +        double          cf = 1;
203          int             i, j;
204                                          /* check suffix => reference file */
205          if (strchr(rop->preop.csym, '.') > rop->preop.csym)
# Line 206 | Line 220 | checksymbolic(ROPMAT *rop)
220                  int     comp = 0;
221                  switch (rop->preop.csym[j]) {
222                  case 'B':
223 +                case 'b':
224                          ++comp;
225                          /* fall through */
226                  case 'G':
227 +                case 'g':
228                          ++comp;
229                          /* fall through */
230                  case 'R':
231 +                case 'r':
232 +                        if (rop->preop.csym[j] <= 'Z')
233 +                                cf = 1./WHTEFFICACY;
234                          if (dt == DTxyze) {
235                                  for (i = 3; i--; )
236 <                                        rop->preop.cmat[j*nc+i] = 1./WHTEFFICACY *
218 <                                                        xyz2rgbmat[comp][i];
236 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
237                          } else if (nc == 3)
238                                  rop->preop.cmat[j*nc+comp] = 1.;
239                          else
240                                  rgbrow(rop, j, comp);
241                          break;
242                  case 'Z':
243 +                case 'z':
244                          ++comp;
245                          /* fall through */
246                  case 'Y':
247 +                case 'y':
248                          ++comp;
249                          /* fall through */
250                  case 'X':
251 +                case 'x':
252 +                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
253 +                                cf = WHTEFFICACY;
254                          if (dt == DTxyze) {
255                                  rop->preop.cmat[j*nc+comp] = 1.;
256                          } else if (nc == 3) {
# Line 239 | Line 262 | checksymbolic(ROPMAT *rop)
262                          else
263                                  xyzrow(rop, j, comp);
264  
265 <                        for (i = nc*(dt != DTxyze); i--; )
266 <                                rop->preop.cmat[j*nc+i] *= WHTEFFICACY;
265 >                        for (i = nc*(cf != 1); i--; )
266 >                                rop->preop.cmat[j*nc+i] *= cf;
267                          break;
268                  case 'S':               /* scotopic (il)luminance */
269 +                        cf = WHTSCOTOPIC;
270 +                        /* fall through */
271 +                case 's':
272                          sensrow(rop, j, scolor2scotopic);
273 <                        for (i = nc; i--; )
274 <                                rop->preop.cmat[j*nc+i] *= WHTSCOTOPIC;
273 >                        for (i = nc*(cf != 1); i--; )
274 >                                rop->preop.cmat[j*nc+i] *= cf;
275                          break;
276                  case 'M':               /* melanopic (il)luminance */
277 +                        cf = WHTMELANOPIC;
278 +                        /* fall through */
279 +                case 'm':
280                          sensrow(rop, j, scolor2melanopic);
281 <                        for (i = nc; i--; )
282 <                                rop->preop.cmat[j*nc+i] *= WHTMELANOPIC;
281 >                        for (i = nc*(cf != 1); i--; )
282 >                                rop->preop.cmat[j*nc+i] *= cf;
283                          break;
284                  case 'A':               /* average component */
285 +                case 'a':
286                          for (i = nc; i--; )
287                                  rop->preop.cmat[j*nc+i] = 1./(double)nc;
288                          break;
# Line 267 | Line 297 | checksymbolic(ROPMAT *rop)
297          memcpy(rop->rmp->wlpart, WLPART, sizeof(rop->rmp->wlpart));
298          rop->rmp->ncomp = rop->preop.clen / nc;
299                                          /* decide on output type */
300 <        if (!strcmp(rop->preop.csym, "XYZ")) {
300 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
301                  if (dt <= DTspec)
302                          rop->rmp->dtype = DTxyze;
303 <        } else if (!strcmp(rop->preop.csym, "RGB")) {
303 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
304                  if (dt <= DTspec)
305                          rop->rmp->dtype = DTrgbe;
306          } else if (rop->rmp->dtype == DTspec)
# Line 374 | Line 404 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
404                          return(0);
405                  rmx_free(res);
406          } else if (dst != src)
407 <                memcpy(dst->mtx, src->mtx,
378 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
407 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
408          if (ro->nsf == dst->ncomp)
409                  rmx_scale(dst, ro->sca);
410          return(1);
# Line 523 | Line 552 | output_headinfo(FILE *fp)
552   }
553  
554   static int
555 < combine_input(ROPMAT *res, FILE *fout)
555 > spawned_children(int np)
556   {
557 <        int     set_r, set_c;
558 <        RMATRIX *tmp = NULL;
559 <        int     co_set;
560 <        int     i;
561 <                                        /* allocate input row buffers */
557 >        size_t  recsize = 0;
558 >        int     i, rv;
559 >
560 > #if defined(_WIN32) || defined(_WIN64)
561 >        if (np > 1) {
562 >                fputs("Warning: only one process under Windows\n", stderr);
563 >                np = 1;
564 >        } else
565 > #endif
566 >        if ((in_nrows > 0) & (np*4 > in_nrows))
567 >                np = in_nrows/4;
568 >                                /* we'll be doing a row at a time */
569          for (i = 0; i < nmats; i++) {
570 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
570 >                mop[i].imx.nrows = 1;
571                  if (!rmx_prepare(&mop[i].imx))
572                          goto memerror;
573 +                recsize += rmx_array_size(&mop[i].imx);
574                  if (mop[i].rmp != &mop[i].imx) {
575                          mop[i].rmp->nrows = 1;
576                          if (!rmx_prepare(mop[i].rmp))
577                                  goto memerror;
578                  }
579          }
580 <                                        /* prep output row buffers */
581 <        if (mcat || res->preop.clen > 0) {
582 <                if (!split_input(res))  /* need separate buffer */
580 >                                /* prep output row buffer */
581 >        if (mcat || mop[nmats].preop.clen > 0) {
582 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
583                          return(0);
584 <                if (res->preop.clen > 0)
585 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
586 <                res->rmp->nrows = 1;
587 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
584 >                if (mop[nmats].preop.clen > 0)
585 >                        mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
586 >                                                mop[nmats].imx.ncomp;
587 >                mop[nmats].rmp->nrows = 1;
588 >                if (!mcat | !mcat_last && !rmx_prepare(mop[nmats].rmp))
589                          goto memerror;
590          }
591 +        mop[nmats].imx.nrows = 1;
592 +        if (!rmx_prepare(&mop[nmats].imx))
593 +                goto memerror;
594 +        if (np <= 1) {          /* single process return */
595 + #ifdef getc_unlocked
596 +                for (i = 0; i < nmats; i++)
597 +                        flockfile(mop[i].infp);
598 +                flockfile(stdout);
599 + #endif
600 +                return(0);
601 +        }
602 +        fflush(stdout);         /* flush header & spawn children */
603 +        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*np);
604 +        if (!cproc)
605 +                goto memerror;
606 +        nchildren = np;
607 +        for (i = 0; i < np; i++) {
608 +                cproc[i].flags = PF_FILT_OUT;
609 +                cproc[i].w = dup(1);
610 +                cproc[i].r = 0;
611 +                cproc[i].pid = -1;
612 +                rv = open_process(&cproc[i], NULL);
613 +                if (rv <= 0) break;
614 +                if (!i && 2*rv >= recsize) {
615 +                        fputs("Problem too small for multi-processing\n",
616 +                                        stderr);
617 +                        close_processes(cproc, 1);
618 +                        exit(1);
619 +                }
620 +        }
621 +        if (rv < 0) {
622 +                perror("fork");
623 +                close_processes(cproc, i);
624 +                exit(1);
625 +        }
626 +        if (rv > 0)             /* parent return? */
627 +                return(1);
628 +        inchild = i;            /* our child index */
629 +        while (i-- > 0)         /* don't share siblings' pipes */
630 +                close(cproc[i].w);
631 +        fpurge(stdin);          /* discard previous matrix input */
632 + #ifdef getc_unlocked
633 +        flockfile(stdin);
634 + #endif
635 +        for (i = 0; i < nmats; i++) {
636 +                if (mop[i].infp != stdin)
637 +                        fclose(mop[i].infp);    /* ! pclose() */
638 +                mop[i].infp = stdin;
639 +                mop[i].imx.dtype = DTdouble;
640 +                mop[i].imx.pflags &= ~RMF_SWAPIN;
641 +        }
642 +        return(0);              /* child return */
643 + memerror:
644 +        fputs("Out of memory in spawned_children()\n", stderr);
645 +        exit(1);
646 + }
647 +
648 + static int
649 + parent_loop()
650 + {
651 +        FILE    **outfp = (FILE **)malloc(nchildren*sizeof(FILE *));
652 +        int     i;
653 +
654 +        if (!outfp) goto memerror;
655 +        for (i = 0; i < nchildren; i++) {
656 +                outfp[i] = fdopen(cproc[i].w, "w");
657 +                if (!outfp[i]) goto memerror;
658 + #ifdef getc_unlocked
659 +                flockfile(outfp[i]);
660 + #endif
661 +        }
662 + #ifdef getc_unlocked
663 +        for (i = 0; i < nmats; i++)
664 +                flockfile(mop[i].infp);
665 + #endif
666 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
667 +            FILE        *ofp = outfp[cur_row % nchildren];
668 +            for (i = 0; i < nmats; i++)
669 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
670 +                        if (cur_row > in_nrows) /* unknown #input rows? */
671 +                                break;
672 +                        fprintf(stderr, "%s: read error at row %d\n",
673 +                                        mop[i].inspec, cur_row);
674 +                        return(0);
675 +                }
676 +            if (i < nmats)
677 +                break;
678 +            for (i = 0; i < nmats; i++)
679 +                if (!rmx_write_data(mop[i].imx.mtx, mop[i].imx.ncomp,
680 +                                        mop[i].imx.ncols, DTdouble, ofp))
681 +                        return(0);
682 +            if (fflush(ofp) == EOF)
683 +                return(0);
684 +        }
685 +        for (i = 0; i < nchildren; i++) {       /* maintain output order */
686 +                sleep(1+(mop[nmats].rmp->ncols*mop[nmats].rmp->ncomp >> 15));
687 +                fclose(outfp[i]);
688 +        }
689 +        free(outfp);
690 +        i = close_processes(cproc, nchildren);
691 +        free(cproc); cproc = NULL;
692 +        if (i < 0) {
693 +                fputs("Warning: missing child in parent_loop()\n", stderr);
694 +                return(1);
695 +        }
696 +        if (i > 0) {
697 +                fprintf(stderr, "Child exited with status %d\n", i);
698 +                return(0);
699 +        }
700 +        return(1);
701 + memerror:
702 +        fputs("Out of memory in parent_loop()\n", stderr);
703 +        exit(1);
704 + }
705 +
706 + static int
707 + combine_input()
708 + {
709 +        const int       row0 = (inchild >= 0)*inchild;
710 +        const int       rstep = nchildren + !nchildren;
711 +        ROPMAT          *res = &mop[nmats];
712 +        int             set_r, set_c;
713 +        RMATRIX         *tmp = NULL;
714 +        int             co_set;
715 +        int             i;
716 +
717          if (mcat && mcat_last &&
718                          !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
719                  goto memerror;
556        res->imx.nrows = 1;
557        if (!rmx_prepare(&res->imx))
558                goto memerror;
720                                          /* figure out what the user set */
721          co_set = fundefined("co");
722          if (!co_set)
# Line 570 | Line 731 | combine_input(ROPMAT *res, FILE *fout)
731                  set_c = varlookup("c") != NULL && !vardefined("c");
732          } else                          /* save a little time */
733                  set_r = set_c = 0;
734 +
735                                          /* read/process row-by-row */
736 <        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
736 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
737              RMATRIX     *mres = NULL;
738 <            for (i = 0; i < nmats; i++) {
738 >            for (i = 0; i < nmats; i++)
739                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
740 <                        if (in_nrows <= 0)      /* normal end? */
741 <                                goto loop_exit;
740 >                        if (cur_row > in_nrows) /* unknown #input rows? */
741 >                                break;
742                          fprintf(stderr, "%s: read error at row %d\n",
743                                          mop[i].inspec, cur_row);
744                          return(0);
745                  }
746 +            if (i < nmats)
747 +                break;
748 +            for (i = 0; i < nmats; i++)
749                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
750                          return(0);
586            }
751              if (set_r) varset("r", '=', cur_row);
752              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
753                  if (set_c) varset("c", '=', cur_col);
# Line 620 | Line 784 | combine_input(ROPMAT *res, FILE *fout)
784                          return(0);
785              }
786              rmx_free(mres); mres = NULL;
787 +            if (inchild >= 0) {         /* children share stdout */
788 +                i = getc(stdin);        /* signals it's our turn */
789 +                if (i != EOF) ungetc(i, stdin);
790 +            }
791              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
792 <                                res->rmp->ncols, res->rmp->dtype, fout))
792 >                                res->rmp->ncols, res->rmp->dtype, stdout))
793                  return(0);
794 +            if (inchild >= 0 && fflush(stdout) == EOF)
795 +                return(0);
796          }
797 < loop_exit:
628 < #if 0           /* we're about to exit, so who cares? */
629 <        rmx_free(tmp);                  /* clean up */
630 <        rmx_reset(res->rmp);
631 <        rmx_reset(&res->imx);
632 <        for (i = 0; i < nmats; i++) {
633 <                rmx_reset(mop[i].rmp);
634 <                rmx_reset(&mop[i].imx);
635 <                if (mop[i].inspec[0] == '!')
636 <                        pclose(mop[i].infp);
637 <                else if (mop[i].inspec != stdin_name)
638 <                        fclose(mop[i].infp);
639 <                mop[i].infp = NULL;
640 <        }
641 < #endif
642 <        return(fflush(fout) != EOF);
797 >        return(inchild >= 0 || fflush(stdout) != EOF);
798   memerror:
799          fputs("Out of buffer space in combine_input()\n", stderr);
800          return(0);
# Line 663 | Line 818 | resize_inparr(int n2alloc)
818   {
819          int     i;
820  
821 <        for (i = nmats; i > n2alloc; i--) {
821 >        if (n2alloc == nall)
822 >                return;
823 >        for (i = nall; i > n2alloc; i--) {
824                  rmx_reset(&mop[i].imx);
825                  if (mop[i].rmp != &mop[i].imx)
826                          rmx_free(mop[i].rmp);
# Line 673 | Line 830 | resize_inparr(int n2alloc)
830                  fputs("Out of memory in resize_inparr()\n", stderr);
831                  exit(1);
832          }
833 <        if (n2alloc > nmats)
834 <                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
833 >        if (n2alloc > nall)
834 >                memset(mop+nall, 0, (n2alloc-nall)*sizeof(ROPMAT));
835          nall = n2alloc;
836   }
837  
# Line 687 | Line 844 | main(int argc, char *argv[])
844          const char      *defCsym = NULL;
845          int             echoheader = 1;
846          int             stdin_used = 0;
847 +        int             nproc = 1;
848          const char      *mcat_spec = NULL;
849          int             n2comp = 0;
850          uby8            comp_ndx[128];
# Line 714 | Line 872 | main(int argc, char *argv[])
872                          case 'h':
873                                  echoheader = !echoheader;
874                                  break;
875 +                        case 'n':
876 +                                nproc = atoi(argv[++i]);
877 +                                if (nproc <= 0)
878 +                                        goto userr;
879 +                                break;
880                          case 'e':
881                                  if (!n) goto userr;
882                                  comp_ndx[n2comp++] = i++;
# Line 762 | Line 925 | main(int argc, char *argv[])
925                                  if (n && !isflt(argv[i+1])) {
926                                          mop[nmats].preop.csym = argv[++i];
927                                          mop[nmats].preop.clen = 0;
928 +                                        mcat_last = 0;
929                                          break;
930                                  }
931                                  if (n > MAXCOMP*MAXCOMP) n = MAXCOMP*MAXCOMP;
# Line 851 | Line 1015 | main(int argc, char *argv[])
1015                  fprintf(stderr, "%s: unsupported output format\n", argv[0]);
1016                  return(1);
1017          }
1018 +        doptimize(1);                   /* optimize definitions */
1019 +        if (spawned_children(nproc))    /* running in parent process? */
1020 +                return(parent_loop() ? 0 : 1);
1021                                          /* process & write rows */
1022 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1022 >        return(combine_input() ? 0 : 1);
1023   stdin_error:
1024          fprintf(stderr, "%s: %s used for more than one input\n",
1025                          argv[0], stdin_name);
1026          return(1);
1027   userr:
1028          fprintf(stderr,
1029 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1029 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1030                          argv[0]);
1031          return(1);
1032   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines