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