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  * fptest02.c -- Floating point test.
28  *
29  * This is similar to fptest1.  Random values are used for some of the
30  * math in routine "gauss".  The value "avgspd" computed in routine
31  * "term()" should come out to a known value.  If this happens this
32  * program prints a "passed" message and exits 0, otherwise a "failed"
33  * message is printed and it exits with value 1.
34  *
35  */
36 
37 #include <stdio.h>
38 #include <errno.h>
39 #include <math.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <time.h>
46 
47 #define MAGIC	0.777807
48 #define DIFF	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 = "fptest02";	/* 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, int);
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 sgtime;			/* 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 
95 static struct event *nextevent(void );
96 
main(int argc,char * argv[])97 int main(int argc, char *argv[])
98 {
99 	struct event *ev;
100 
101 	nproc = 128;
102 	ncycmax = 10;
103 	dtc = 0.01;
104 	dts = 0.0;
105 	alpha = 0.1;
106 
107 	init();
108 
109 	while ((ev = nextevent()) != NULL) {
110 		doevent(ev);
111 	}
112 
113 	term();
114 	tst_resm(TPASS, "PASS");
115 	tst_exit();
116 }
117 
118 /*
119 	initialize all processes to "entering work section"
120 */
init(void)121 static int init(void)
122 {
123 	int p;
124 	double dtw, dtwsig;
125 
126 	ncycle = 0;
127 	sgtime = 0;
128 	lsttime = 0;
129 	barcnt = 0;
130 	nwaiting = 0;
131 	critfree = TRUE;
132 
133 	dtw = 1. / nproc;	/* mean process work time */
134 	dtwsig = dtw * alpha;	/* std deviation of work time */
135 	gaussinit(dtw, dtwsig, time(0));
136 
137 	for (p = 1; p <= nproc; p++) {
138 		eventtab[p].type = NULLEVENT;
139 	}
140 
141 	for (p = 1; p <= nproc; p++) {
142 		addevent(ENTERWORK, p, sgtime);
143 	}
144 
145 	return (0);
146 }
147 
148 /*
149 	print edit quantities
150 */
term(void)151 static int term(void)
152 {
153 	double avgspd;
154 	double v;
155 
156 	avgspd = ncycle / sgtime;
157 	v = avgspd - MAGIC;
158 	if (v < 0.0)
159 		v *= -1.0;
160 	if (v > DIFF) {
161 		tst_resm(TFAIL, "FAIL");
162 		v = avgspd - MAGIC;
163 		tst_resm(TINFO, "avgspd = %.15f\n", avgspd);
164 		tst_resm(TINFO, "expected %.15f\n", MAGIC);
165 		tst_resm(TINFO, "diff = %.15f\n", v);
166 		tst_exit();
167 	}
168 	return (0);
169 }
170 
171 /*
172 	add an event to the event queue
173 */
addevent(int type,int proc,double t)174 static int addevent(int type, int proc, double t)
175 {
176 	int i;
177 	int ok = FALSE;
178 
179 	for (i = 1; i <= nproc; i++) {
180 		if (eventtab[i].type == NULLEVENT) {
181 			eventtab[i].type = type;
182 			eventtab[i].proc = proc;
183 			eventtab[i].time = t;
184 			ok = TRUE;
185 			break;
186 		}
187 	}
188 	if (ok)
189 		return (0);
190 	else
191 		tst_brkm(TBROK, NULL, "No room for event");
192 
193 	return (0);
194 }
195 
196 /*
197 	get earliest event in event queue
198 */
nextevent(void)199 static struct event *nextevent(void)
200 {
201 	double mintime = BIG;
202 	int imin = 0;
203 	int i;
204 
205 	for (i = 1; i <= nproc; i++) {
206 		if ((eventtab[i].type != NULLEVENT)
207 		    && (eventtab[i].time < mintime)) {
208 			imin = i;
209 			mintime = eventtab[i].time;
210 		}
211 	}
212 
213 	if (imin) {
214 		rtrevent.type = eventtab[imin].type;
215 		rtrevent.proc = eventtab[imin].proc;
216 		rtrevent.time = eventtab[imin].time;
217 		eventtab[imin].type = NULLEVENT;
218 		return (&rtrevent);
219 	} else
220 		return (NULL);
221 }
222 
223 /*
224 	add a processor to the waiting queue
225 */
addwaiting(int p)226 static int addwaiting(int p)
227 {
228 	waiting[++nwaiting] = p;
229 	return (0);
230 }
231 
232 /*
233 	remove the next processor from the waiting queue
234 */
getwaiting(void)235 static int getwaiting(void)
236 {
237 	if (nwaiting)
238 		return (waiting[nwaiting--]);
239 	else
240 		return (0);
241 }
242 
dtcrit(void)243 static double dtcrit(void)
244 {
245 	return (dtc);
246 }
247 
dtspinoff(void)248 static double dtspinoff(void)
249 {
250 	return (dts);
251 }
252 
dtwork(void)253 static double dtwork(void)
254 {
255 	return (gauss());
256 }
257 
258 /*
259 	take the action prescribed by 'ev', update the clock, and
260 	generate any subsequent events
261 */
doevent(struct event * ev)262 static int doevent(struct event *ev)
263 {
264 	double nxttime;
265 	int i, p, proc;
266 
267 	sgtime = ev->time;
268 	proc = ev->proc;
269 
270 	switch (ev->type) {
271 	case TRYCRIT:
272 		if (critfree == TRUE)
273 			addevent(ENTERCRIT, proc, sgtime);
274 		else
275 			addwaiting(proc);
276 		break;
277 	case ENTERCRIT:
278 		critfree = FALSE;
279 		nxttime = sgtime + dtcrit();
280 		addevent(LEAVECRIT, proc, nxttime);
281 		break;
282 	case LEAVECRIT:
283 		critfree = TRUE;
284 		addevent(ATBARRIER, proc, sgtime);
285 		if ((p = getwaiting()) != 0) {
286 			nxttime = sgtime;
287 			addevent(ENTERCRIT, p, nxttime);
288 		}
289 		break;
290 	case ATBARRIER:
291 		barcnt++;
292 		if (barcnt == nproc) {
293 			nxttime = sgtime;
294 			for (i = 1; i <= nproc; i++) {
295 				nxttime += dtspinoff();
296 				addevent(ENTERWORK, i, nxttime);
297 			}
298 			barcnt = 0;
299 			ncycle++;
300 		}
301 		break;
302 	case ENTERWORK:
303 		nxttime = sgtime + dtwork();
304 		if (ncycle < ncycmax)
305 			addevent(LEAVEWORK, proc, nxttime);
306 		break;
307 	case LEAVEWORK:
308 		addevent(TRYCRIT, proc, sgtime);
309 		break;
310 	default:
311 		tst_brkm(TBROK, NULL, "Illegal event");
312 		break;
313 	}
314 	return (0);
315 }
316 
317 static int alternator = 1;
318 static double mean;
319 static double stdev;
320 static double u1, u2;
321 static double twopi;
322 static double rnorm = 2147483647;
323 
gaussinit(double m,double s,int seed)324 static void gaussinit(double m, double s, int seed)
325 {
326 	srand48(seed);
327 	mean = m;
328 	stdev = s;
329 	twopi = 2. * acos((double)-1.0);
330 	return;
331 }
332 
gauss(void)333 static double gauss(void)
334 {
335 	double x1, x2;
336 
337 	if (alternator == 1) {
338 		alternator = -1;
339 		u1 = lrand48() / rnorm;
340 		u2 = lrand48() / rnorm;
341 		x1 = sqrt(-2.0 * log(u1)) * cos(twopi * u2);
342 		return (mean + stdev * x1);
343 	} else {
344 		alternator = 1;
345 		x2 = sqrt(-2.0 * log(u1)) * sin(twopi * u2);
346 		return (mean + stdev * x2);
347 	}
348 }
349