1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2002
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /* Group Bull & IBM Corporation */
21 /* 11/20/2002 Port to LTP robbiew@us.ibm.com */
22 /* jacky.malcles@bull.net */
23 /* IBM Corporation */
24 /* 06/30/2001 Port to Linux nsharoff@us.ibm.com */
25
26 /*
27 * fptest01.c -- Floating point test.
28 *
29 * It is taken from a benchmark called "barsim".
30 *
31 * If the computation arrives at the expected values this routine
32 * prints a "passed" message and exits 0. If an incorrect value is
33 * computed a "failed" message is printed and the routine exits 1.
34 */
35
36 #include <stdio.h>
37 #include <errno.h>
38 #include <math.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44
45 #define MAGIC1 1632.796126
46 #define DIFF1 0.001
47 #define MAGIC2 0.777807
48 #define DIFF2 0.001
49 #define EVENTMX 256
50 #define BIG 1.e50
51 #define FALSE 0
52 #define TRUE 1
53 #define TRYCRIT 1
54 #define ENTERCRIT 2
55 #define LEAVECRIT 3
56 #define ATBARRIER 4
57 #define ENTERWORK 5
58 #define LEAVEWORK 6
59 #define NULLEVENT 999
60
61 /** LTP Port **/
62 #include "test.h"
63
64 char *TCID = "fptest01"; /* Test program identifier. */
65 int TST_TOTAL = 1; /* Total number of test cases. */
66 /**************/
67
68 struct event {
69 int proc;
70 int type;
71 double time;
72 };
73
74 static int init(void);
75 static int doevent(struct event *);
76 static int term(void);
77 static int addevent(int, int, double);
78
79 static void gaussinit(double, double);
80 static double gauss(void);
81
82 struct event eventtab[EVENTMX];
83 struct event rtrevent;
84 int waiting[EVENTMX]; /* array of waiting processors */
85 int nwaiting; /* number of waiting processors */
86 double global_time; /* global clock */
87 double lsttime; /* time used for editing */
88 double dtc, dts, alpha; /* timing parameters */
89 int nproc; /* number of processors */
90 int barcnt; /* number of processors ATBARRIER */
91 int ncycle; /* number of cycles completed */
92 int ncycmax; /* number of cycles to run */
93 int critfree; /* TRUE if critical section not occupied */
94 int gcount; /* # calls to gauss */
95
96 static struct event *nextevent(void);
97
main(void)98 int main(void)
99 {
100 struct event *ev;
101
102 nproc = 128;
103 ncycmax = 10;
104 dtc = 0.01;
105 dts = 0.0;
106 alpha = 0.1;
107
108 init();
109
110 while ((ev = nextevent()) != NULL) {
111 doevent(ev);
112 }
113
114 term();
115 tst_resm(TPASS, "PASS");
116 tst_exit();
117 }
118
119 /*
120 initialize all processes to "entering work section"
121 */
init(void)122 static int init(void)
123 {
124 int p;
125 double dtw, dtwsig;
126
127 ncycle = 0;
128 global_time = 0;
129 lsttime = 0;
130 barcnt = 0;
131 nwaiting = 0;
132 critfree = TRUE;
133
134 dtw = 1. / nproc; /* mean process work time */
135 dtwsig = dtw * alpha; /* std deviation of work time */
136 gaussinit(dtw, dtwsig);
137
138 for (p = 1; p <= nproc; p++) {
139 eventtab[p].type = NULLEVENT;
140 }
141
142 for (p = 1; p <= nproc; p++) {
143 addevent(ENTERWORK, p, global_time);
144 }
145
146 return (0);
147 }
148
149 /*
150 print edit quantities
151 */
term(void)152 static int term(void)
153 {
154 double avgspd;
155 double t_total = 0.0;
156 double v;
157 int i;
158
159 for (i = 0; i < nproc; i++)
160 t_total += eventtab[i].time;
161
162 avgspd = ncycle / global_time;
163
164 v = t_total - MAGIC1;
165 if (v < 0.0)
166 v *= -1.0;
167
168 if (v > DIFF1) {
169 tst_resm(TFAIL, "FAIL");
170 v = t_total - MAGIC1;
171 tst_resm(TINFO, "t_total = %.15f\n", t_total);
172 tst_resm(TINFO, "expected %.15f\n", MAGIC1);
173 tst_resm(TINFO, "diff = %.15f\n", v);
174 tst_exit();
175 }
176
177 v = avgspd - MAGIC2;
178 if (v < 0.0)
179 v *= -1.0;
180
181 if (v > DIFF2) {
182 tst_resm(TFAIL, "FAIL");
183 v = avgspd - MAGIC2;
184 tst_resm(TINFO, "avgspd = %.15f\n", avgspd);
185 tst_resm(TINFO, "expected %.15f\n", MAGIC2);
186 tst_resm(TINFO, "diff = %.15f\n", v);
187 tst_exit();
188 }
189 return (0);
190 }
191
192 /*
193 add an event to the event queue
194 */
addevent(int type,int proc,double t)195 static int addevent(int type, int proc, double t)
196 {
197 int i;
198 int ok = FALSE;
199
200 for (i = 1; i <= nproc; i++) {
201 if (eventtab[i].type == NULLEVENT) {
202 eventtab[i].type = type;
203 eventtab[i].proc = proc;
204 eventtab[i].time = t;
205 ok = TRUE;
206 break;
207 }
208 }
209 if (ok)
210 return (0);
211 else
212 tst_brkm(TBROK, NULL, "No room for event");
213 return (0);
214 }
215
216 /*
217 get earliest event in event queue
218 */
nextevent(void)219 static struct event *nextevent(void)
220 {
221 double mintime = BIG;
222 int imin = 0;
223 int i;
224
225 for (i = 1; i <= nproc; i++) {
226 if (eventtab[i].type != NULLEVENT && eventtab[i].time < mintime) {
227 imin = i;
228 mintime = eventtab[i].time;
229 }
230 }
231
232 if (imin) {
233 rtrevent.type = eventtab[imin].type;
234 rtrevent.proc = eventtab[imin].proc;
235 rtrevent.time = eventtab[imin].time;
236 eventtab[imin].type = NULLEVENT;
237 return (&rtrevent);
238 } else
239 return (NULL);
240 }
241
242 /*
243 add a processor to the waiting queue
244 */
addwaiting(int p)245 static int addwaiting(int p)
246 {
247 waiting[++nwaiting] = p;
248 return (0);
249 }
250
251 /*
252 remove the next processor from the waiting queue
253 */
getwaiting(void)254 static int getwaiting(void)
255 {
256 if (nwaiting)
257 return (waiting[nwaiting--]);
258 else
259 return (0);
260 }
261
dtcrit(void)262 static double dtcrit(void)
263 {
264 return (dtc);
265 }
266
dtspinoff(void)267 static double dtspinoff(void)
268 {
269 return (dts);
270 }
271
dtwork(void)272 static double dtwork(void)
273 {
274 return (gauss());
275 }
276
277 /*
278 take the action prescribed by 'ev', update the clock, and
279 generate any subsequent events
280 */
doevent(struct event * ev)281 static int doevent(struct event *ev)
282 {
283 double nxttime;
284 int i, p, proc;
285
286 global_time = ev->time;
287 proc = ev->proc;
288
289 switch (ev->type) {
290 case TRYCRIT:
291 if (critfree == TRUE)
292 addevent(ENTERCRIT, proc, global_time);
293 else
294 addwaiting(proc);
295 break;
296 case ENTERCRIT:
297 critfree = FALSE;
298 nxttime = global_time + dtcrit();
299 addevent(LEAVECRIT, proc, nxttime);
300 break;
301 case LEAVECRIT:
302 critfree = TRUE;
303 addevent(ATBARRIER, proc, global_time);
304 if ((p = getwaiting()) != 0) {
305 nxttime = global_time;
306 addevent(ENTERCRIT, p, nxttime);
307 }
308 break;
309 case ATBARRIER:
310 barcnt++;
311 if (barcnt == nproc) {
312 nxttime = global_time;
313 for (i = 1; i <= nproc; i++) {
314 nxttime += dtspinoff();
315 addevent(ENTERWORK, i, nxttime);
316 }
317 barcnt = 0;
318 ncycle++;
319 }
320 break;
321 case ENTERWORK:
322 nxttime = global_time + dtwork();
323 if (ncycle < ncycmax)
324 addevent(LEAVEWORK, proc, nxttime);
325 break;
326 case LEAVEWORK:
327 addevent(TRYCRIT, proc, global_time);
328 break;
329 default:
330 tst_brkm(TBROK, NULL, "Illegal event");
331 break;
332 }
333 return (0);
334 }
335
336 static int alternator = 1;
337 static double mean;
338 static double stdev;
339 static double u1, u2;
340 static double twopi;
341
gaussinit(double m,double s)342 static void gaussinit(double m, double s)
343 {
344 mean = m;
345 stdev = s;
346 twopi = 2. * acos((double)-1.0);
347 u1 = twopi / 400.0;
348 u2 = twopi / 500.0;
349 }
350
gauss(void)351 static double gauss(void)
352 {
353 double x1, x2;
354
355 gcount++;
356
357 u1 += u2;
358 if (u1 > 0.99)
359 u1 = twopi / 500.0;
360 u2 += u1;
361 if (u2 > 0.99)
362 u2 = twopi / 400.0;
363
364 if (alternator == 1) {
365 alternator = -1;
366 x1 = sqrt(-2.0 * log(u1)) * cos(twopi * u2);
367 return (mean + stdev * x1);
368 } else {
369 alternator = 1;
370 x2 = sqrt(-2.0 * log(u1)) * sin(twopi * u2);
371 return (mean + stdev * x2);
372 }
373 }
374