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.1 by greg, Tue Dec 12 16:31:45 2023 UTC vs.
Revision 2.27 by greg, Sat Mar 1 01:37:49 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"
12 #include "resolu.h"
17   #include "rmatrix.h"
18   #include "calcomp.h"
15 #include "paths.h"
19  
20   #ifndef M_PI
21   #define M_PI    3.14159265358979323846
# Line 45 | Line 48 | int            nmats = 0;                      /* number of actual inputs */
48   RMATRIX         *mcat = NULL;                   /* final concatenation */
49   int             mcat_last = 0;                  /* goes after trailing ops? */
50  
51 < int             in_nrows;                       /* input row count */
52 < #define in_ncols        (mop[0].rmp->ncols)     /* input column count */
51 > int             in_nrows;                       /* number of input rows (or 0) */
52 > #define in_ncols        (mop[0].rmp->ncols)     /* number of input columns */
53   #define in_ncomp        (mop[0].rmp->ncomp)     /* input #components */
54  
55   extern int      nowarn;                         /* turn off warnings? */
# Line 55 | Line 58 | int            cur_row;                        /* current input/output row */
58   int             cur_col;                        /* current input/output column */
59   int             cur_chan;                       /* if we're looping channels */
60  
61 < static int      checksymbolic(ROPMAT *rop);
61 > SUBPROC         *cproc = NULL;                  /* child process array */
62 > int             nchildren = 0;                  /* # of child processes */
63 > int             inchild = -1;                   /* our child ID (-1: parent) */
64  
65 < static int
65 > extern int      checksymbolic(ROPMAT *rop);
66 >
67 > int
68   split_input(ROPMAT *rop)
69   {
70          if (rop->rmp == &rop->imx && !(rop->rmp = rmx_copy(&rop->imx))) {
# Line 69 | Line 76 | split_input(ROPMAT *rop)
76   }
77  
78   /* Check/set transform based on a reference input file */
79 < static int
79 > int
80   checkreffile(ROPMAT *rop)
81   {
82          static const char       *curRF = NULL;
# Line 132 | Line 139 | checkreffile(ROPMAT *rop)
139   }
140  
141   /* Compute conversion row from spectrum to one channel of RGB */
142 < static void
142 > void
143   rgbrow(ROPMAT *rop, int r, int p)
144   {
145          const int       nc = rop->imx.ncomp;
# Line 149 | Line 156 | rgbrow(ROPMAT *rop, int r, int p)
156   }
157  
158   /* Compute conversion row from spectrum to one channel of XYZ */
159 < static void
159 > void
160   xyzrow(ROPMAT *rop, int r, int p)
161   {
162          const int       nc = rop->imx.ncomp;
# Line 166 | Line 173 | xyzrow(ROPMAT *rop, int r, int p)
173   }
174  
175   /* Use the spectral sensitivity function to compute matrix coefficients */
176 < static void
177 < sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, int ncs, const float wlpt[4]))
176 > void
177 > sensrow(ROPMAT *rop, int r, double (*sf)(const SCOLOR sc, int ncs, const float wlpt[4]))
178   {
179          const int       nc = rop->imx.ncomp;
180          int             i;
# Line 181 | Line 188 | sensrow(ROPMAT *rop, int r, double (*sf)(SCOLOR sc, in
188   }
189  
190   /* Check/set symbolic transform */
191 < static int
191 > int
192   checksymbolic(ROPMAT *rop)
193   {
194          const int       nc = rop->imx.ncomp;
195          const int       dt = rop->imx.dtype;
196 +        double          cf = 1;
197          int             i, j;
198                                          /* check suffix => reference file */
199          if (strchr(rop->preop.csym, '.') > rop->preop.csym)
# Line 206 | Line 214 | checksymbolic(ROPMAT *rop)
214                  int     comp = 0;
215                  switch (rop->preop.csym[j]) {
216                  case 'B':
217 +                case 'b':
218                          ++comp;
219                          /* fall through */
220                  case 'G':
221 +                case 'g':
222                          ++comp;
223                          /* fall through */
224                  case 'R':
225 +                case 'r':
226 +                        if (rop->preop.csym[j] <= 'Z')
227 +                                cf = 1./WHTEFFICACY;
228                          if (dt == DTxyze) {
229                                  for (i = 3; i--; )
230 <                                        rop->preop.cmat[j*nc+i] = 1./WHTEFFICACY *
218 <                                                        xyz2rgbmat[comp][i];
230 >                                        rop->preop.cmat[j*nc+i] = cf*xyz2rgbmat[comp][i];
231                          } else if (nc == 3)
232                                  rop->preop.cmat[j*nc+comp] = 1.;
233                          else
234                                  rgbrow(rop, j, comp);
235                          break;
236                  case 'Z':
237 +                case 'z':
238                          ++comp;
239                          /* fall through */
240                  case 'Y':
241 +                case 'y':
242                          ++comp;
243                          /* fall through */
244                  case 'X':
245 +                case 'x':
246 +                        if ((rop->preop.csym[j] <= 'Z') & (dt != DTxyze))
247 +                                cf = WHTEFFICACY;
248                          if (dt == DTxyze) {
249                                  rop->preop.cmat[j*nc+comp] = 1.;
250                          } else if (nc == 3) {
# Line 239 | Line 256 | checksymbolic(ROPMAT *rop)
256                          else
257                                  xyzrow(rop, j, comp);
258  
259 <                        for (i = nc*(dt != DTxyze); i--; )
260 <                                rop->preop.cmat[j*nc+i] *= WHTEFFICACY;
259 >                        for (i = nc*(cf != 1); i--; )
260 >                                rop->preop.cmat[j*nc+i] *= cf;
261                          break;
262                  case 'S':               /* scotopic (il)luminance */
263 +                        cf = WHTSCOTOPIC;
264 +                        /* fall through */
265 +                case 's':
266                          sensrow(rop, j, scolor2scotopic);
267 <                        for (i = nc; i--; )
268 <                                rop->preop.cmat[j*nc+i] *= WHTSCOTOPIC;
267 >                        for (i = nc*(cf != 1); i--; )
268 >                                rop->preop.cmat[j*nc+i] *= cf;
269                          break;
270                  case 'M':               /* melanopic (il)luminance */
271 +                        cf = WHTMELANOPIC;
272 +                        /* fall through */
273 +                case 'm':
274                          sensrow(rop, j, scolor2melanopic);
275 <                        for (i = nc; i--; )
276 <                                rop->preop.cmat[j*nc+i] *= WHTMELANOPIC;
275 >                        for (i = nc*(cf != 1); i--; )
276 >                                rop->preop.cmat[j*nc+i] *= cf;
277                          break;
278                  case 'A':               /* average component */
279 +                case 'a':
280                          for (i = nc; i--; )
281                                  rop->preop.cmat[j*nc+i] = 1./(double)nc;
282                          break;
# Line 267 | Line 291 | checksymbolic(ROPMAT *rop)
291          memcpy(rop->rmp->wlpart, WLPART, sizeof(rop->rmp->wlpart));
292          rop->rmp->ncomp = rop->preop.clen / nc;
293                                          /* decide on output type */
294 <        if (!strcmp(rop->preop.csym, "XYZ")) {
294 >        if (!strcasecmp(rop->preop.csym, "XYZ")) {
295                  if (dt <= DTspec)
296                          rop->rmp->dtype = DTxyze;
297 <        } else if (!strcmp(rop->preop.csym, "RGB")) {
297 >        } else if (!strcasecmp(rop->preop.csym, "RGB")) {
298                  if (dt <= DTspec)
299                          rop->rmp->dtype = DTrgbe;
300          } else if (rop->rmp->dtype == DTspec)
# Line 278 | Line 302 | checksymbolic(ROPMAT *rop)
302          return(1);
303   }
304  
305 < static int
305 > int
306   get_component_xfm(ROPMAT *rop)
307   {
308          int     i, j;
# Line 361 | Line 385 | get_component_xfm(ROPMAT *rop)
385          return(1);
386   }
387  
388 < static int
388 > int
389   apply_op(RMATRIX *dst, const RMATRIX *src, const RUNARYOP *ro)
390   {
391          if (ro->clen > 0) {
# Line 374 | Line 398 | apply_op(RMATRIX *dst, const RMATRIX *src, const RUNAR
398                          return(0);
399                  rmx_free(res);
400          } else if (dst != src)
401 <                memcpy(dst->mtx, src->mtx,
378 <                                sizeof(double)*dst->ncomp*dst->ncols*dst->nrows);
401 >                memcpy(dst->mtx, src->mtx, rmx_array_size(dst));
402          if (ro->nsf == dst->ncomp)
403                  rmx_scale(dst, ro->sca);
404          return(1);
405   }
406  
407 < static int
407 > int
408   open_input(ROPMAT *rop)
409   {
410          int     outtype;
# Line 403 | Line 426 | open_input(ROPMAT *rop)
426   }
427  
428   /* Return nominal wavelength associated with input component (return nm) */
429 < static double
429 > double
430   l_wavelength(char *nam)
431   {
432          double  comp = argument(1);
# Line 427 | Line 450 | l_wavelength(char *nam)
450   }
451  
452   /* Return ith input with optional channel selector */
453 < static double
453 > double
454   l_chanin(char *nam)
455   {
456          double  inp = argument(1);
# Line 452 | Line 475 | l_chanin(char *nam)
475          return(mop[mi].rmp->mtx[cur_col*in_ncomp + chan]);
476   }
477  
478 < static int
478 > int
479   initialize(RMATRIX *imp)
480   {
481          int     i;
# Line 465 | Line 488 | initialize(RMATRIX *imp)
488                  restype = mop[i].rmp->dtype;
489                  if (!imp->dtype || (restype = rmx_newtype(restype, imp->dtype)) > 0)
490                          imp->dtype = restype;
491 <                else
491 >                else if (!nowarn)
492                          fprintf(stderr, "%s: warning - data type mismatch\n",
493                                          mop[i].inspec);
494                  if (!i) {
472                        imp->nrows = in_nrows = mop[0].rmp->nrows;
495                          imp->ncols = mop[0].rmp->ncols;
496                          imp->ncomp = mop[0].rmp->ncomp;
497                          memcpy(imp->wlpart, mop[0].rmp->wlpart, sizeof(imp->wlpart));
498 <                } else if ((mop[i].rmp->nrows != imp->nrows) |
499 <                                (mop[i].rmp->ncols != imp->ncols) |
500 <                                (mop[i].rmp->ncomp != imp->ncomp)) {
498 >                } else if ((mop[i].rmp->ncols != imp->ncols) |
499 >                                (mop[i].rmp->ncomp != imp->ncomp) |
500 >                                ((in_nrows > 0) & (mop[i].rmp->nrows > 0) &
501 >                                        (mop[i].rmp->nrows != in_nrows))) {
502                          fprintf(stderr, "%s: mismatch in size or #components\n",
503                                          mop[i].inspec);
504                          return(0);
505                  }                       /* XXX should check wlpart? */
506 +                if (in_nrows <= 0)
507 +                        in_nrows = imp->nrows = mop[i].rmp->nrows;
508          }                               /* set up .cal environment */
509          esupport |= E_VARIABLE|E_FUNCTION|E_RCONST;
510          esupport &= ~(E_OUTCHAN|E_INCHAN);
# Line 497 | Line 522 | initialize(RMATRIX *imp)
522          return(1);
523   }
524  
525 < static void
525 > void
526   output_headinfo(FILE *fp)
527   {
528          int     i;
# Line 520 | Line 545 | output_headinfo(FILE *fp)
545          }
546   }
547  
548 < static int
549 < combine_input(ROPMAT *res, FILE *fout)
548 > int
549 > spawned_children(int np)
550   {
551 <        int     set_r, set_c;
552 <        RMATRIX *tmp = NULL;
553 <        int     co_set;
554 <        int     i;
555 <                                        /* allocate input row buffers */
551 >        int     i, rv;
552 >
553 > #if defined(_WIN32) || defined(_WIN64)
554 >        if (np > 1) {
555 >                if (!nowarn)
556 >                        fputs("Warning: only one process under Windows\n", stderr);
557 >                np = 1;
558 >        } else
559 > #endif
560 >        if ((in_nrows > 0) & (np*4 > in_nrows))
561 >                np = in_nrows/4;
562 >                                /* we'll be doing a row at a time */
563          for (i = 0; i < nmats; i++) {
564 <                mop[i].imx.nrows = 1;   /* we'll be doing a row at a time */
564 >                mop[i].imx.nrows = 1;
565                  if (!rmx_prepare(&mop[i].imx))
566                          goto memerror;
567                  if (mop[i].rmp != &mop[i].imx) {
# Line 538 | Line 570 | combine_input(ROPMAT *res, FILE *fout)
570                                  goto memerror;
571                  }
572          }
573 <                                        /* prep output row buffers */
574 <        if (mcat || res->preop.clen > 0) {
575 <                if (!split_input(res))  /* need separate buffer */
544 <                        return(0);
545 <                if (res->preop.clen > 0)
546 <                        res->rmp->ncomp = res->preop.clen / res->imx.ncomp;
547 <                res->rmp->nrows = 1;
548 <                if (!mcat | !mcat_last && !rmx_prepare(res->rmp))
573 >                                /* prep output row buffer(s) */
574 >        if (mop[nmats].preop.clen > 0) {
575 >                if (!split_input(&mop[nmats]))  /* need separate buffer */
576                          goto memerror;
577 +                mop[nmats].rmp->ncomp = mop[nmats].preop.clen /
578 +                                        mop[nmats].imx.ncomp;
579          }
580 <        if (mcat && mcat_last &&
581 <                        !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp)))
580 >        mop[nmats].imx.nrows = 1;
581 >        if (!rmx_prepare(&mop[nmats].imx))
582                  goto memerror;
583 <        res->imx.nrows = 1;
584 <        if (!rmx_prepare(&res->imx))
583 >        if (mop[nmats].rmp != &mop[nmats].imx) {
584 >                mop[nmats].rmp->nrows = 1;
585 >                if (!rmx_prepare(mop[nmats].rmp))
586 >                        goto memerror;
587 >        }
588 >        if (np <= 1) {          /* single process return */
589 > #ifdef getc_unlocked
590 >                for (i = 0; i < nmats; i++)
591 >                        flockfile(mop[i].infp);
592 >                flockfile(stdout);
593 > #endif
594 >                return(0);
595 >        }
596 >        fflush(stdout);         /* flush header & spawn children */
597 >        nchildren = np + 1;     /* extra child to sequence output */
598 >        cproc = (SUBPROC *)malloc(sizeof(SUBPROC)*nchildren);
599 >        if (!cproc)
600                  goto memerror;
601 +        for (i = nchildren; i--; ) cproc[i] = sp_inactive;
602 +        cproc[nchildren-1].flags |= PF_FILT_OUT;
603 +                                /* start each child from parent */
604 +        for (i = 0; i < nchildren; i++)
605 +                if ((rv = open_process(&cproc[i], NULL)) <= 0)
606 +                        break;  /* child breaks here */
607 +        if (rv < 0) {
608 +                perror("fork"); /* WTH? */
609 +                close_processes(cproc, i);
610 +                exit(1);
611 +        }
612 +        if (i != nchildren-1) { /* last child is sole reader */
613 +                int     j = i;
614 +                while (j-- > 0) {
615 +                        close(cproc[j].r);
616 +                        cproc[j].r = -1;
617 +                }
618 +        }
619 +        if (rv > 0)
620 +                return(1);      /* parent return value */
621 +
622 +        inchild = i;            /* else set our child index */
623 +        while (i-- > 0)         /* only parent writes siblings */
624 +                close(cproc[i].w);
625 +
626 +        i = nmats;              /* close matrix streams (carefully) */
627 +        while (i-- > 0) {
628 +                if (mop[i].infp != stdin) {
629 +                        close(fileno(mop[i].infp));     /* avoid lseek() */
630 +                        fclose(mop[i].infp);            /* ! pclose() */
631 +                }
632 +                mop[i].infp = NULL;
633 +        }
634 +        fpurge(stdin);          /* discard previously buffered input */
635 +
636 +        if (inchild == nchildren-1)
637 +                return(-1);     /* output process return value */
638 +
639 +        i = nmats;              /* get matrix rows from parent */
640 +        while (i-- > 0) {
641 +                mop[i].infp = stdin;
642 +                mop[i].imx.dtype = DTrmx_native;
643 +                mop[i].imx.pflags &= ~RMF_SWAPIN;
644 +        }
645 + #ifdef getc_unlocked
646 +        flockfile(stdin);
647 + #endif
648 +        mop[nmats].rmp->dtype = DTrmx_native;
649 +        return(0);              /* worker child return value */
650 + memerror:
651 +        fputs("Out of memory in spawned_children()\n", stderr);
652 +        exit(1);
653 + }
654 +
655 + int
656 + parent_loop(void)
657 + {
658 +        int     i;
659 +
660 +        rmx_reset(&mop[nmats].imx);             /* not touching output side */
661 +        if (mop[nmats].rmp != &mop[nmats].imx) {
662 +                rmx_free(mop[nmats].rmp);
663 +                mop[nmats].rmp = &mop[nmats].imx;
664 +        }
665 + #ifdef getc_unlocked
666 +        for (i = 0; i < nmats; i++)             /* we handle matrix inputs */
667 +                flockfile(mop[i].infp);
668 + #endif
669 +                                                /* load & send rows to kids */
670 +        for (cur_row = 0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row++) {
671 +            int         wfd = cproc[cur_row % (nchildren-1)].w;
672 +            for (i = 0; i < nmats; i++)
673 +                if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
674 +                        if (cur_row > in_nrows) /* unknown #input rows? */
675 +                                break;
676 +                        fprintf(stderr, "%s: load error at row %d\n",
677 +                                        mop[i].inspec, cur_row);
678 +                        return(0);
679 +                }
680 +            if (i < nmats)
681 +                break;
682 +            for (i = 0; i < nmats; i++)
683 +                if (writebuf(wfd, mop[i].imx.mtx, rmx_array_size(&mop[i].imx))
684 +                                        != rmx_array_size(&mop[i].imx)) {
685 +                        fprintf(stderr, "%s: write error at row %d\n",
686 +                                        mop[i].inspec, cur_row);
687 +                        return(0);
688 +                }
689 +        }
690 +        i = close_processes(cproc, nchildren);  /* collect family */
691 +        free(cproc); cproc = NULL; nchildren = 0;
692 +        if (i < 0) {
693 +                if (!nowarn)
694 +                        fputs("Warning: lost child process\n", stderr);
695 +                return(1);
696 +        }
697 +        if (i > 0) {
698 +                fprintf(stderr, "Child exited with status %d\n", i);
699 +                return(0);
700 +        }
701 +        return(1);                              /* return success! */
702 + }
703 +
704 + int
705 + combine_input(void)
706 + {
707 +        const int       row0 = (inchild >= 0)*inchild;
708 +        const int       rstep = nchildren ? nchildren-1 : 1;
709 +        ROPMAT          *res = &mop[nmats];
710 +        int             set_r, set_c;
711 +        RMATRIX         *tmp = NULL;
712 +        int             co_set;
713 +        int             i;
714 +
715 +        if (mcat_last && !(tmp = rmx_alloc(1, res->imx.ncols, res->rmp->ncomp))) {
716 +                fputs("Out of buffer space in combine_input()\n", stderr);
717 +                return(0);
718 +        }
719                                          /* figure out what the user set */
720          co_set = fundefined("co");
721          if (!co_set)
# Line 569 | Line 731 | combine_input(ROPMAT *res, FILE *fout)
731          } else                          /* save a little time */
732                  set_r = set_c = 0;
733                                          /* read/process row-by-row */
734 <        for (cur_row = 0; cur_row < in_nrows; cur_row++) {
734 >        for (cur_row = row0; (in_nrows <= 0) | (cur_row < in_nrows); cur_row += rstep) {
735              RMATRIX     *mres = NULL;
736 <            for (i = 0; i < nmats; i++) {
736 >            for (i = 0; i < nmats; i++)
737                  if (!rmx_load_row(mop[i].imx.mtx, &mop[i].imx, mop[i].infp)) {
738 <                        fprintf(stderr, "%s: read error at row %d\n",
738 >                        if (cur_row > in_nrows) /* unknown #input rows? */
739 >                                break;
740 >                        fprintf(stderr, "%s: load error at row %d\n",
741                                          mop[i].inspec, cur_row);
742                          return(0);
743                  }
744 +            if (i < nmats)
745 +                break;
746 +            for (i = 0; i < nmats; i++)
747                  if (!apply_op(mop[i].rmp, &mop[i].imx, &mop[i].preop))
748                          return(0);
582            }
749              if (set_r) varset("r", '=', cur_row);
750              for (cur_col = 0; cur_col < in_ncols; cur_col++) {
751                  if (set_c) varset("c", '=', cur_col);
# Line 617 | Line 783 | combine_input(ROPMAT *res, FILE *fout)
783              }
784              rmx_free(mres); mres = NULL;
785              if (!rmx_write_data(res->rmp->mtx, res->rmp->ncomp,
786 <                                res->rmp->ncols, res->rmp->dtype, fout))
786 >                                res->rmp->ncols, res->rmp->dtype, stdout) ||
787 >                                 (inchild >= 0 && fflush(stdout) == EOF)) {
788 >                fprintf(stderr, "Conversion/write error at row %d\n",
789 >                                cur_row);
790                  return(0);
791 +            }
792          }
793 < #if 0           /* we're about to exit, so who cares? */
794 <        rmx_free(tmp);                  /* clean up */
795 <        rmx_reset(res->rmp);
796 <        rmx_reset(&res->imx);
797 <        for (i = 0; i < nmats; i++) {
798 <                rmx_reset(mop[i].rmp);
793 >        return(inchild >= 0 || fflush(stdout) != EOF);
794 > multerror:
795 >        fputs("Unexpected matrix multiply error\n", stderr);
796 >        return(0);
797 > }
798 >
799 > int
800 > output_loop(void)
801 > {
802 >        const size_t    row_size = rmx_array_size(mop[nmats].rmp);
803 >        int             cur_child = 0;
804 >        int             i = nmats;
805 >
806 >        while (i-- > 0) {                               /* free input buffers */
807                  rmx_reset(&mop[i].imx);
808 <                if (mop[i].inspec[0] == '!')
809 <                        pclose(mop[i].infp);
810 <                else if (mop[i].inspec != stdin_name)
811 <                        fclose(mop[i].infp);
634 <                mop[i].infp = NULL;
808 >                if (mop[i].rmp != &mop[i].imx) {
809 >                        rmx_free(mop[i].rmp);
810 >                        mop[i].rmp = &mop[i].imx;
811 >                }
812          }
813 +        if (mop[nmats].rmp != &mop[nmats].imx)          /* output is split? */
814 +                rmx_reset(&mop[nmats].imx);
815 + #ifdef getc_unlocked
816 +        flockfile(stdout);                              /* we own this, now */
817   #endif
818 <        return(fflush(fout) != EOF);
819 < memerror:
820 <        fputs("Out of buffer space in combine_input()\n", stderr);
821 <        return(0);
822 < multerror:
823 <        fputs("Unexpected matrix multiply error in combine_input()\n", stderr);
824 <        return(0);
818 >        for ( ; ; ) {                                   /* loop until no more */
819 >                ssize_t         rv;
820 >                rv = readbuf(cproc[cur_child].r, mop[nmats].rmp->mtx, row_size);
821 >                if (!rv)                                /* out of rows? */
822 >                        break;
823 >                if (rv != row_size) {
824 >                        fputs("Read error\n", stderr);
825 >                        return(0);
826 >                }                                       /* do final conversion */
827 >                if (!rmx_write_data(mop[nmats].rmp->mtx, mop[nmats].rmp->ncomp,
828 >                                mop[nmats].rmp->ncols, mop[nmats].rmp->dtype, stdout)) {
829 >                        fputs("Conversion/write error\n", stderr);
830 >                        return(0);
831 >                }
832 >                cur_child++;
833 >                cur_child *= (cur_child < inchild);     /* loop over workers */
834 >        }
835 >        return(fflush(stdout) != EOF);
836   }
837  
838 < static int
838 > int
839   get_factors(double da[], int n, char *av[])
840   {
841          int     ac;
# Line 653 | Line 845 | get_factors(double da[], int n, char *av[])
845          return(ac);
846   }
847  
848 < static void
848 > void
849   resize_inparr(int n2alloc)
850   {
851          int     i;
852  
853 <        for (i = nmats; i > n2alloc; i--) {
853 >        if (n2alloc == nall)
854 >                return;
855 >        for (i = nall; i-- > n2alloc; ) {
856                  rmx_reset(&mop[i].imx);
857                  if (mop[i].rmp != &mop[i].imx)
858                          rmx_free(mop[i].rmp);
# Line 668 | Line 862 | resize_inparr(int n2alloc)
862                  fputs("Out of memory in resize_inparr()\n", stderr);
863                  exit(1);
864          }
865 <        if (n2alloc > nmats)
866 <                memset(mop+nmats, 0, (n2alloc-nmats)*sizeof(ROPMAT));
865 >        if (n2alloc > nall)
866 >                memset(mop+nall, 0, (n2alloc-nall)*sizeof(ROPMAT));
867          nall = n2alloc;
868   }
869  
# Line 682 | Line 876 | main(int argc, char *argv[])
876          const char      *defCsym = NULL;
877          int             echoheader = 1;
878          int             stdin_used = 0;
879 +        int             nproc = 1;
880          const char      *mcat_spec = NULL;
881          int             n2comp = 0;
882          uby8            comp_ndx[128];
# Line 709 | Line 904 | main(int argc, char *argv[])
904                          case 'h':
905                                  echoheader = !echoheader;
906                                  break;
907 +                        case 'n':
908 +                                nproc = atoi(argv[++i]);
909 +                                if (nproc <= 0)
910 +                                        goto userr;
911 +                                break;
912                          case 'e':
913                                  if (!n) goto userr;
914                                  comp_ndx[n2comp++] = i++;
# Line 747 | Line 947 | main(int argc, char *argv[])
947                                  }
948                                  break;
949                          case 'C':
950 +                                mcat_last = 0;
951                                  if (!n || isflt(argv[i+1]))
952                                          goto userr;
953                                  defCsym = mop[nmats].preop.csym = argv[++i];
954                                  mop[nmats].preop.clen = 0;
754                                mcat_last = 0;
955                                  break;
956                          case 'c':
957 +                                mcat_last = 0;
958                                  if (n && !isflt(argv[i+1])) {
959                                          mop[nmats].preop.csym = argv[++i];
960                                          mop[nmats].preop.clen = 0;
# Line 769 | Line 970 | main(int argc, char *argv[])
970                                          goto userr;
971                                  }
972                                  mop[nmats].preop.csym = NULL;
772                                mcat_last = 0;
973                                  break;
974                          case 'm':
975 +                                mcat_last = 1;
976                                  if (!n) goto userr;
977                                  if (argv[++i][0] == '-' && !argv[i][1]) {
978                                          if (stdin_used++) goto stdin_error;
979                                          mcat_spec = stdin_name;
980                                  } else
981                                          mcat_spec = argv[i];
781                                mcat_last = 1;
982                                  break;
983                          default:
984                                  fprintf(stderr, "%s: unknown option '%s'\n",
# Line 846 | Line 1046 | main(int argc, char *argv[])
1046                  fprintf(stderr, "%s: unsupported output format\n", argv[0]);
1047                  return(1);
1048          }
1049 <                                        /* process & write rows */
1050 <        return(combine_input(&mop[nmats], stdout) ? 0 : 1);
1049 >        doptimize(1);                   /* optimize definitions */
1050 >        i = spawned_children(nproc);    /* create multiple processes if requested */
1051 >        if (i > 0)                      /* running in parent process? */
1052 >                return(parent_loop() ? 0 : 1);
1053 >        if (i < 0)                      /* running in output process? */
1054 >                return(output_loop() ? 0 : 1);
1055 >                                        /* else we are a worker process */
1056 >        return(combine_input() ? 0 : 1);
1057   stdin_error:
1058          fprintf(stderr, "%s: %s used for more than one input\n",
1059                          argv[0], stdin_name);
1060          return(1);
1061   userr:
1062          fprintf(stderr,
1063 <        "Usage: %s [-h][-f{adfc}][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1063 >        "Usage: %s [-h][-f{adfc}][-n nproc][-e expr][-f file][-s sf .. | -c ce ..] m1 .. -m mcat > mres\n",
1064                          argv[0]);
1065          return(1);
1066   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines