Home | History | Annotate | Download | only in fptests
      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 (at) us.ibm.com */
     22 /*                                               jacky.malcles (at) bull.net */
     23 /* IBM Corporation */
     24 /* 06/30/2001	Port to Linux	nsharoff (at) 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 
     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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    235 static int getwaiting(void)
    236 {
    237 	if (nwaiting)
    238 		return (waiting[nwaiting--]);
    239 	else
    240 		return (0);
    241 }
    242 
    243 static double dtcrit(void)
    244 {
    245 	return (dtc);
    246 }
    247 
    248 static double dtspinoff(void)
    249 {
    250 	return (dts);
    251 }
    252 
    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 */
    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 
    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 
    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