- Fixes wrong return type for `is_close` - Adds stricter compiler flags for test files so we don't see the above issue again - Re-uses test helper functions between compare_sgemm_sbgemm/bgemm.cpull/5377/head
@@ -13,7 +13,7 @@ | |||||
# 3. Neither the name of the OpenBLAS project nor the names of | # 3. Neither the name of the OpenBLAS project nor the names of | ||||
# its contributors may be used to endorse or promote products | # its contributors may be used to endorse or promote products | ||||
# derived from this software without specific prior written permission. | # derived from this software without specific prior written permission. | ||||
# | |||||
# | |||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
@@ -34,6 +34,7 @@ ifneq (, $(filter $(CORE),LOONGSON3R3 LOONGSON3R4)) | |||||
endif | endif | ||||
override FFLAGS += -fno-tree-vectorize | override FFLAGS += -fno-tree-vectorize | ||||
endif | endif | ||||
override CFLAGS += -std=c11 -Wall -Werror | |||||
SUPPORT_GEMM3M = 0 | SUPPORT_GEMM3M = 0 | ||||
@@ -402,10 +403,10 @@ zblat3 : zblat3.$(SUFFIX) ../$(LIBNAME) | |||||
endif | endif | ||||
ifeq ($(BUILD_BFLOAT16),1) | ifeq ($(BUILD_BFLOAT16),1) | ||||
test_bgemm : compare_sgemm_bgemm.c ../$(LIBNAME) | |||||
test_bgemm : compare_sgemm_bgemm.c test_helpers.h ../$(LIBNAME) | |||||
$(CC) $(CLDFLAGS) -o test_bgemm compare_sgemm_bgemm.c ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) | $(CC) $(CLDFLAGS) -o test_bgemm compare_sgemm_bgemm.c ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) | ||||
test_sbgemm : compare_sgemm_sbgemm.c ../$(LIBNAME) | |||||
test_sbgemm : compare_sgemm_sbgemm.c test_helpers.h ../$(LIBNAME) | |||||
$(CC) $(CLDFLAGS) -o test_sbgemm compare_sgemm_sbgemm.c ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) | $(CC) $(CLDFLAGS) -o test_sbgemm compare_sgemm_sbgemm.c ../$(LIBNAME) $(EXTRALIB) $(CEXTRALIB) | ||||
endif | endif | ||||
@@ -28,20 +28,13 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include "test_helpers.h" | |||||
#define SGEMM BLASFUNC(sgemm) | #define SGEMM BLASFUNC(sgemm) | ||||
#define BGEMM BLASFUNC(bgemm) | #define BGEMM BLASFUNC(bgemm) | ||||
#define BGEMM_LARGEST 256 | #define BGEMM_LARGEST 256 | ||||
static float float16to32(bfloat16 value) | |||||
{ | |||||
blasint one = 1; | |||||
float result; | |||||
sbf16tos_(&one, &value, &one, &result, &one); | |||||
return result; | |||||
} | |||||
static float truncate_float(float value) { | |||||
static float truncate_float32_to_bfloat16(float value) { | |||||
blasint one = 1; | blasint one = 1; | ||||
bfloat16 tmp; | bfloat16 tmp; | ||||
float result; | float result; | ||||
@@ -50,17 +43,6 @@ static float truncate_float(float value) { | |||||
return result; | return result; | ||||
} | } | ||||
static void *malloc_safe(size_t size) { | |||||
if (size == 0) | |||||
return malloc(1); | |||||
else | |||||
return malloc(size); | |||||
} | |||||
static float is_close(float a, float b, float rtol, float atol) { | |||||
return fabs(a - b) <= (atol + rtol*fabs(b)); | |||||
} | |||||
int | int | ||||
main (int argc, char *argv[]) | main (int argc, char *argv[]) | ||||
{ | { | ||||
@@ -151,15 +133,15 @@ main (int argc, char *argv[]) | |||||
DD[i * m + j] += | DD[i * m + j] += | ||||
float16to32 (AA[k * j + l]) * float16to32 (BB[i + l * n]); | float16to32 (AA[k * j + l]) * float16to32 (BB[i + l * n]); | ||||
} | } | ||||
if (!is_close(float16to32(CC[i * m + j]), truncate_float(C[i * m + j]), 0.01, 0.001)) { | |||||
if (!is_close(float16to32(CC[i * m + j]), truncate_float32_to_bfloat16(C[i * m + j]), 0.01, 0.001)) { | |||||
printf("Mismatch at i=%d, j=%d, k=%d: CC=%.6f, C=%.6f\n", | printf("Mismatch at i=%d, j=%d, k=%d: CC=%.6f, C=%.6f\n", | ||||
i, j, k, float16to32(CC[i * m + j]), truncate_float(C[i * m + j])); | |||||
i, j, k, float16to32(CC[i * m + j]), truncate_float32_to_bfloat16(C[i * m + j])); | |||||
ret++; | ret++; | ||||
} | } | ||||
if (!is_close(float16to32(CC[i * m + j]), truncate_float(DD[i * m + j]), 0.0001, 0.00001)) { | |||||
if (!is_close(float16to32(CC[i * m + j]), truncate_float32_to_bfloat16(DD[i * m + j]), 0.0001, 0.00001)) { | |||||
printf("Mismatch at i=%d, j=%d, k=%d: CC=%.6f, DD=%.6f\n", | printf("Mismatch at i=%d, j=%d, k=%d: CC=%.6f, DD=%.6f\n", | ||||
i, j, k, float16to32(CC[i * m + j]), truncate_float(DD[i * m + j])); | |||||
i, j, k, float16to32(CC[i * m + j]), truncate_float32_to_bfloat16(DD[i * m + j])); | |||||
ret++; | ret++; | ||||
} | } | ||||
@@ -27,72 +27,15 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include "../common.h" | #include "../common.h" | ||||
#include "test_helpers.h" | |||||
#define SGEMM BLASFUNC(sgemm) | #define SGEMM BLASFUNC(sgemm) | ||||
#define SBGEMM BLASFUNC(sbgemm) | #define SBGEMM BLASFUNC(sbgemm) | ||||
#define SGEMV BLASFUNC(sgemv) | #define SGEMV BLASFUNC(sgemv) | ||||
#define SBGEMV BLASFUNC(sbgemv) | #define SBGEMV BLASFUNC(sbgemv) | ||||
typedef union | |||||
{ | |||||
unsigned short v; | |||||
#if defined(_AIX) | |||||
struct __attribute__((packed)) | |||||
#else | |||||
struct | |||||
#endif | |||||
{ | |||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |||||
unsigned short s:1; | |||||
unsigned short e:8; | |||||
unsigned short m:7; | |||||
#else | |||||
unsigned short m:7; | |||||
unsigned short e:8; | |||||
unsigned short s:1; | |||||
#endif | |||||
} bits; | |||||
} bfloat16_bits; | |||||
typedef union | |||||
{ | |||||
float v; | |||||
#if defined(_AIX) | |||||
struct __attribute__((packed)) | |||||
#else | |||||
struct | |||||
#endif | |||||
{ | |||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |||||
uint32_t s:1; | |||||
uint32_t e:8; | |||||
uint32_t m:23; | |||||
#else | |||||
uint32_t m:23; | |||||
uint32_t e:8; | |||||
uint32_t s:1; | |||||
#endif | |||||
} bits; | |||||
} float32_bits; | |||||
float | |||||
float16to32 (bfloat16_bits f16) | |||||
{ | |||||
float32_bits f32; | |||||
f32.bits.s = f16.bits.s; | |||||
f32.bits.e = f16.bits.e; | |||||
f32.bits.m = (uint32_t) f16.bits.m << 16; | |||||
return f32.v; | |||||
} | |||||
#define SBGEMM_LARGEST 256 | #define SBGEMM_LARGEST 256 | ||||
void *malloc_safe(size_t size) | |||||
{ | |||||
if (size == 0) | |||||
return malloc(1); | |||||
else | |||||
return malloc(size); | |||||
} | |||||
int | int | ||||
main (int argc, char *argv[]) | main (int argc, char *argv[]) | ||||
{ | { | ||||
@@ -111,14 +54,13 @@ main (int argc, char *argv[]) | |||||
float *A = (float *)malloc_safe(m * k * sizeof(FLOAT)); | float *A = (float *)malloc_safe(m * k * sizeof(FLOAT)); | ||||
float *B = (float *)malloc_safe(k * n * sizeof(FLOAT)); | float *B = (float *)malloc_safe(k * n * sizeof(FLOAT)); | ||||
float *C = (float *)malloc_safe(m * n * sizeof(FLOAT)); | float *C = (float *)malloc_safe(m * n * sizeof(FLOAT)); | ||||
bfloat16_bits *AA = (bfloat16_bits *)malloc_safe(m * k * sizeof(bfloat16_bits)); | |||||
bfloat16_bits *BB = (bfloat16_bits *)malloc_safe(k * n * sizeof(bfloat16_bits)); | |||||
bfloat16 *AA = (bfloat16 *)malloc_safe(m * k * sizeof(bfloat16)); | |||||
bfloat16 *BB = (bfloat16 *)malloc_safe(k * n * sizeof(bfloat16)); | |||||
float *DD = (float *)malloc_safe(m * n * sizeof(FLOAT)); | float *DD = (float *)malloc_safe(m * n * sizeof(FLOAT)); | ||||
float *CC = (float *)malloc_safe(m * n * sizeof(FLOAT)); | float *CC = (float *)malloc_safe(m * n * sizeof(FLOAT)); | ||||
if ((A == NULL) || (B == NULL) || (C == NULL) || (AA == NULL) || (BB == NULL) || | if ((A == NULL) || (B == NULL) || (C == NULL) || (AA == NULL) || (BB == NULL) || | ||||
(DD == NULL) || (CC == NULL)) | (DD == NULL) || (CC == NULL)) | ||||
return 1; | return 1; | ||||
bfloat16 atmp,btmp; | |||||
blasint one=1; | blasint one=1; | ||||
for (j = 0; j < m; j++) | for (j = 0; j < m; j++) | ||||
@@ -126,8 +68,7 @@ main (int argc, char *argv[]) | |||||
for (i = 0; i < k; i++) | for (i = 0; i < k; i++) | ||||
{ | { | ||||
A[j * k + i] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | A[j * k + i] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | ||||
sbstobf16_(&one, &A[j*k+i], &one, &atmp, &one); | |||||
AA[j * k + i].v = atmp; | |||||
sbstobf16_(&one, &A[j*k+i], &one, &AA[j * k + i], &one); | |||||
} | } | ||||
} | } | ||||
for (j = 0; j < n; j++) | for (j = 0; j < n; j++) | ||||
@@ -135,8 +76,7 @@ main (int argc, char *argv[]) | |||||
for (i = 0; i < k; i++) | for (i = 0; i < k; i++) | ||||
{ | { | ||||
B[j * k + i] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | B[j * k + i] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | ||||
sbstobf16_(&one, &B[j*k+i], &one, &btmp, &one); | |||||
BB[j * k + i].v = btmp; | |||||
sbstobf16_(&one, &B[j*k+i], &one, &BB[j * k + i], &one); | |||||
} | } | ||||
} | } | ||||
for (y = 0; y < 4; y++) | for (y = 0; y < 4; y++) | ||||
@@ -182,10 +122,12 @@ main (int argc, char *argv[]) | |||||
DD[i * m + j] += | DD[i * m + j] += | ||||
float16to32 (AA[k * j + l]) * float16to32 (BB[i + l * n]); | float16to32 (AA[k * j + l]) * float16to32 (BB[i + l * n]); | ||||
} | } | ||||
if (fabs (CC[i * m + j] - C[i * m + j]) > 1.0) | |||||
if (!is_close(CC[i * m + j], C[i * m + j], 0.01, 0.001)) { | |||||
ret++; | ret++; | ||||
if (fabs (CC[i * m + j] - DD[i * m + j]) > 1.0) | |||||
} | |||||
if (!is_close(CC[i * m + j], DD[i * m + j], 0.001, 0.0001)) { | |||||
ret++; | ret++; | ||||
} | |||||
} | } | ||||
} | } | ||||
free(A); | free(A); | ||||
@@ -211,14 +153,13 @@ main (int argc, char *argv[]) | |||||
float *A = (float *)malloc_safe(x * x * sizeof(FLOAT)); | float *A = (float *)malloc_safe(x * x * sizeof(FLOAT)); | ||||
float *B = (float *)malloc_safe(x * sizeof(FLOAT) << l); | float *B = (float *)malloc_safe(x * sizeof(FLOAT) << l); | ||||
float *C = (float *)malloc_safe(x * sizeof(FLOAT) << l); | float *C = (float *)malloc_safe(x * sizeof(FLOAT) << l); | ||||
bfloat16_bits *AA = (bfloat16_bits *)malloc_safe(x * x * sizeof(bfloat16_bits)); | |||||
bfloat16_bits *BB = (bfloat16_bits *)malloc_safe(x * sizeof(bfloat16_bits) << l); | |||||
bfloat16 *AA = (bfloat16 *)malloc_safe(x * x * sizeof(bfloat16)); | |||||
bfloat16 *BB = (bfloat16 *)malloc_safe(x * sizeof(bfloat16) << l); | |||||
float *DD = (float *)malloc_safe(x * sizeof(FLOAT)); | float *DD = (float *)malloc_safe(x * sizeof(FLOAT)); | ||||
float *CC = (float *)malloc_safe(x * sizeof(FLOAT) << l); | float *CC = (float *)malloc_safe(x * sizeof(FLOAT) << l); | ||||
if ((A == NULL) || (B == NULL) || (C == NULL) || (AA == NULL) || (BB == NULL) || | if ((A == NULL) || (B == NULL) || (C == NULL) || (AA == NULL) || (BB == NULL) || | ||||
(DD == NULL) || (CC == NULL)) | (DD == NULL) || (CC == NULL)) | ||||
return 1; | return 1; | ||||
bfloat16 atmp, btmp; | |||||
blasint one = 1; | blasint one = 1; | ||||
for (j = 0; j < x; j++) | for (j = 0; j < x; j++) | ||||
@@ -226,12 +167,10 @@ main (int argc, char *argv[]) | |||||
for (i = 0; i < x; i++) | for (i = 0; i < x; i++) | ||||
{ | { | ||||
A[j * x + i] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | A[j * x + i] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | ||||
sbstobf16_(&one, &A[j*x+i], &one, &atmp, &one); | |||||
AA[j * x + i].v = atmp; | |||||
sbstobf16_(&one, &A[j*x+i], &one, &AA[j * x + i], &one); | |||||
} | } | ||||
B[j << l] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | B[j << l] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | ||||
sbstobf16_(&one, &B[j << l], &one, &btmp, &one); | |||||
BB[j << l].v = btmp; | |||||
sbstobf16_(&one, &B[j << l], &one, &BB[j << l], &one); | |||||
CC[j << l] = C[j << l] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | CC[j << l] = C[j << l] = ((FLOAT) rand () / (FLOAT) RAND_MAX) + 0.5; | ||||
} | } | ||||
@@ -262,10 +201,12 @@ main (int argc, char *argv[]) | |||||
} | } | ||||
for (j = 0; j < x; j++) { | for (j = 0; j < x; j++) { | ||||
if (fabs (CC[j << l] - C[j << l]) > 1.0) | |||||
if (!is_close(CC[j << l], C[j << l], 0.01, 0.001)) { | |||||
ret++; | ret++; | ||||
if (fabs (CC[j << l] - DD[j]) > 1.0) | |||||
} | |||||
if (!is_close(CC[j << l], DD[j], 0.001, 0.0001)) { | |||||
ret++; | ret++; | ||||
} | |||||
} | } | ||||
} | } | ||||
free(A); | free(A); | ||||
@@ -0,0 +1,55 @@ | |||||
/*************************************************************************** | |||||
Copyright (c) 2025 The OpenBLAS Project | |||||
All rights reserved. | |||||
Redistribution and use in source and binary forms, with or without | |||||
modification, are permitted provided that the following conditions are | |||||
met: | |||||
1. Redistributions of source code must retain the above copyright | |||||
notice, this list of conditions and the following disclaimer. | |||||
2. Redistributions in binary form must reproduce the above copyright | |||||
notice, this list of conditions and the following disclaimer in | |||||
the documentation and/or other materials provided with the | |||||
distribution. | |||||
3. Neither the name of the OpenBLAS project nor the names of | |||||
its contributors may be used to endorse or promote products | |||||
derived from this software without specific prior written permission. | |||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBLAS PROJECT OR CONTRIBUTORS BE | |||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | |||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||||
*****************************************************************************/ | |||||
#ifndef TEST_HELPERS_H | |||||
#define TEST_HELPERS_H | |||||
#include <stdbool.h> | |||||
#include "../common.h" | |||||
#if IFLOAT == bfloat16 | |||||
static float float16to32(bfloat16 value) | |||||
{ | |||||
blasint one = 1; | |||||
float result; | |||||
sbf16tos_(&one, &value, &one, &result, &one); | |||||
return result; | |||||
} | |||||
#endif | |||||
static void *malloc_safe(size_t size) { | |||||
if (size == 0) | |||||
return malloc(1); | |||||
else | |||||
return malloc(size); | |||||
} | |||||
static bool is_close(float a, float b, float rtol, float atol) { | |||||
return fabs(a - b) <= (atol + rtol*fabs(b)); | |||||
} | |||||
#endif |