2130 zvol DKIOCFREE uses nested DMU transactions
[illumos-gate.git] / usr / src / cmd / fps / fptest / benchmarks.c
blobdae5149e9eeb8ecc67fa3a03a7c303af39a68ec3
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #ifdef __lint
30 #pragma error_messages(off, E_VALUE_TYPE)
31 #endif
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fp.h>
36 #include <fps_ereport.h>
38 #define EXPECTED 1.9999999999999998E+00
40 static void fdivd(double *f22, double *f2, double *f12);
41 static void fmuld(double *x, double *y, double *z, double *z1);
42 static void fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd);
43 int fpu_fdivd(int rloop, struct fps_test_ereport *report);
44 int fpu_fmuld(int rloop, struct fps_test_ereport *report);
45 int fpu_fmulx(int rloop, struct fps_test_ereport *report);
47 #ifdef V9B
49 /* Lint doesn't recognize .il files where these are defined */
50 #ifdef __lint
52 unsigned long fcmpgt16(double in1, double in2);
53 unsigned long fcmpne16(double in1, double in2);
54 unsigned long setgsr(unsigned long);
56 #else
58 extern float fpackfix(double num);
59 extern unsigned long fcmpgt16(double in1, double in2);
60 extern unsigned long fcmpne16(double in1, double in2);
61 extern unsigned long setgsr(unsigned long);
63 #endif
65 int align_data(int loop,
66 struct fps_test_ereport *report);
67 int vis_test(struct fps_test_ereport *report);
68 static int align_error_create(char *err, uint32_t start, uint32_t offest,
69 int loop, uint32_t count);
70 static int do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
71 uchar_t *f0, uchar_t *f2, uint32_t bmask);
72 static int visgt16(struct fps_test_ereport *report);
73 static int visne16(struct fps_test_ereport *report);
74 static int vispackfix(struct fps_test_ereport *report);
76 #endif
80 * fpu_fdivd(int rloop, int unit, struct fps_test_ereport *report)
81 * returns whether the correct value is calculated each time
82 * rloop times. If an error is found, the relevant data is stored
83 * in report. The test uses internally generated random double
84 * precision within a certain range to conduct the following test:
86 * (a * 2^1022) / ((a+e) * 2^1021)
88 * which is guaranteed to fill the resulting mantissa with all ones.
91 int
92 fpu_fdivd(int rloop, struct fps_test_ereport *report)
95 char err_data[MAX_INFO_SIZE];
96 double expect_ans = EXPECTED;
97 double f12 = 0;
98 double f2;
99 double f22;
100 int loop = 0;
101 uint64_t expect;
102 uint64_t observe;
104 srand48(1L);
106 while (loop < rloop) {
107 loop++;
109 *(uint32_t *)& f22 = mrand48();
110 *(uint32_t *)& f22 &= 0x80069fff;
111 *(uint32_t *)& f22 |= 0x7fd69f00;
113 #ifdef __lint
114 (void) f22;
115 #endif
117 *((uint32_t *)& f22 + 1) = mrand48();
118 *((uint32_t *)& f22 + 1) |= 0x00000001;
120 *(uint64_t *)& f2 = *(uint64_t *)& f22 + 1;
121 *(uint32_t *)& f2 &= 0x800FFFFF;
122 *(uint32_t *)& f2 |= 0x7FC00000;
123 #ifdef __lint
124 (void) f2;
125 #endif
127 fdivd(&f22, &f2, &f12);
129 if (f12 != expect_ans) {
130 (void) snprintf(err_data, sizeof (err_data),
131 "\nExpected: %.16e,\nObserved: %.16e",
132 expect_ans, f12);
133 expect = *(uint64_t *)&expect_ans;
134 observe = *(uint64_t *)&f12;
135 setup_fps_test_struct(IS_EREPORT_INFO, report,
136 6340, &observe, &expect, 1, 1, err_data);
138 return (-1);
142 return (0);
146 * fdivd(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
147 * performs the assembly level instructions for
148 * fpu_fdivd.
150 /* ARGSUSED */
151 static void
152 fdivd(double *f22, double *f2, double *f12)
154 asm("ldd [%i0], %f22");
155 asm("ldd [%i1], %f2");
156 asm("fdivd %f22, %f2, %f12");
157 asm("std %f12,[%i2]");
158 asm("membar #Sync");
162 * fpu_fmuld(int rloop, int unit, struct fps_test_ereport *report)
163 * returns whether the correct value is calculated each time
164 * rloop times. If an error is found, the relevant data is stored
165 * in report. The goal is to check if (x * y) == (y * x). The
166 * data pattern is important, and the back-to-back fmuld's are
167 * important.
170 fpu_fmuld(int rloop, struct fps_test_ereport *report)
172 char err_data[MAX_INFO_SIZE];
173 double x;
174 double y;
175 double z;
176 double z1;
177 int loop;
178 uint64_t expect;
179 uint64_t observe;
180 uint64_t *px;
181 uint64_t *py;
183 loop = 0;
184 px = (uint64_t *)& x;
185 py = (uint64_t *)& y;
186 *px = 0x2FEBD8507111CDE5UL; /* 4865027 */
187 *py = 0x2FE284A9A98EAA26UL;
189 #ifdef __lint
190 (void) x;
191 (void) y;
192 #endif
194 while (loop < rloop) {
195 loop++;
196 z = z1 = 0.0;
199 * Data pattern and back-to-back fmuld() are
200 * important
202 fmuld(&x, &y, &z, &z1);
204 if (*(uint64_t *)&z != *(uint64_t *)&z1) {
205 (void) snprintf(err_data, sizeof (err_data),
206 "\nExpected: %.16e,\nObserved: %.16e",
207 *(uint64_t *)&z, *(uint64_t *)&z1);
208 expect = *(uint64_t *)&z;
209 observe = *(uint64_t *)&z1;
210 setup_fps_test_struct(IS_EREPORT_INFO, report,
211 6341, &observe, &expect, 1, 1, err_data);
213 return (-1);
217 return (0);
221 * fmuld(double *x,double *y, double *z, double *z1)
222 * performs the assembly level instructions for
223 * fpu_fmuld.
225 /* ARGSUSED */
226 static void
227 fmuld(double *x, double *y, double *z, double *z1)
229 asm("ldd[%i0], %f0");
230 asm("ldd[%i1], %f4");
231 asm("fmuld%f0, %f4, %f2");
232 asm("fmuld%f4, %f0, %f6");
233 asm("std%f2, [%i2]");
234 asm("std%f6, [%i3]");
235 asm("membar #Sync");
240 * fpu_fmulx(int rloop, int unit, struct fps_test_ereport *report)
241 * returns whether the correct value is calculated each time
242 * rloop times. If an error is found, the relevant data is stored
243 * in report. The goal is to check if (x * y) == (y * x) with
244 * 64-bit intgers.
247 fpu_fmulx(int rloop, struct fps_test_ereport *report)
249 char err_data[MAX_INFO_SIZE];
250 int loop;
251 int loop_lim;
252 uint32_t *rs1;
253 uint32_t *rs2;
254 uint64_t expect;
255 uint64_t observe;
256 uint64_t v1;
257 uint64_t v2;
258 uint64_t vd1;
259 uint64_t vd2;
260 uint64_t *rd1;
261 uint64_t *rd2;
263 v1 = v2 = vd1 = vd2 = 0;
264 loop = 0;
265 loop_lim = rloop;
267 if (loop_lim < 10)
268 loop_lim = 10;
270 if (loop_lim > 100000)
271 loop_lim = 100000;
273 rs1 = (uint32_t *)& v1;
274 rs2 = (uint32_t *)& v2;
275 rd1 = &vd1;
276 rd2 = &vd2;
278 #ifdef __lint
279 (void) v1;
280 (void) v2;
281 #endif
283 srand(0l);
284 while (loop < loop_lim) {
285 loop++;
287 #ifndef __lint
289 *rs1 = mrand48();
290 *(rs1 + 1) = mrand48();
291 *rs2 = mrand48();
292 *(rs2 + 1) = mrand48();
293 #endif
295 /* LINTED */
296 fmulx((uint64_t *)rs1, (uint64_t *)rs2, rd1);
298 /* LINTED */
299 fmulx((uint64_t *)rs2, (uint64_t *)rs1, rd2);
301 if (*rd1 != *rd2) {
302 expect = (uint64_t)*rd1;
303 observe = (uint64_t)*rd2;
304 (void) snprintf(err_data, sizeof (err_data),
305 "\nExpected: %lld\nObserved: %lld", *rd1, *rd2);
306 setup_fps_test_struct(IS_EREPORT_INFO, report,
307 6356, &observe, &expect, 1, 1, err_data);
309 return (-1);
313 return (0);
317 * fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
318 * performs the assembly level instructions for
319 * fpu_fmulx.
321 /* ARGSUSED */
322 static void
323 fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
325 asm("ldx [%i0], %l0");
326 asm("ldx [%i1], %l1");
327 asm("mulx %l0, %l1, %l2");
328 asm("stx %l2, [%i2]");
329 asm("membar #Sync");
335 #ifdef V9B
337 #pragma align 64 (f0)
338 #pragma align 8 (f2)
340 #define MEMSIZE 2048*3
342 static uchar_t f0[64];
343 static uchar_t f2[8];
345 static uint32_t bmask[] = {0x01234567, 0x12345678,
346 0x23456789, 0x3456789a,
347 0x456789ab, 0x56789abc,
348 0x6789abcd, 0x789abcde,
349 0x89abcdef, 0x9abcdef0,
350 0xabcdef01, 0xbcdef012,
351 0xcdef0123, 0xdef01234,
352 0xef012345, 0xf0123456,
353 0x55555555, 0xaaaaaaaa,
354 0x00000000, 0xffffffff};
356 #ifdef __lint
358 /*ARGSUSED*/
359 unsigned long
360 setgsr(unsigned long arg1)
362 return (0);
365 /*ARGSUSED*/
366 float
367 fpackfix(double arg1)
369 return (0.0);
372 /*ARGSUSED*/
373 unsigned long
374 fcmpne16(double arg1, double arg2)
376 return (0);
379 /*ARGSUSED*/
380 unsigned long
381 fcmpgt16(double arg1, double arg2)
383 return (0);
386 #endif /* LINT */
389 * align_data(int loop, struct fps_test_ereport *report)
390 * returns whether a miscompare was found after running alignment tests
391 * loop amount of times. If an error is found, relevant data is stored
392 * in report. This test exercises the alignaddr and aligndata
393 * instructions with different byte alignments to ensure proper
394 * operation. These two instructions are used extensively by the kernel
395 * to move data size greater than 512 bytes. User level memcpy and
396 * memmove library also use these instructions for data size
397 * greater than 256 bytes.
400 align_data(int loop, struct fps_test_ereport *report)
402 char err[MAX_INFO_SIZE];
403 int test_ret;
404 int nr_malloc;
405 size_t memsize;
406 struct timeval timeout;
407 uchar_t c;
408 uchar_t *pf0;
409 uchar_t *pf2;
410 uchar_t *src;
411 uint32_t cnt;
412 uint32_t i;
413 uint32_t offset;
414 uint32_t start;
415 uint64_t expect[2];
416 uint64_t observe[2];
418 timeout.tv_sec = 0;
419 timeout.tv_usec = 10000;
420 nr_malloc = 0;
421 err[0] = '\0';
423 /* Make sure memsize is 64 bytes aligned with minimum of 64 bytes */
424 memsize = MEMSIZE;
425 memsize = memsize / 64 * 64;
427 if (memsize < 64)
428 memsize = 64;
430 src = (uchar_t *)memalign(64, memsize + 64);
432 while (src == NULL && nr_malloc < 10) {
433 (void) select(1, NULL, NULL, NULL, &timeout);
434 nr_malloc++;
435 src = (uchar_t *)memalign(64, memsize + 64);
438 if (src == NULL)
439 _exit(FPU_SYSCALL_FAIL);
441 /* Initialize source array with sequential data */
442 c = 0;
444 for (i = 0; i < memsize + 64; i++)
445 *(src + i) = c++;
447 for (cnt = 0; cnt < loop; cnt++) {
448 for (start = 1; start < 64; start += 1) {
449 offset = 0;
451 test_ret = do_aligndata(src + start, &offset,
452 memsize, f0, f2, bmask[cnt % 20]);
455 * Miscompare on the two aligndata
456 * instructions. Calculate offset to source
457 * array and get miscompare data
460 if (test_ret != 0) {
461 pf0 = f0 + offset % 64;
462 pf2 = f2;
464 for (i = 0; i < 8; i++) {
465 if (*(pf0 + i) != *(pf2 + i))
466 break;
469 (void) align_error_create(err, start,
470 offset + start + i, loop, cnt);
471 expect[0] =
472 (uint64_t)(*(uint8_t *)
473 (src + offset + start + i));
474 expect[1] = (uint64_t)0;
475 observe[0] = (uint64_t)(*(uint8_t *)(pf0 + i));
476 observe[1] = (uint64_t)(*(uint8_t *)(pf2 + i));
477 setup_fps_test_struct(
478 IS_EREPORT_INFO,
479 report, 6344, observe,
480 expect, 1, 2, err);
482 free(src);
484 return (-1);
488 * No miscompare on the aligndata
489 * instructions. Check to see whether the
490 * last 64 bytes matches the input
492 if (test_ret == 0) {
493 pf2 = src + offset + start;
495 for (i = 0; i < 64; i++) {
496 if (f0[i] != *(pf2 + i)) {
498 (void) align_error_create(err,
499 start,
500 offset + start + i,
501 loop, cnt);
502 expect[0] =
503 (uint64_t)(*(uint8_t *)
504 (pf2 + i));
505 expect[1] = (uint64_t)0;
506 observe[0] = (uint64_t)f0[i];
507 observe[1] = (uint64_t)0;
508 setup_fps_test_struct(
509 IS_EREPORT_INFO,
510 report, 6343, observe,
511 expect, 1, 1, err);
513 free(src);
514 return (-1);
521 free(src);
523 return (0);
527 * align_error_create(char *err, int start, int offset, int loop, int count)
528 * returns if a successful snprintf was performed when creating an align_data
529 * error message for align_data.
531 static int
532 align_error_create(char *err, uint32_t start,
533 uint32_t offset, int loop, uint32_t count)
535 if (err == NULL)
536 return (-1);
538 return snprintf(err, sizeof (err),
539 "Start = %2.2d offset = %2.2d loop = %d cnt = %d",
540 start, offset, loop, count);
544 * do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
545 * uchar_t *f0, uchar_t *f2, uint32_t bmask) performs
546 * the assembly lvl routines for align_data.
548 /*ARGSUSED*/
549 static int
550 do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
551 uchar_t *f0, uchar_t *f2, uint32_t bmask)
553 int ret = 1;
555 asm("bmask %i5,%g0,%g0");
556 /* produce GSR.offset and align %l0 to 8 bytes boundary */
557 asm("alignaddr %i0, %g0, %l0");
558 /* %i0 then used as error register, assume error */
559 asm("mov 1,%i0");
560 /* %l1 used as offset counter */
561 asm("mov -8,%l1");
562 asm("ldd [%l0], %f0");
564 asm("next_read:");
566 asm("ldd [%l0+8], %f2");
567 asm("ldd [%l0+0x10], %f4");
568 asm("faligndata %f0, %f2, %f32");
569 asm("faligndata %f0, %f2, %f48");
570 asm("fcmpd %fcc0,%f32,%f48");
571 asm("fblg,pn %fcc0,error");
572 /* %l1 contains offset value */
573 asm("add %l1,8,%l1");
574 /* 0 - 7 */
576 asm("ldd [%l0+0x18], %f6");
577 asm("faligndata %f2, %f4, %f34");
578 asm("faligndata %f2, %f4, %f48");
579 asm("fcmpd %fcc0,%f34,%f48");
580 asm("fblg,pn %fcc0,error");
581 /* %l1 contains offset value */
582 asm("add %l1,8,%l1");
583 /* 9 - 15 */
585 asm("ldd [%l0+0x20], %f8");
586 asm("faligndata %f4, %f6, %f36");
587 asm("faligndata %f4, %f6, %f48");
588 asm("fcmpd %fcc0,%f36,%f48");
589 asm("fblg,pn %fcc0,error");
590 /* %l1 contains offset value */
591 asm("add %l1,8,%l1");
592 /* 16 - 23 */
594 asm("ldd [%l0+0x28], %f10");
595 asm("faligndata %f6, %f8, %f38");
596 asm("faligndata %f6, %f8, %f48");
597 asm("fcmpd %fcc0,%f38,%f48");
598 asm("fblg,pn %fcc0,error");
599 /* contains offset value */
600 asm("add %l1,8,%l1");
601 /* 24 - 31 */
603 asm("ldd [%l0+0x28], %f10");
604 asm("faligndata %f8, %f10, %f40");
605 asm("faligndata %f8, %f10, %f48");
606 asm("fcmpd %fcc0,%f40,%f48");
607 asm("fblg,pn %fcc0,error");
608 /* %l1 contains offset value */
609 asm("add %l1,8,%l1");
610 /* 32 - 39 */
612 asm("ldd [%l0+0x30], %f12");
613 asm("faligndata %f10, %f12, %f42");
614 asm("faligndata %f10, %f12, %f48");
615 asm("fcmpd %fcc0,%f42,%f48");
616 asm("fblg,pn %fcc0,error");
617 /* %l1 contains offset value */
618 asm("add %l1,8,%l1");
619 /* 40 - 47 */
621 asm("ldd [%l0+0x38], %f14");
622 asm("faligndata %f12, %f14, %f44");
623 asm("faligndata %f12, %f14, %f48");
624 asm("fcmpd %fcc0,%f44,%f48");
625 asm("fblg,pn %fcc0,error");
626 /* %l1 contains offset value */
627 asm("add %l1,8,%l1");
628 /* 48 - 55 */
630 asm("ldd [%l0+0x40], %f0");
631 asm("faligndata %f14, %f0, %f46");
632 asm("faligndata %f14, %f0, %f48");
633 asm("fcmpd %fcc0,%f46,%f48");
634 asm("fblg,pn %fcc0,error");
635 /* %l1 contains offset value */
636 asm("add %l1,8,%l1");
637 /* 56 - 63 */
639 asm("subcc %i2,64,%i2");
640 asm("bg next_read");
641 asm("add %l0,64,%l0");
643 /* no miscompare error */
644 asm("mov 0,%i0");
645 ret = 0;
646 /* no error, move back to last 64 bytes boundary */
647 asm("sub %l1,56,%l1");
649 asm("error:");
650 asm("stda %f32,[%i3]0xf0");
651 asm("std %f48,[%i4]");
652 /* store offset value */
653 asm("st %l1,[%i1]");
654 asm("membar #Sync");
656 return (ret);
660 * vis_test(struct fps_test_ereport *report)
661 * checks if various RISC operations are performed
662 * succesfully. If an error is found, relevant data
663 * is stored in report.
666 vis_test(struct fps_test_ereport *report)
668 int v1;
669 int v2;
670 int v3;
672 v1 = visgt16(report);
673 v2 = visne16(report);
674 v3 = vispackfix(report);
676 if ((0 != v1) || (0 != v2) || (0 != v3))
677 return (-1);
679 return (0);
683 * visgt16(struct fps_test_ereport *report)
684 * does a greater-than compare instruction and returns if
685 * successful or not. If an error, relevant data is
686 * stored in report.
688 static int
689 visgt16(struct fps_test_ereport *report)
691 uint64_t expected;
692 uint64_t observed;
693 unsigned long a = 0x0000000000000001;
694 unsigned long b = 0x8000000008000008;
695 unsigned long c = fcmpgt16(*((double *)&a), *((double *)&b));
697 if (c == 0x8)
698 return (0);
699 else {
700 expected = (uint64_t)0x8;
701 observed = (*(uint64_t *)&c);
702 setup_fps_test_struct(NO_EREPORT_INFO, report,
703 6364, &observed, &expected, 1, 1);
705 return (-1);
710 * visne16(struct fps_test_ereport *report)
711 * does a not-equal compare instruction and returns if
712 * successful or not. If an error, relevant data is
713 * stored in report.
715 static int
716 visne16(struct fps_test_ereport *report)
718 uint64_t expected;
719 uint64_t observed;
720 unsigned long a = 0x0000000000000001;
721 unsigned long b = 0x0001000000001001;
722 unsigned long c = fcmpne16(*((double *)&a), *((double *)&b));
724 if (c == 0x9)
725 return (0);
726 else {
727 expected = (uint64_t)0x9;
728 observed = (*(uint64_t *)&c);
729 setup_fps_test_struct(NO_EREPORT_INFO, report,
730 6365, &observed, &expected, 1, 1);
732 return (-1);
737 * vispackfix(struct fps_test_ereport *report)
738 * does four 16-bit pack conversions to a lower precsion
739 * format and returns if successful or not. If an error,
740 * relevant data is stored in report.
742 static int
743 vispackfix(struct fps_test_ereport *report)
745 float b;
746 uint64_t expected;
747 uint64_t observed;
748 unsigned int c;
749 unsigned long a = 0x8008000008008008;
750 unsigned long gsr = 0;
752 (void) setgsr(gsr);
754 b = fpackfix(*((double *)&a));
755 c = *((unsigned int *)&b);
757 if (c == 0x80080800)
758 return (0);
759 else {
760 expected = (uint64_t)0x80080800;
761 observed = (uint64_t)c;
762 setup_fps_test_struct(NO_EREPORT_INFO, report,
763 6366, &observed, &expected, 1, 1);
765 return (-1);
769 #endif