benchmarks.c revision 60c45ed01d4f99571d468c42f609d11a099fab1e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc.
* All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __lint
#endif
#include <stdlib.h>
#include <unistd.h>
#include <fp.h>
#include <fps_ereport.h>
#define EXPECTED 1.9999999999999998E+00
#ifdef V9B
float fpackfix(double);
struct fps_test_ereport *report);
unsigned long fcmpgt16(double, double);
unsigned long fcmpne16(double, double);
unsigned long setgsr(unsigned long);
#endif
/*
* fpu_fdivd(int rloop, int unit, struct fps_test_ereport *report)
* returns whether the correct value is calculated each time
* rloop times. If an error is found, the relevant data is stored
* in report. The test uses internally generated random double
* precision within a certain range to conduct the following test:
*
* (a * 2^1022) / ((a+e) * 2^1021)
*
* which is guaranteed to fill the resulting mantissa with all ones.
*
*/
int
{
char err_data[MAX_INFO_SIZE];
double expect_ans = EXPECTED;
double f12 = 0;
double f2;
double f22;
int loop = 0;
srand48(1L);
loop++;
/* LINTED */
#ifdef __lint
(void) f22;
#endif
/* LINTED */
#ifdef __lint
(void) f2;
#endif
if (f12 != expect_ans) {
"\nExpected: %.16e,\nObserved: %.16e",
expect_ans, f12);
return (-1);
}
}
return (0);
}
/*
* fdivd(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
* performs the assembly level instructions for
* fpu_fdivd.
*/
/* ARGSUSED */
static void
{
asm("ldd [%i0], %f22");
asm("ldd [%i1], %f2");
asm("fdivd %f22, %f2, %f12");
asm("std %f12,[%i2]");
asm("membar #Sync");
}
/*
* fpu_fmuld(int rloop, int unit, struct fps_test_ereport *report)
* returns whether the correct value is calculated each time
* rloop times. If an error is found, the relevant data is stored
* in report. The goal is to check if (x * y) == (y * x). The
* data pattern is important, and the back-to-back fmuld's are
* important.
*/
int
{
char err_data[MAX_INFO_SIZE];
double x;
double y;
double z;
double z1;
int loop;
loop = 0;
*py = 0x2FE284A9A98EAA26UL;
#ifdef __lint
(void) x;
(void) y;
#endif
loop++;
z = z1 = 0.0;
/*
* Data pattern and back-to-back fmuld() are
* important
*/
"\nExpected: %.16e,\nObserved: %.16e",
return (-1);
}
}
return (0);
}
/*
* fmuld(double *x,double *y, double *z, double *z1)
* performs the assembly level instructions for
* fpu_fmuld.
*/
/* ARGSUSED */
static void
{
asm("ldd[%i0], %f0");
asm("ldd[%i1], %f4");
asm("fmuld%f0, %f4, %f2");
asm("fmuld%f4, %f0, %f6");
asm("std%f2, [%i2]");
asm("std%f6, [%i3]");
asm("membar #Sync");
}
/*
* fpu_fmulx(int rloop, int unit, struct fps_test_ereport *report)
* returns whether the correct value is calculated each time
* rloop times. If an error is found, the relevant data is stored
* in report. The goal is to check if (x * y) == (y * x) with
* 64-bit intgers.
*/
int
{
char err_data[MAX_INFO_SIZE];
int loop;
int loop_lim;
loop = 0;
if (loop_lim < 10)
loop_lim = 10;
if (loop_lim > 100000)
loop_lim = 100000;
#ifdef __lint
(void) v1;
(void) v2;
#endif
srand(0l);
loop++;
#ifndef __lint
#endif
/* LINTED */
/* LINTED */
return (-1);
}
}
return (0);
}
/*
* fmulx(uint64_t *rs1, uint64_t *rs2, uint64_t *rd)
* performs the assembly level instructions for
* fpu_fmulx.
*/
/* ARGSUSED */
static void
{
asm("ldx [%i0], %l0");
asm("ldx [%i1], %l1");
asm("mulx %l0, %l1, %l2");
asm("stx %l2, [%i2]");
asm("membar #Sync");
}
#ifdef V9B
0x23456789, 0x3456789a,
0x456789ab, 0x56789abc,
0x6789abcd, 0x789abcde,
0x89abcdef, 0x9abcdef0,
0xabcdef01, 0xbcdef012,
0xcdef0123, 0xdef01234,
0xef012345, 0xf0123456,
0x55555555, 0xaaaaaaaa,
0x00000000, 0xffffffff};
/*
* align_data(int loop, int unit, struct fps_test_ereport *report)
* returns whether a miscompare was found after running alignment tests
* loop amount of times. If an error is found, relevant data is stored
* in report. This test exercises the alignaddr and aligndata
* instructions with different byte alignments to ensure proper
* operation. These two instructions are used extensively by the kernel
* to move data size greater than 512 bytes. User level memcpy and
* memmove library also use these instructions for data size
* greater than 256 bytes.
*/
int
{
char err[MAX_INFO_SIZE];
int test_ret;
int nr_malloc;
uchar_t c;
uint32_t i;
nr_malloc = 0;
err[0] = '\0';
/* Make sure memsize is 64 bytes aligned with minimum of 64 bytes */
if (memsize < 64)
memsize = 64;
nr_malloc++;
}
/* Initialize source array with sequential data */
c = 0;
for (i = 0; i < memsize + 64; i++)
*(src + i) = c++;
test_ret = 0;
offset = 0;
/*
* Miscompare on the two aligndata
* instructions. Calculate offset to source
* array and get miscompare data
*/
if (test_ret != 0) {
for (i = 0; i < 8; i++) {
break;
}
expect[0] =
return (-1);
}
/*
* No miscompare on the aligndata
* instructions. Check to see whether the
* last 64 bytes matches the input
*/
if (test_ret == 0) {
for (i = 0; i < 64; i++) {
expect[0] =
(pf2 + i));
return (-1);
}
}
}
}
}
return (0);
}
/*
* align_error_create(char *err, int start, int offset, int loop, int count)
* returns if a successful snprintf was performed when creating an align_data
* error message for align_data.
*/
static int
{
return (-1);
"Start = %2.2d offset = %2.2d loop = %d cnt = %d",
}
/*
* do_aligndata(uchar_t *from, uint32_t *offset, size_t sz,
* uchar_t *f0, uchar_t *f2, uint32_t bmask) performs
* the assembly lvl routines for align_data.
*/
static int
{
asm("bmask %i5,%g0,%g0");
/* produce GSR.offset and align %l0 to 8 bytes boundary */
asm("alignaddr %i0, %g0, %l0");
/* %i0 then used as error register, assume error */
asm("mov 1,%i0");
/* %l1 used as offset counter */
asm("mov -8,%l1");
asm("ldd [%l0], %f0");
asm("next_read:");
asm("ldd [%l0+8], %f2");
asm("ldd [%l0+0x10], %f4");
asm("faligndata %f0, %f2, %f32");
asm("faligndata %f0, %f2, %f48");
asm("fcmpd %fcc0,%f32,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 0 - 7 */
asm("ldd [%l0+0x18], %f6");
asm("faligndata %f2, %f4, %f34");
asm("faligndata %f2, %f4, %f48");
asm("fcmpd %fcc0,%f34,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 9 - 15 */
asm("ldd [%l0+0x20], %f8");
asm("faligndata %f4, %f6, %f36");
asm("faligndata %f4, %f6, %f48");
asm("fcmpd %fcc0,%f36,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 16 - 23 */
asm("ldd [%l0+0x28], %f10");
asm("faligndata %f6, %f8, %f38");
asm("faligndata %f6, %f8, %f48");
asm("fcmpd %fcc0,%f38,%f48");
asm("fblg,pn %fcc0,error");
/* contains offset value */
asm("add %l1,8,%l1");
/* 24 - 31 */
asm("ldd [%l0+0x28], %f10");
asm("faligndata %f8, %f10, %f40");
asm("faligndata %f8, %f10, %f48");
asm("fcmpd %fcc0,%f40,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 32 - 39 */
asm("ldd [%l0+0x30], %f12");
asm("faligndata %f10, %f12, %f42");
asm("faligndata %f10, %f12, %f48");
asm("fcmpd %fcc0,%f42,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 40 - 47 */
asm("ldd [%l0+0x38], %f14");
asm("faligndata %f12, %f14, %f44");
asm("faligndata %f12, %f14, %f48");
asm("fcmpd %fcc0,%f44,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 48 - 55 */
asm("ldd [%l0+0x40], %f0");
asm("faligndata %f14, %f0, %f46");
asm("faligndata %f14, %f0, %f48");
asm("fcmpd %fcc0,%f46,%f48");
asm("fblg,pn %fcc0,error");
/* %l1 contains offset value */
asm("add %l1,8,%l1");
/* 56 - 63 */
asm("subcc %i2,64,%i2");
asm("bg next_read");
asm("add %l0,64,%l0");
/* no miscompare error */
asm("mov 0,%i0");
/* no error, move back to last 64 bytes boundary */
asm("sub %l1,56,%l1");
asm("error:");
asm("stda %f32,[%i3]0xf0");
asm("std %f48,[%i4]");
/* store offset value */
asm("st %l1,[%i1]");
asm("membar #Sync");
}
/*
* vis_test(int unit, struct fps_test_ereport *report)
* checks if various RISC operations are performed
* succesfully. If an error is found, relevant data
* is stored in report.
*/
int
{
int v1;
int v2;
int v3;
return (-1);
return (0);
}
/*
* visgt16(int unit, struct fps_test_ereport *report)
* does a greater-than compare instruction and returns if
* successful or not. If an error, relevant data is
* stored in report.
*/
static int
{
unsigned long a = 0x0000000000000001;
unsigned long b = 0x8000000008000008;
unsigned long c = fcmpgt16(*((double *)&a), *((double *)&b));
if (c == 0x8)
return (0);
else {
return (-1);
}
}
/*
* visne16(int unit, struct fps_test_ereport *report)
* does a not-equal compare instruction and returns if
* successful or not. If an error, relevant data is
* stored in report.
*/
static int
{
unsigned long a = 0x0000000000000001;
unsigned long b = 0x0001000000001001;
unsigned long c = fcmpne16(*((double *)&a), *((double *)&b));
if (c == 0x9)
return (0);
else {
return (-1);
}
}
/*
* vispackfix(int unit, struct fps_test_ereport *report)
* does four 16-bit pack conversions to a lower precsion
* format and returns if successful or not. If an error,
* relevant data is stored in report.
*/
static int
{
float b;
int failed = 0;
unsigned int c;
unsigned long a = 0x8008000008008008;
unsigned long gsr = 0;
unsigned long old_gsr;
b = fpackfix(*((double *)&a));
c = *((unsigned int *)&b);
if (c == 0x80080800)
return (0);
else {
return (-1);
}
}
#endif