1 /* 2 * Copyright (C) Bull S.A. 2001 3 * Copyright (c) International Business Machines Corp., 2001 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 /******************************************************************************/ 21 /* */ 22 /* Dec-03-2001 Created: Jacky Malcles & Jean Noel Cordenner */ 23 /* These tests are adapted from AIX float PVT tests. */ 24 /* */ 25 /******************************************************************************/ 26 #include "tfloat.h" 27 28 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } } 29 /* 30 * allocates a buffer and read a file to it 31 * input parameters: 32 * fname: name of the file to read 33 * data: pointer where buffer addr. will be returned 34 * 35 * uses also external variable datadir to build file pathname 36 * 37 * returns: 38 * 0 in case of failure 39 * # of bytes read elsewhere 40 */ 41 static size_t read_file(char *fname, void **data) 42 { 43 struct stat bufstat; 44 char path[PATH_MAX]; 45 size_t fsize; 46 void *buffer; 47 int fd; 48 int maxretries = 1; 49 50 (void)sprintf(path, "%s/%s", datadir, fname); 51 52 errno = 0; 53 54 while (stat(path, &bufstat)) { 55 if (errno == ETIMEDOUT || errno == EINTR || errno == 0) { 56 printf("Error stat'ing %s: %s\n", 57 path, strerror(errno)); 58 pthread_testcancel(); 59 /* retrying... */ 60 if (maxretries--) 61 continue; 62 } 63 return (size_t) 0; 64 } 65 66 fsize = bufstat.st_size; 67 if (!fsize) { 68 errno = ENOENT; 69 return (size_t) 0; 70 } 71 72 while ((buffer = malloc(fsize)) == NULL) { 73 if (errno == EINTR || errno == 0) { 74 printf("Error malloc'ing: %s\n", strerror(errno)); 75 pthread_testcancel(); 76 /* retrying... */ 77 if (maxretries--) 78 continue; 79 } 80 return (size_t) 0; 81 } 82 83 while ((fd = open(path, O_RDONLY)) < 0) { 84 if (errno == ETIMEDOUT || errno == EINTR || errno == 0) { 85 printf("Error opening %s: %s\n", path, strerror(errno)); 86 pthread_testcancel(); 87 /* retrying... */ 88 if (maxretries--) 89 continue; 90 } 91 SAFE_FREE(buffer); 92 return (size_t) 0; 93 } 94 95 while (read(fd, buffer, fsize) != fsize) { 96 if (errno == ETIMEDOUT || errno == EINTR || errno == 0) { 97 printf("Error reading %s: %s\n", path, strerror(errno)); 98 pthread_testcancel(); 99 /* retrying... */ 100 if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) 0) { 101 if (maxretries--) 102 continue; 103 } 104 } 105 (void)close(fd); 106 SAFE_FREE(buffer); 107 return (size_t) 0; 108 } 109 110 (void)close(fd); 111 *data = buffer; 112 return fsize; 113 } 114 115 /* this subroutine is used in compute_xxx functions to check results 116 and record errors if appropriate */ 117 static void check_error(TH_DATA * th_data, double e, double r, int index) 118 { 119 double x; 120 int pe, pr, px; 121 static const char errtmplt[] = 122 "%s failed at index %d: OLD: %2.18e NEW: %2.18e DIFF: %2.18e\n"; 123 124 x = fabs(r - e); /* diff expected/computed */ 125 126 if (x > EPS) { /* error ? */ 127 /* compute exponent parts */ 128 (void)frexp(r, &pr); /* for computed */ 129 (void)frexp(x, &px); /* for difference */ 130 (void)frexp(e, &pe); /* for dexected */ 131 132 if (abs(pe - px) < th_data->th_func.precision || 133 abs(pr - px) < th_data->th_func.precision) { 134 /* not a rounding error */ 135 ++th_data->th_nerror; 136 /* record first error only ! */ 137 if (th_data->th_result == 0) { 138 sprintf(th_data->detail_data, 139 errtmplt, 140 th_data->th_func.fident, 141 index, e, r, x); 142 th_data->th_result = 1; 143 } 144 } 145 } 146 } 147 148 /* 149 * these functions handle the various cases of computation 150 * they are called by pthread_code 151 */ 152 153 /* normal case: compares f(input data) to expected data */ 154 static void compute_normal(TH_DATA * th_data, double *din, double *dex, 155 int index) 156 { 157 double d, r, e; 158 159 d = din[index]; 160 e = dex[index]; 161 r = (*(th_data->th_func.funct)) (d); 162 163 check_error(th_data, e, r, index); 164 } 165 166 /* atan2 and hypot case: compares f(sin(input data),cos(input data)) 167 to expected data */ 168 static void compute_atan2_hypot(TH_DATA * th_data, double *din, double *dex, 169 int index) 170 { 171 double d, r, e; 172 173 d = din[index]; 174 e = dex[index]; 175 r = (*(th_data->th_func.funct)) (sin(d), cos(d)); 176 177 check_error(th_data, e, r, index); 178 } 179 180 /* modf case: compares integral and fractional parts to expected datas */ 181 static void compute_modf(TH_DATA * th_data, double *din, double *dex, 182 double *dex2, int index) 183 { 184 static const char errtmplt1[] = 185 "%s failed at index %d: OLD integral part: %f NEW: %f\n"; 186 double d, r, e; 187 double tmp; 188 189 d = din[index]; 190 e = dex[index]; 191 r = (*(th_data->th_func.funct)) (d, &tmp); 192 193 if (tmp != dex2[index]) { /* bad integral part! */ 194 ++th_data->th_nerror; 195 /* record first error only ! */ 196 if (th_data->th_result == 0) { 197 sprintf(th_data->detail_data, 198 errtmplt1, 199 th_data->th_func.fident, 200 index, dex2[index], tmp); 201 th_data->th_result = 1; 202 } 203 return; 204 } 205 206 check_error(th_data, e, r, index); 207 } 208 209 /* fmod and pow case: compares f(input data, input data2) to expected data */ 210 static void compute_fmod_pow(TH_DATA * th_data, double *din, double *dex, 211 double *dex2, int index) 212 { 213 double d, r, e; 214 215 d = din[index]; 216 e = dex[index]; 217 r = (*(th_data->th_func.funct)) (d, dex2[index]); 218 219 check_error(th_data, e, r, index); 220 } 221 222 /* frexp case: compares mantissa and exponent to expected datas */ 223 /* lgamma case: compares result and signgam to expected datas */ 224 static void compute_frexp_lgamma(TH_DATA * th_data, double *din, double *dex, 225 int *dex2, int index) 226 { 227 static const char errtmplt2[] = 228 "%s failed at index %d: OLD (exp. or sign): %d NEW: %d\n"; 229 double d, r, e; 230 int tmp; 231 static const char xinf[8] = "lgamma"; 232 233 d = din[index]; 234 e = dex[index]; 235 r = (*(th_data->th_func.funct)) (d, &tmp); 236 237 if (strcmp(th_data->th_func.fident, xinf) != 0) { 238 if (tmp != dex2[index]) { /* bad exponent! */ 239 ++th_data->th_nerror; 240 /* record first error only ! */ 241 if (th_data->th_result == 0) { 242 sprintf(th_data->detail_data, 243 errtmplt2, 244 th_data->th_func.fident, 245 index, dex2[index], tmp); 246 th_data->th_result = 1; 247 } 248 return; 249 } 250 } 251 252 check_error(th_data, e, r, index); 253 } 254 255 /* ldexp case: compares f(input data, input data2) to expected data */ 256 static void compute_ldexp(TH_DATA * th_data, double *din, double *dex, 257 int *din2, int index) 258 { 259 double d, r, e; 260 261 d = din[index]; 262 e = dex[index]; 263 r = (*(th_data->th_func.funct)) (d, din2[index]); 264 265 check_error(th_data, e, r, index); 266 } 267 268 /* 269 * Function which does the job, to be called as the 270 * "start routine" parameter of pthread_create subroutine. 271 * Uses the compute_xxx subroutines above. 272 * 273 * input parameters ("arg" parameter of pthread_create subroutine): 274 * pointer to a TH_DATA structure. 275 * 276 */ 277 void *thread_code(void *arg) 278 { 279 TH_DATA *th_data = (TH_DATA *) arg; 280 size_t fsize, fsize2, fsize3; 281 double *din, *dex, *dex2 = NULL; 282 int imax, index; 283 284 fsize = read_file(th_data->th_func.din_fname, (void **)&din); 285 if (fsize == (size_t) 0) { 286 sprintf(th_data->detail_data, 287 "FAIL: %s: reading %s, %s\n", 288 th_data->th_func.fident, 289 th_data->th_func.din_fname, strerror(errno)); 290 th_data->th_result = 1; 291 SAFE_FREE(din); 292 pthread_exit((void *)1); 293 } 294 fsize2 = read_file(th_data->th_func.dex_fname, (void **)&dex); 295 if (fsize2 == (size_t) 0) { 296 sprintf(th_data->detail_data, 297 "FAIL: %s: reading %s, %s\n", 298 th_data->th_func.fident, 299 th_data->th_func.dex_fname, strerror(errno)); 300 th_data->th_result = 1; 301 SAFE_FREE(din); 302 SAFE_FREE(dex); 303 pthread_exit((void *)1); 304 } 305 306 fsize3 = (size_t) 0; 307 switch (th_data->th_func.code_funct) { 308 case FUNC_MODF: 309 case FUNC_FMOD: 310 case FUNC_POW: 311 case FUNC_FREXP: 312 case FUNC_LDEXP: 313 case FUNC_GAM: 314 fsize3 = read_file(th_data->th_func.dex2_fname, (void **)&dex2); 315 if (fsize3 == (size_t) 0) { 316 sprintf(th_data->detail_data, 317 "FAIL: %s: reading %s, %s\n", 318 th_data->th_func.fident, 319 th_data->th_func.dex2_fname, strerror(errno)); 320 th_data->th_result = 1; 321 SAFE_FREE(din); 322 SAFE_FREE(dex); 323 pthread_exit((void *)1); 324 } 325 } 326 327 switch (th_data->th_func.code_funct) { 328 case FUNC_NORMAL: 329 case FUNC_ATAN2: 330 case FUNC_HYPOT: 331 if (fsize2 != fsize) 332 goto file_size_error; 333 break; 334 case FUNC_MODF: 335 case FUNC_FMOD: 336 case FUNC_POW: 337 if (fsize2 != fsize || fsize3 != fsize) 338 goto file_size_error; 339 break; 340 case FUNC_FREXP: 341 case FUNC_LDEXP: 342 case FUNC_GAM: 343 if (fsize2 != fsize || 344 (sizeof(double) / sizeof(int)) * fsize3 != fsize) 345 goto file_size_error; 346 break; 347 default: 348 file_size_error: 349 sprintf(th_data->detail_data, 350 "FAIL: %s: file sizes don't match\n", 351 th_data->th_func.fident); 352 th_data->th_result = 1; 353 SAFE_FREE(din); 354 SAFE_FREE(dex); 355 if (fsize3) 356 SAFE_FREE(dex2); 357 pthread_exit((void *)1); 358 } 359 360 imax = fsize / sizeof(double); 361 362 while (th_data->th_nloop <= num_loops) { 363 /* loop stopped by pthread_cancel */ 364 365 for (index = th_data->th_num; index < imax; index += num_threads) { /* computation loop */ 366 switch (th_data->th_func.code_funct) { 367 case FUNC_NORMAL: 368 compute_normal(th_data, din, dex, index); 369 break; 370 case FUNC_ATAN2: 371 case FUNC_HYPOT: 372 compute_atan2_hypot(th_data, din, dex, index); 373 break; 374 case FUNC_MODF: 375 compute_modf(th_data, din, dex, dex2, index); 376 break; 377 case FUNC_FMOD: 378 case FUNC_POW: 379 compute_fmod_pow(th_data, 380 din, dex, dex2, index); 381 break; 382 case FUNC_FREXP: 383 case FUNC_GAM: 384 compute_frexp_lgamma(th_data, 385 din, dex, (int *)dex2, 386 index); 387 break; 388 case FUNC_LDEXP: 389 compute_ldexp(th_data, 390 din, dex, (int *)dex2, index); 391 break; 392 default: 393 sprintf(th_data->detail_data, 394 "FAIL: %s: unexpected function type\n", 395 th_data->th_func.fident); 396 th_data->th_result = 1; 397 SAFE_FREE(din); 398 SAFE_FREE(dex); 399 if (fsize3) 400 SAFE_FREE(dex2); 401 pthread_exit((void *)1); 402 } 403 pthread_testcancel(); 404 } /* end of computation loop */ 405 ++th_data->th_nloop; 406 } /* end of loop */ 407 SAFE_FREE(din); 408 SAFE_FREE(dex); 409 if (fsize3) 410 SAFE_FREE(dex2); 411 pthread_exit(NULL); 412 } 413