ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/readobj.c
Revision: 2.30
Committed: Mon Jun 23 19:56:47 2025 UTC (2 weeks, 2 days ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.29: +107 -7 lines
Log Message:
perf: Consolidate object block memory to reduce malloc() fragmentation/overhead

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.30 static const char RCSid[] = "$Id: readobj.c,v 2.29 2025/06/07 05:09:45 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * readobj.c - routines for reading in object descriptions.
6     *
7 greg 2.8 * External symbols declared in object.h
8     */
9    
10 greg 2.9 #include "copyright.h"
11 greg 1.1
12 schorsch 2.13 #include <ctype.h>
13 schorsch 2.16 #include <string.h>
14 schorsch 2.14 #include <stdio.h>
15 schorsch 2.13
16 greg 2.17 #include "platform.h"
17 greg 1.1 #include "standard.h"
18     #include "object.h"
19     #include "otypes.h"
20    
21 greg 2.30 #ifndef OBJMEMOPT
22     #define OBJMEMOPT 1 /* optimize object block memory? */
23     #endif
24 greg 1.1
25     OBJREC *objblock[MAXOBJBLK]; /* our objects */
26 greg 1.4 OBJECT nobjects = 0; /* # of objects */
27 greg 1.1
28    
29 greg 2.8 void
30 greg 2.22 readobj( /* read in an object file or stream */
31     char *inpspec
32     )
33 greg 1.1 {
34 greg 2.4 OBJECT lastobj;
35 greg 1.1 FILE *infp;
36 greg 2.19 char buf[2048];
37 greg 2.22 int c;
38 greg 1.1
39 greg 2.4 lastobj = nobjects;
40     if (inpspec == NULL) {
41 greg 1.1 infp = stdin;
42 greg 2.4 inpspec = "standard input";
43     } else if (inpspec[0] == '!') {
44     if ((infp = popen(inpspec+1, "r")) == NULL) {
45     sprintf(errmsg, "cannot execute \"%s\"", inpspec);
46 greg 1.1 error(SYSTEM, errmsg);
47     }
48 greg 2.4 } else if ((infp = fopen(inpspec, "r")) == NULL) {
49     sprintf(errmsg, "cannot open scene file \"%s\"", inpspec);
50 greg 1.1 error(SYSTEM, errmsg);
51     }
52 greg 2.25 #ifdef getc_unlocked /* avoid stupid semaphores */
53     flockfile(infp);
54     #endif
55 greg 1.1 while ((c = getc(infp)) != EOF) {
56     if (isspace(c))
57     continue;
58     if (c == '#') { /* comment */
59     fgets(buf, sizeof(buf), infp);
60 greg 1.2 } else if (c == '!') { /* command */
61 greg 1.1 ungetc(c, infp);
62 greg 1.2 fgetline(buf, sizeof(buf), infp);
63 greg 1.1 readobj(buf);
64     } else { /* object */
65     ungetc(c, infp);
66 greg 2.4 getobject(inpspec, infp);
67 greg 1.1 }
68     }
69 greg 2.27 if (inpspec[0] == '!') {
70     if (pclose(infp) != 0) {
71     sprintf(errmsg, "bad status from \"%s\"", inpspec);
72 greg 2.28 error(WARNING, errmsg);
73 greg 2.27 }
74     } else if (infp != stdin)
75 greg 1.1 fclose(infp);
76 greg 2.25 #ifdef getc_unlocked
77     else
78     funlockfile(infp);
79     #endif
80 greg 2.4 if (nobjects == lastobj) {
81     sprintf(errmsg, "(%s): empty file", inpspec);
82     error(WARNING, errmsg);
83     }
84 greg 1.1 }
85    
86    
87 greg 2.8 void
88 greg 2.22 getobject( /* read the next object */
89     char *name,
90     FILE *fp
91     )
92 greg 1.1 {
93 greg 2.11 #define OALIAS -2
94 greg 1.1 OBJECT obj;
95     char sbuf[MAXSTR];
96 greg 1.6 int rval;
97 greg 2.22 OBJREC *objp;
98 greg 1.1
99     if ((obj = newobject()) == OVOID)
100     error(SYSTEM, "out of object space");
101     objp = objptr(obj);
102     /* get modifier */
103 greg 1.7 strcpy(sbuf, "EOF");
104     fgetword(sbuf, MAXSTR, fp);
105 greg 2.20 if (strchr(sbuf, '\t')) {
106     sprintf(errmsg, "(%s): illegal tab in modifier \"%s\"",
107     name, sbuf);
108     error(USER, errmsg);
109     }
110 greg 1.1 if (!strcmp(sbuf, VOIDID))
111     objp->omod = OVOID;
112 greg 2.11 else if (!strcmp(sbuf, ALIASMOD))
113     objp->omod = OALIAS;
114 greg 1.1 else if ((objp->omod = modifier(sbuf)) == OVOID) {
115     sprintf(errmsg, "(%s): undefined modifier \"%s\"", name, sbuf);
116     error(USER, errmsg);
117     }
118     /* get type */
119 greg 1.7 strcpy(sbuf, "EOF");
120     fgetword(sbuf, MAXSTR, fp);
121 greg 2.11 if ((objp->otype = otype(sbuf)) < 0) {
122 greg 1.1 sprintf(errmsg, "(%s): unknown type \"%s\"", name, sbuf);
123     error(USER, errmsg);
124     }
125     /* get identifier */
126 greg 1.7 sbuf[0] = '\0';
127     fgetword(sbuf, MAXSTR, fp);
128 greg 2.20 if (strchr(sbuf, '\t')) {
129     sprintf(errmsg, "(%s): illegal tab in identifier \"%s\"",
130     name, sbuf);
131     error(USER, errmsg);
132     }
133 greg 1.1 objp->oname = savqstr(sbuf);
134     /* get arguments */
135 greg 2.11 if (objp->otype == MOD_ALIAS) {
136 greg 2.26 OBJECT ref;
137     OBJREC *rfp;
138 greg 1.7 strcpy(sbuf, "EOF");
139     fgetword(sbuf, MAXSTR, fp);
140 greg 2.26 if ((ref = modifier(sbuf)) == OVOID) {
141 greg 2.11 sprintf(errmsg, "(%s): bad reference \"%s\"",
142     name, sbuf);
143     objerror(objp, USER, errmsg);
144 greg 2.26 } /* skip pass-thru aliases */
145     while ((rfp=objptr(ref))->otype == MOD_ALIAS &&
146     !rfp->oargs.nsargs & (rfp->omod != OVOID))
147     ref = rfp->omod;
148    
149     if ((objp->omod == OALIAS) | (objp->omod == rfp->omod)) {
150     objp->omod = ref;
151 greg 2.11 } else {
152     objp->oargs.sarg = (char **)malloc(sizeof(char *));
153     if (objp->oargs.sarg == NULL)
154     error(SYSTEM, "out of memory in getobject");
155     objp->oargs.nsargs = 1;
156     objp->oargs.sarg[0] = savestr(sbuf);
157 greg 1.1 }
158 greg 1.6 } else if ((rval = readfargs(&objp->oargs, fp)) == 0) {
159 greg 1.1 sprintf(errmsg, "(%s): bad arguments", name);
160     objerror(objp, USER, errmsg);
161 greg 1.6 } else if (rval < 0) {
162     sprintf(errmsg, "(%s): error reading scene", name);
163     error(SYSTEM, errmsg);
164 greg 1.1 }
165 greg 2.11 if (objp->omod == OALIAS) {
166     sprintf(errmsg, "(%s): inappropriate use of '%s' modifier",
167     name, ALIASMOD);
168     objerror(objp, USER, errmsg);
169     }
170 greg 1.1 /* initialize */
171     objp->os = NULL;
172    
173     insertobject(obj); /* add to global structure */
174 greg 2.11 #undef OALIAS
175 greg 1.1 }
176    
177    
178 greg 2.30 static void
179     optimize_objblock(int i) /* consolidate memory in object block */
180     {
181     #if OBJMEMOPT
182     OBJREC *o, *co;
183     int n = 0;
184     unsigned long sargcnt = 0, iargcnt = 0, fargcnt = 0, namecnt = 0;
185    
186     if (i < 0 || objblock[i] == NULL || objblock[i][OBJBLKSIZ].otype < 0)
187     return; /* invalid or already flagged */
188    
189     for (o = objblock[i]+OBJBLKSIZ; o-- > objblock[i]; ) {
190     if (o->oname == NULL) /* too early to optimize? */
191     return;
192     if (o->os != NULL) /* too late to optimize? */
193     return;
194     n += (o->oargs.nsargs > 0) | (o->oargs.nfargs > 0);
195     sargcnt += o->oargs.nsargs;
196     fargcnt += o->oargs.nfargs;
197     #ifdef IARGS
198     iargcnt += o->oargs.niargs;
199     #endif
200     namecnt += strlen(o->oname)+1;
201     }
202     if (n < OBJBLKSIZ/10) /* never happens? */
203     return;
204     /* prep consolidation object */
205     co = objblock[i]+OBJBLKSIZ;
206     co->oargs.nsargs = sargcnt;
207     co->oargs.nfargs = fargcnt;
208     if ((co->oargs.nsargs != sargcnt) | (co->oargs.nfargs != fargcnt))
209     return; /* overrun condition */
210    
211     co->oname = (char *)malloc(sizeof(char)*namecnt);
212     co->oargs.sarg = (char **)malloc(sizeof(char *)*sargcnt);
213     co->oargs.farg = (RREAL *)malloc(sizeof(RREAL)*fargcnt);
214     if ((co->oname == NULL) | (co->oargs.sarg == NULL) |
215     (co->oargs.farg == NULL)) {
216     free(co->oname);
217     free(co->oargs.sarg); free(co->oargs.farg);
218     return; /* insufficient memory */
219     }
220     #ifdef IARGS
221     co->oargs.niargs = iargcnt;
222     co->oargs.iarg = (long *)malloc(sizeof(long)*iargcnt);
223     if (co->oargs.iarg == NULL) {
224     free(co->oname);
225     free(co->oargs.sarg); free(co->oargs.farg);
226     return; /* insufficient memory */
227     }
228     iargcnt = 0;
229     #endif
230     namecnt = sargcnt = fargcnt = 0;
231     for (o = objblock[i]+OBJBLKSIZ; o-- > objblock[i]; ) {
232     n = strlen(o->oname)+1;
233     memcpy(co->oname + namecnt, o->oname, n);
234     freeqstr(o->oname);
235     o->oname = co->oname + namecnt;
236     namecnt += n;
237     if (o->oargs.nsargs) {
238     memcpy(co->oargs.sarg+sargcnt, o->oargs.sarg,
239     sizeof(char *)*o->oargs.nsargs);
240     free(o->oargs.sarg);
241     o->oargs.sarg = co->oargs.sarg + sargcnt;
242     sargcnt += o->oargs.nsargs;
243     }
244     if (o->oargs.nfargs) {
245     memcpy(co->oargs.farg+fargcnt, o->oargs.farg,
246     sizeof(RREAL)*o->oargs.nfargs);
247     free(o->oargs.farg);
248     o->oargs.farg = co->oargs.farg + fargcnt;
249     fargcnt += o->oargs.nfargs;
250     }
251     #ifdef IARGS
252     if (o->oargs.niargs) {
253     memcpy(co->oargs.iarg+iargcnt, o->oargs.iarg,
254     sizeof(long)*o->oargs.niargs);
255     free(o->oargs.iarg);
256     o->oargs.iarg = co->oargs.iarg + iargcnt;
257     iargcnt += o->oargs.niargs;
258     }
259     #endif
260     }
261     co->otype = -1; /* flag for optimized block */
262     #endif
263     }
264    
265    
266 greg 2.10 OBJECT
267 greg 2.22 newobject(void) /* get a new object */
268 greg 1.1 {
269 greg 2.22 int i;
270 greg 1.1
271 gwlarson 2.7 if ((nobjects & (OBJBLKSIZ-1)) == 0) { /* new block */
272 greg 2.30 i = nobjects >> OBJBLKSHFT;
273     optimize_objblock(i-1); /* optimize previous block */
274 greg 1.1 errno = 0;
275     if (i >= MAXOBJBLK)
276     return(OVOID);
277 greg 2.30 objblock[i] = (OBJREC *)calloc(OBJBLKSIZ+OBJMEMOPT,
278     sizeof(OBJREC));
279 greg 1.1 if (objblock[i] == NULL)
280     return(OVOID);
281     }
282     return(nobjects++);
283 greg 2.8 }
284    
285     void
286 greg 2.22 freeobjects( /* free a range of objects */
287     int firstobj,
288     int nobjs
289     )
290 greg 2.8 {
291 greg 2.22 int obj;
292 greg 2.8 /* check bounds */
293     if (firstobj < 0)
294     return;
295     if (nobjs <= 0)
296     return;
297     if (firstobj + nobjs > nobjects)
298     return;
299     /* clear objects */
300     for (obj = firstobj+nobjs; obj-- > firstobj; ) {
301 greg 2.22 OBJREC *o = objptr(obj);
302 greg 2.8 free_os(o); /* free client memory */
303 greg 2.30 if (!OBJMEMOPT || !objblock[obj>>OBJBLKSHFT][OBJBLKSIZ].otype) {
304     freeqstr(o->oname);
305     freefargs(&o->oargs);
306     }
307     memset(o, 0, sizeof(OBJREC));
308 greg 2.8 }
309     /* free objects off end */
310     for (obj = nobjects; obj-- > 0; )
311     if (objptr(obj)->oname != NULL)
312     break;
313 greg 2.24 if (++obj >= nobjects)
314     return;
315 greg 2.8 while (nobjects > obj) /* free empty end blocks */
316     if ((--nobjects & (OBJBLKSIZ-1)) == 0) {
317     int i = nobjects >> OBJBLKSHFT;
318 greg 2.30 /* consolidated block? */
319     if (OBJMEMOPT && objblock[i][OBJBLKSIZ].otype < 0) {
320     free(objblock[i][OBJBLKSIZ].oname);
321     freefargs(&objblock[i][OBJBLKSIZ].oargs);
322     }
323     free(objblock[i]);
324 greg 2.8 objblock[i] = NULL;
325     }
326 greg 2.24 truncobjndx(); /* truncate modifier look-up */
327 greg 1.1 }