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 */
read_file(char * fname,void ** data)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 */
check_error(TH_DATA * th_data,double e,double r,int index)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 */
compute_normal(TH_DATA * th_data,double * din,double * dex,int index)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 */
compute_atan2_hypot(TH_DATA * th_data,double * din,double * dex,int index)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 */
compute_modf(TH_DATA * th_data,double * din,double * dex,double * dex2,int index)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 */
compute_fmod_pow(TH_DATA * th_data,double * din,double * dex,double * dex2,int index)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 */
compute_frexp_lgamma(TH_DATA * th_data,double * din,double * dex,int * dex2,int index)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 */
compute_ldexp(TH_DATA * th_data,double * din,double * dex,int * din2,int index)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 */
thread_code(void * arg)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