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 * 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 98 int main(int argc, char **argv) 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 254 static int getwaiting(void) 255 { 256 if (nwaiting) 257 return (waiting[nwaiting--]); 258 else 259 return (0); 260 } 261 262 static double dtcrit(void) 263 { 264 return (dtc); 265 } 266 267 static double dtspinoff(void) 268 { 269 return (dts); 270 } 271 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 */ 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 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 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