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.8 by greg, Thu May 16 18:59:19 2024 UTC vs.
Revision 2.31 by greg, Fri Apr 18 23:59:03 2025 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 original process.  Final conversion
9 + * and output to stdout is sorted by last child while its siblings send it
10 + * their record calculations.
11   */
12  
8 #include <errno.h>
13   #include <math.h>
14   #include "platform.h"
15 + #include "rtprocess.h"
16   #include "rtio.h"
17   #include "rmatrix.h"
18   #include "calcomp.h"
14 #include "paths.h"
19  
20   #ifndef M_PI
21   #define M_PI    3.14159265358979323846
22   #endif
23  
20 #define MAXCOMP         MAXCSAMP        /* #components we support */
21
24   /* Unary matrix operation(s) */
25   typedef struct {
26          double          cmat[MAXCOMP*MAXCOMP];  /* component transformation */
# Line 54 | Line 56 | int            cur_row;                        /* current input/output row */
56   int             cur_col;                        /* current input/output column */
57   int             cur_chan;                       /* if we're looping channels */
58  
59 < static int      checksymbolic(ROPMAT *rop);
59 > SUBPROC         *cproc = NULL;                  /* child process array */
60 > int             nchildren = 0;                  /* # of child processes */
61 > int             inchild = -1;                   /* our child ID (-1: parent) */
62  
63 < static int
63 > extern int      checksymbolic(ROPMAT *rop);
64 >
65 > int
66   split_input(ROPMAT *rop)
67   {
68          if (rop->rmp == &rop->imx && !(rop->rmp = rmx_copy(&rop->imx))) {
# Line 68 | Line 74 | split_input(ROPMAT *rop)
74   }
75  
76   /* Check/set transform based on a reference input file */
77 < static int
77 > int
78   checkreffile(ROPMAT *rop)
79   {
80          static const char       *curRF = NULL;
# Line 131 | Line 137 | checkreffile(ROPMAT *rop)
137   }
138  
139   /* Compute conversion row from spectrum to one channel of RGB */
140 < static void
140 > void
141   rgbrow(ROPMAT *rop, int r, int p)
142   {
143          const int       nc = rop->imx.ncomp;
# Line 148 | Line 154 | rgbrow(ROPMAT *rop, int r, int p)
154   }
155  
156   /* Compute conversion row from spectrum to one channel of XYZ */
157 < static void
157 > void
158   xyzrow(ROPMAT *rop, int r, int p)
159   {
160          const int       nc = rop->imx.ncomp;
# Line 165 | Line 171 | xyzrow(ROPMAT *rop, int r, int p)
171   }
172  
173   /* Use the spectral sensitivity function to compute matrix coefficients */
174 < static void
175 < sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, int ncs, const float wlpt[4]))
174 > void
175 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
176   {
177          const int       nc = rop->imx.ncomp;
178          int             i;
# Line 180 | Line 186 | sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, in
186   }
187  
188   /* Check/set symbolic transform */
189 < static int
189 > int
190   checksymbolic(ROPMAT *rop)
191   {
192          const int       nc = rop->imx.ncomp;
# Line 294 | Line 300 | checksymbolic(ROPMAT *rop)
300          return(1);
301   }
302  
303 < static int
303 > int
304   get_component_xfm(ROPMAT *rop)
305   {
306          int     i, j;
# Line 377 | Line 383 | get_component_xfm(ROPMAT *rop)
383          return(1);
384   }
385  
386 < static int
386 > int
387   apply_op(RMATRIX *dst, const RMATRIX *src, const RUNARYOP *ro)
388   {
389          if (ro->clen > 0) {
# Line 390 | Line 396 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
396                          return(0);
397                  rmx_free(res);
398          } else if (dst != src)
399 <                memcpy(dst->mtx, src->mtx,
394 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
399 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
400          if (ro->nsf == dst->ncomp)
401                  rmx_scale(dst, ro->sca);
402          return(1);
403   }
404  
405 < static int
405 > int
406   open_input(ROPMAT *rop)
407   {
408          int     outtype;
# Line 419 | Line 424 | open_input(ROPMAT *rop)
424   }
425  
426   /* Return nominal wavelength associated with input component (return nm) */
427 < static double
427 > double
428   l_wavelength(char *nam)
429   {
430          double  comp = argument(1);
# Line 443 | Line 448 | l_wavelength(char *nam)
448   }
449  
450   /* Return ith input with optional channel selector */
451 < static double
451 > double
452   l_chanin(char *nam)
453   {
454          double  inp = argument(1);
# Line 468 | Line 473 | l_chanin(char *nam)
473          return(mop[mi].rmp->mtx[cur_col*in_ncomp + chan]);
474   }
475  
476 < static int
476 > int
477   initialize(RMATRIX *imp)
478   {
479          int     i;
# Line 481 | Line 486 | initialize(RMATRIX *imp)
486                  restype = mop[i].rmp->dtype;
487                  if (!imp->dtype || (restype = rmx_newtype(restype, imp->dtype)) > 0)
488                          imp->dtype = restype;
489 <                else
489 >                else if (!nowarn)
490                          fprintf(stderr, "%s: warning - data type mismatch\n",
491                                          mop[i].inspec);
492                  if (!i) {
# Line 515 | Line 520 | initialize(RMATRIX *imp)
520          return(1);
521   }
522  
523 < static void
523 > void
524   output_headinfo(FILE *fp)
525   {
526          int     i;
# Line 538 | Line 543 | output_headinfo(FILE *fp)
543          }
544   }
545  
546 < static int
547 < combine_input(ROPMAT *res, FILE *fout)
546 > int
547 > spawned_children(int np)
548   {
549 <        int     set_r, set_c;
550 <        RMATRIX *tmp = NULL;
551 <        int     co_set;
552 <        int     i;
553 <                                        /* allocate input row buffers */
549 >        int     i, rv;
550 >
551 > #if defined(_WIN32) || defined(_WIN64)
552 >        if (np > 1) {
553 >                if (!nowarn)
554 >                        fputs("Warning: only one process under Windows\n", stderr);
555 >                np = 1;
556 >        } else
557 > #endif
558 >        if ((in_nrows > 0) & (np*4 > in_nrows))
559 >                np = in_nrows/4;
560 >                                /* we'll be doing a row at a time */
561          for (i = 0; i < nmats; i++) {
562 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
562 >                mop[i].imx.nrows = 1;
563                  if (!rmx_prepare(&mop[i].imx))
564                          goto memerror;
565                  if (mop[i].rmp != &mop[i].imx) {
# Line 556 | Line 568 | combine_input(ROPMAT *res, FILE *fout)
568                                  goto memerror;
569                  }
570          }
571 <                                        /* prep output row buffers */
572 <        if (mcat || res->preop.clen > 0) {
573 <                if (!split_input(res))  /* need separate buffer */
562 <                        return(0);
563 <                if (res->preop.clen > 0)
564 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
565 <                res->rmp->nrows = 1;
566 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
571 >                                /* prep output row buffer(s) */
572 >        if (mop[nmats].preop.clen > 0) {
573 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
574                          goto memerror;
575 +                mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
576 +                                        mop[nmats].imx.ncomp;
577          }
578 <        if (mcat && mcat_last &&
579 <                        !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
578 >        mop[nmats].imx.nrows = 1;
579 >        if (!rmx_prepare(&mop[nmats].imx))
580                  goto memerror;
581 <        res->imx.nrows = 1;
582 <        if (!rmx_prepare(&res->imx))
581 >        if (mop[nmats].rmp != &mop[nmats].imx) {
582 >                mop[nmats].rmp->nrows = 1;
583 >                if (!rmx_prepare(mop[nmats].rmp))
584 >                        goto memerror;
585 >        }
586 >        if (np <= 1) {          /* single process return */
587 > #ifdef getc_unlocked
588 >                for (i = 0; i < nmats; i++)
589 >                        flockfile(mop[i].infp);
590 >                flockfile(stdout);
591 > #endif
592 >                return(0);
593 >        }
594 >        fflush(stdout);         /* flush header & spawn children */
595 >        nchildren = np + 1;     /* extra child to sequence output */
596 >        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*nchildren);
597 >        if (!cproc)
598                  goto memerror;
599 +        for (i = nchildren; i--; ) cproc[i] = sp_inactive;
600 +        cproc[nchildren-1].flags |= PF_FILT_OUT;
601 +                                /* start each child from parent */
602 +        for (i = 0; i < nchildren; i++)
603 +                if ((rv = open_process(&cproc[i], NULL)) <= 0)
604 +                        break;  /* child breaks here */
605 +        if (rv < 0) {
606 +                perror("fork"); /* WTH? */
607 +                close_processes(cproc, i);
608 +                exit(1);
609 +        }
610 +        if (i != nchildren-1) { /* last child is sole reader */
611 +                int     j = i;
612 +                while (j-- > 0) {
613 +                        close(cproc[j].r);
614 +                        cproc[j].r = -1;
615 +                }
616 +        }
617 +        if (rv > 0)
618 +                return(1);      /* parent return value */
619 +
620 +        inchild = i;            /* else set our child index */
621 +        while (i-- > 0)         /* only parent writes siblings */
622 +                close(cproc[i].w);
623 +
624 +        i = nmats;              /* close matrix streams (carefully) */
625 +        while (i-- > 0) {
626 +                if (mop[i].infp != stdin) {
627 +                        close(fileno(mop[i].infp));     /* avoid lseek() */
628 +                        fclose(mop[i].infp);            /* ! pclose() */
629 +                }
630 +                mop[i].infp = NULL;
631 +        }
632 +        fpurge(stdin);          /* discard previously buffered input */
633 +
634 +        if (inchild == nchildren-1)
635 +                return(-1);     /* output process return value */
636 +
637 +        i = nmats;              /* get matrix rows from parent */
638 +        while (i-- > 0) {
639 +                mop[i].infp = stdin;
640 +                mop[i].imx.dtype = DTrmx_native;
641 +                mop[i].imx.pflags &= ~RMF_SWAPIN;
642 +        }
643 + #ifdef getc_unlocked
644 +        flockfile(stdin);
645 + #endif
646 +        mop[nmats].rmp->dtype = DTrmx_native;
647 +        return(0);              /* worker child return value */
648 + memerror:
649 +        fputs("Out of memory in spawned_children()\n", stderr);
650 +        exit(1);
651 + }
652 +
653 + int
654 + parent_loop(void)
655 + {
656 +        int     i;
657 +
658 +        rmx_reset(&mop[nmats].imx);             /* not touching output side */
659 +        if (mop[nmats].rmp != &mop[nmats].imx) {
660 +                rmx_free(mop[nmats].rmp);
661 +                mop[nmats].rmp = &mop[nmats].imx;
662 +        }
663 + #ifdef getc_unlocked
664 +        for (i = 0; i < nmats; i++)             /* we handle matrix inputs */
665 +                flockfile(mop[i].infp);
666 + #endif
667 +                                                /* load & send rows to kids */
668 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
669 +            int         wfd = cproc[cur_row % (nchildren-1)].w;
670 +            for (i = 0; i < nmats; i++)
671 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
672 +                        if (cur_row > in_nrows) /* unknown #input rows? */
673 +                                break;
674 +                        fprintf(stderr, "%s: load error at row %d\n",
675 +                                        mop[i].inspec, cur_row);
676 +                        return(0);
677 +                }
678 +            if (i < nmats)
679 +                break;
680 +            for (i = 0; i < nmats; i++)
681 +                if (writebuf(wfd, mop[i].imx.mtx, rmx_array_size(&mop[i].imx))
682 +                                        != rmx_array_size(&mop[i].imx)) {
683 +                        fprintf(stderr, "%s: write error at row %d\n",
684 +                                        mop[i].inspec, cur_row);
685 +                        return(0);
686 +                }
687 +        }
688 +        i = close_processes(cproc, nchildren);  /* collect family */
689 +        free(cproc); cproc = NULL; nchildren = 0;
690 +        if (i < 0) {
691 +                if (!nowarn)
692 +                        fputs("Warning: lost child process\n", stderr);
693 +                return(1);
694 +        }
695 +        if (i > 0) {
696 +                fprintf(stderr, "Child exited with status %d\n", i);
697 +                return(0);
698 +        }
699 +        return(1);                              /* return success! */
700 + }
701 +
702 + int
703 + combine_input(void)
704 + {
705 +        const int       row0 = (inchild >= 0)*inchild;
706 +        const int       rstep = nchildren ? nchildren-1 : 1;
707 +        ROPMAT          *res = &mop[nmats];
708 +        int             set_r, set_c;
709 +        RMATRIX         *tmp = NULL;
710 +        int             co_set;
711 +        int             i;
712 +
713 +        if (mcat_last && !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp))) {
714 +                fputs("Out of buffer space in combine_input()\n", stderr);
715 +                return(0);
716 +        }
717                                          /* figure out what the user set */
718          co_set = fundefined("co");
719          if (!co_set)
# Line 587 | Line 729 | combine_input(ROPMAT *res, FILE *fout)
729          } else                          /* save a little time */
730                  set_r = set_c = 0;
731                                          /* read/process row-by-row */
732 <        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
732 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
733              RMATRIX     *mres = NULL;
734 <            for (i = 0; i < nmats; i++) {
734 >            for (i = 0; i < nmats; i++)
735                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
736                          if (cur_row > in_nrows) /* unknown #input rows? */
737 <                                goto loop_exit;
738 <                        fprintf(stderr, "%s: read error at row %d\n",
737 >                                break;
738 >                        fprintf(stderr, "%s: load error at row %d\n",
739                                          mop[i].inspec, cur_row);
740                          return(0);
741                  }
742 +            if (i < nmats)
743 +                break;
744 +            for (i = 0; i < nmats; i++)
745                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
746                          return(0);
602            }
747              if (set_r) varset("r", '=', cur_row);
748              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
749                  if (set_c) varset("c", '=', cur_col);
# Line 637 | Line 781 | combine_input(ROPMAT *res, FILE *fout)
781              }
782              rmx_free(mres); mres = NULL;
783              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
784 <                                res->rmp->ncols, res->rmp->dtype, fout))
784 >                                res->rmp->ncols, res->rmp->dtype, stdout) ||
785 >                                 (inchild >= 0 && fflush(stdout) == EOF)) {
786 >                fprintf(stderr, "Conversion/write error at row %d\n",
787 >                                cur_row);
788                  return(0);
789 +            }
790          }
791 < loop_exit:
792 < #if 0           /* we're about to exit, so who cares? */
793 <        rmx_free(tmp);                  /* clean up */
794 <        rmx_reset(res->rmp);
795 <        rmx_reset(&res->imx);
796 <        for (i = 0; i < nmats; i++) {
797 <                rmx_reset(mop[i].rmp);
791 >        return(inchild >= 0 || fflush(stdout) != EOF);
792 > multerror:
793 >        fputs("Unexpected matrix multiply error\n", stderr);
794 >        return(0);
795 > }
796 >
797 > int
798 > output_loop(void)
799 > {
800 >        const size_t    row_size = rmx_array_size(mop[nmats].rmp);
801 >        int             cur_child = 0;
802 >        int             i = nmats;
803 >
804 >        while (i-- > 0) {                               /* free input buffers */
805                  rmx_reset(&mop[i].imx);
806 <                if (mop[i].inspec[0] == '!')
807 <                        pclose(mop[i].infp);
808 <                else if (mop[i].inspec != stdin_name)
809 <                        fclose(mop[i].infp);
655 <                mop[i].infp = NULL;
806 >                if (mop[i].rmp != &mop[i].imx) {
807 >                        rmx_free(mop[i].rmp);
808 >                        mop[i].rmp = &mop[i].imx;
809 >                }
810          }
811 +        if (mop[nmats].rmp != &mop[nmats].imx)          /* output is split? */
812 +                rmx_reset(&mop[nmats].imx);
813 + #ifdef getc_unlocked
814 +        flockfile(stdout);                              /* we own this, now */
815   #endif
816 <        return(fflush(fout) != EOF);
817 < memerror:
818 <        fputs("Out of buffer space in combine_input()\n", stderr);
819 <        return(0);
820 < multerror:
821 <        fputs("Unexpected matrix multiply error in combine_input()\n", stderr);
822 <        return(0);
816 >        for ( ; ; ) {                                   /* loop until no more */
817 >                ssize_t         rv;
818 >                rv = readbuf(cproc[cur_child].r, mop[nmats].rmp->mtx, row_size);
819 >                if (!rv)                                /* out of rows? */
820 >                        break;
821 >                if (rv != row_size) {
822 >                        fputs("Read error\n", stderr);
823 >                        return(0);
824 >                }                                       /* do final conversion */
825 >                if (!rmx_write_data(mop[nmats].rmp->mtx, mop[nmats].rmp->ncomp,
826 >                                mop[nmats].rmp->ncols, mop[nmats].rmp->dtype, stdout)) {
827 >                        fputs("Conversion/write error\n", stderr);
828 >                        return(0);
829 >                }
830 >                cur_child++;
831 >                cur_child *= (cur_child < inchild);     /* loop over workers */
832 >        }
833 >        return(fflush(stdout) != EOF);
834   }
835  
836 < static int
836 > int
837   get_factors(double da[], int n, char *av[])
838   {
839          int     ac;
# Line 674 | Line 843 | get_factors(double da[], int n, char *av[])
843          return(ac);
844   }
845  
846 < static void
846 > void
847   resize_inparr(int n2alloc)
848   {
849          int     i;
850  
851          if (n2alloc == nall)
852                  return;
853 <        for (i = nall; i > n2alloc; i--) {
853 >        for (i = nall; i-- > n2alloc; ) {
854                  rmx_reset(&mop[i].imx);
855                  if (mop[i].rmp != &mop[i].imx)
856                          rmx_free(mop[i].rmp);
# Line 705 | Line 874 | main(int argc, char *argv[])
874          const char      *defCsym = NULL;
875          int             echoheader = 1;
876          int             stdin_used = 0;
877 +        int             nproc = 1;
878          const char      *mcat_spec = NULL;
879          int             n2comp = 0;
880          uby8            comp_ndx[128];
# Line 732 | Line 902 | main(int argc, char *argv[])
902                          case 'h':
903                                  echoheader = !echoheader;
904                                  break;
905 +                        case 'n':
906 +                                nproc = atoi(argv[++i]);
907 +                                if (nproc <= 0)
908 +                                        goto userr;
909 +                                break;
910                          case 'e':
911                                  if (!n) goto userr;
912                                  comp_ndx[n2comp++] = i++;
# Line 770 | Line 945 | main(int argc, char *argv[])
945                                  }
946                                  break;
947                          case 'C':
948 +                                mcat_last = 0;
949                                  if (!n || isflt(argv[i+1]))
950                                          goto userr;
951                                  defCsym = mop[nmats].preop.csym = argv[++i];
952                                  mop[nmats].preop.clen = 0;
777                                mcat_last = 0;
953                                  break;
954                          case 'c':
955 +                                mcat_last = 0;
956                                  if (n && !isflt(argv[i+1])) {
957                                          mop[nmats].preop.csym = argv[++i];
958                                          mop[nmats].preop.clen = 0;
# Line 792 | Line 968 | main(int argc, char *argv[])
968                                          goto userr;
969                                  }
970                                  mop[nmats].preop.csym = NULL;
795                                mcat_last = 0;
971                                  break;
972                          case 'm':
973 +                                mcat_last = 1;
974                                  if (!n) goto userr;
975                                  if (argv[++i][0] == '-' && !argv[i][1]) {
976                                          if (stdin_used++) goto stdin_error;
977                                          mcat_spec = stdin_name;
978                                  } else
979                                          mcat_spec = argv[i];
804                                mcat_last = 1;
980                                  break;
981                          default:
982                                  fprintf(stderr, "%s: unknown option '%s'\n",
# Line 816 | Line 991 | main(int argc, char *argv[])
991          resize_inparr(nmats+1);         /* extra matrix at end for result */
992          mop[nmats].inspec = "trailing_ops";
993                                          /* load final concatenation matrix */
994 <        if (mcat_spec && !(mcat = rmx_load(mcat_spec, RMPnone))) {
994 >        if (mcat_spec && !(mcat = rmx_load(mcat_spec))) {
995                  fprintf(stderr, "%s: error loading concatenation matrix: %s\n",
996                                  argv[0], mcat_spec);
997                  return(1);
# Line 859 | Line 1034 | main(int argc, char *argv[])
1034                          return(1);
1035                  mop[nmats].rmp->ncols = mcat->ncols;
1036          }
1037 + #if DTrmx_native==DTfloat
1038 +        if (outfmt == DTdouble)
1039 +                fprintf(stderr, "%s: warning - writing float result as double\n", argv[0]);
1040 + #endif
1041          newheader("RADIANCE", stdout);  /* write output header */
1042          if (echoheader)
1043                  output_headinfo(stdout);
# Line 870 | Line 1049 | main(int argc, char *argv[])
1049                  return(1);
1050          }
1051          doptimize(1);                   /* optimize definitions */
1052 <                                        /* process & write rows */
1053 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1052 >        i = spawned_children(nproc);    /* create multiple processes if requested */
1053 >        if (i > 0)                      /* running in parent process? */
1054 >                return(parent_loop() ? 0 : 1);
1055 >        if (i < 0)                      /* running in output process? */
1056 >                return(output_loop() ? 0 : 1);
1057 >                                        /* else we are a worker process */
1058 >        return(combine_input() ? 0 : 1);
1059   stdin_error:
1060          fprintf(stderr, "%s: %s used for more than one input\n",
1061                          argv[0], stdin_name);
1062          return(1);
1063   userr:
1064          fprintf(stderr,
1065 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1065 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1066                          argv[0]);
1067          return(1);
1068   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines