benchmarks: Add Whetstone FPU benchmark

Add the Whetstone floating-point benchmark to NuttX applications.
The Whetstone benchmark is a widely-used tool for evaluating FPU
(floating-point unit) performance.

This benchmark is ported from netlib.org whetstone.c which has a
custom permissive license requiring attribution. Therefore it
depends on ALLOW_CUSTOM_PERMISSIVE_COMPONENTS.

Usage: whetstone [loops]

Signed-off-by: makejian <makejian@xiaomi.com>
This commit is contained in:
makejian 2026-01-20 10:29:56 +08:00 committed by Alan C. Assis
parent 37403210f9
commit 9148fb9718
5 changed files with 637 additions and 0 deletions

View file

@ -0,0 +1,31 @@
# ##############################################################################
# apps/benchmarks/whetstone/CMakeLists.txt
#
# Licensed to the Apache Software Foundation (ASF) under one or more contributor
# license agreements. See the NOTICE file distributed with this work for
# additional information regarding copyright ownership. The ASF licenses this
# file to you under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#
# ##############################################################################
if(CONFIG_BENCHMARK_WHETSTONE)
nuttx_add_application(
NAME
${CONFIG_BENCHMARK_WHETSTONE_PROGNAME}
SRCS
whetstone.c
STACKSIZE
${CONFIG_BENCHMARK_WHETSTONE_STACKSIZE}
PRIORITY
${CONFIG_BENCHMARK_WHETSTONE_PRIORITY})
endif()

View file

@ -0,0 +1,34 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config BENCHMARK_WHETSTONE
tristate "Double Precision Benchmark"
default n
depends on ALLOW_CUSTOM_PERMISSIVE_COMPONENTS
---help---
Enable a Whetstone test.
This benchmark is based on the C converted version from
https://www.netlib.org/benchmark/whetstone.c which has a
custom permissive license requiring attribution.
if BENCHMARK_WHETSTONE
config BENCHMARK_WHETSTONE_PROGNAME
string "Program name"
default "whetstone"
---help---
This is the name of the program that will be used when the NSH ELF
program is installed.
config BENCHMARK_WHETSTONE_PRIORITY
int "Whetstone test task priority"
default 100
config BENCHMARK_WHETSTONE_STACKSIZE
int "Whetstone test stack size"
default DEFAULT_TASK_STACKSIZE
endif

View file

@ -0,0 +1,23 @@
############################################################################
# apps/benchmarks/whetstone/Make.defs
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
ifneq ($(CONFIG_BENCHMARK_WHETSTONE),)
CONFIGURED_APPS += $(APPDIR)/benchmarks/whetstone
endif

View file

@ -0,0 +1,32 @@
############################################################################
# apps/benchmarks/whetstone/Makefile
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################
include $(APPDIR)/Make.defs
# WHETSTONE speed test
PROGNAME = $(CONFIG_BENCHMARK_WHETSTONE_PROGNAME)
PRIORITY = $(CONFIG_BENCHMARK_WHETSTONE_PRIORITY)
STACKSIZE = $(CONFIG_BENCHMARK_WHETSTONE_STACKSIZE)
MODULE = $(CONFIG_BENCHMARK_WHETSTONE)
MAINSRC = whetstone.c
include $(APPDIR)/Application.mk

View file

@ -0,0 +1,517 @@
/****************************************************************************
* apps/benchmarks/whetstone/whetstone.c
*
* SPDX-License-Identifier: LicenseRef-Painter-Engineering-Whetstone
*
* Converted Whetstone Double Precision Benchmark
* Version 1.2 22 March 1998
*
* (c) Copyright 1998 Painter Engineering, Inc.
* All Rights Reserved.
*
* Permission is granted to use, duplicate, and
* publish this text and program as long as it
* includes this entire comment block and limited
* rights reference.
*
* Converted by Rich Painter, Painter Engineering, Inc. based on the
* www.netlib.org benchmark/whetstoned version obtained 16 March 1998.
*
* A novel approach was used here to keep the look and feel of the
* FORTRAN version. Altering the FORTRAN-based array indices,
* starting at element 1, to start at element 0 for C, would require
* numerous changes, including decrementing the variable indices by 1.
* Instead, the array e1[] was declared 1 element larger in C. This
* allows the FORTRAN index range to function without any literal or
* variable indices changes. The array element e1[0] is simply never
* used and does not alter the benchmark results.
*
* The major FORTRAN comment blocks were retained to minimize
* differences between versions. Modules N5 and N12, like in the
* FORTRAN version, have been eliminated here.
*
* An optional command-line argument has been provided [-c] to
* offer continuous repetition of the entire benchmark.
* An optional argument for setting an alternate loop count is also
* provided. Define PRINTOUT to cause the pout() function to print
* outputs at various stages. Final timing measurements should be
* made with the PRINTOUT undefined.
*
* Questions and comments may be directed to the author at
* r.painter@ieee.org
****************************************************************************/
/****************************************************************************
* Benchmark #2 -- Double Precision Whetstone (A001)
*
* o This is a REAL*8 version of
* the Whetstone benchmark program.
*
* o DO-loop semantics are ANSI-66 compatible.
*
* o Final measurements are to be made with all
* WRITE statements and FORMAT sttements removed.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
/* standard C library headers required */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
/* the following is optional depending on the timing function used */
#include <time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* map the FORTRAN math functions, etc. to the C versions */
#define DSIN sin
#define DCOS cos
#define DATAN atan
#define DLOG log
#define DEXP exp
#define DSQRT sqrt
#define IF if
#define USAGE "usage: whetdc [-c] [loops]\n"
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* function prototypes */
void pout(long n, long j, long k, double x1,
double x2, double x3, double x4);
void pa(double e[]);
void p0(void);
void p3(double x, double y, FAR double *z);
/****************************************************************************
* Private Data
****************************************************************************/
/* COMMON t,t1,t2,e1(4),j,k,l */
double t;
double t1;
double t2;
double e1[5];
int j;
int k;
int l;
/****************************************************************************
* Public Functions
****************************************************************************/
int main(int argc, FAR char *argv[])
{
/* used in the FORTRAN version */
long loop;
long i;
long n1;
long n2;
long n3;
long n4;
long n6;
long n7;
long n8;
long n9;
long n10;
long n11;
double x1;
double x2;
double x3;
double x4;
double x;
double y;
double z;
int ii;
int jj;
/* added for this version */
long loopstart;
long startsec;
long finisec;
float KIPS;
int continuous;
loopstart = 1000; /* see the note about loop below */
continuous = 0;
ii = 1; /* start at the first arg (temp use of ii here) */
while (ii < argc)
{
if (strncmp(argv[ii], "-c", 2) == 0 || argv[ii][0] == 'c')
{
continuous = 1;
}
else if (atol(argv[ii]) > 0)
{
loopstart = atol(argv[ii]);
}
else
{
fprintf(stderr, USAGE);
return 1;
}
ii++;
}
LCONT:
/* Start benchmark timing at this point. */
startsec = time(0);
/* The actual benchmark starts here. */
t = .499975;
t1 = 0.50025;
t2 = 2.0;
/* With loopcount loop=10, one million Whetstone instructions
* will be executed in EACH MAJOR loop..A MAJOR loop IS EXECUTED
* 'ii' TIMES TO INCREASE WALL-CLOCK TIMING ACCURACY.
*
* loop = 1000;
*/
loop = loopstart;
ii = 1;
jj = 1;
IILOOP:
n1 = 0;
n2 = 12 * loop;
n3 = 14 * loop;
n4 = 345 * loop;
n6 = 210 * loop;
n7 = 32 * loop;
n8 = 899 * loop;
n9 = 616 * loop;
n10 = 0;
n11 = 93 * loop;
/* Module 1: Simple identifiers */
x1 = 1.0;
x2 = -1.0;
x3 = -1.0;
x4 = -1.0;
for (i = 1; i <= n1; i++)
{
x1 = (x1 + x2 + x3 - x4) * t;
x2 = (x1 + x2 - x3 + x4) * t;
x3 = (x1 - x2 + x3 + x4) * t;
x4 = (-x1 + x2 + x3 + x4) * t;
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n1, n1, n1, x1, x2, x3, x4);
}
#endif
/* Module 2: Array elements */
e1[1] = 1.0;
e1[2] = -1.0;
e1[3] = -1.0;
e1[4] = -1.0;
for (i = 1; i <= n2; i++)
{
e1[1] = (e1[1] + e1[2] + e1[3] - e1[4]) * t;
e1[2] = (e1[1] + e1[2] - e1[3] + e1[4]) * t;
e1[3] = (e1[1] - e1[2] + e1[3] + e1[4]) * t;
e1[4] = (-e1[1] + e1[2] + e1[3] + e1[4]) * t;
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n2, n3, n2, e1[1], e1[2], e1[3], e1[4]);
}
#endif
/* Module 3: Array as parameter */
for (i = 1; i <= n3; i++)
{
pa(e1);
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n3, n2, n2, e1[1], e1[2], e1[3], e1[4]);
}
#endif
/* Module 4: Conditional jumps */
j = 1;
for (i = 1; i <= n4; i++)
{
if (j == 1)
{
j = 2;
}
else
{
j = 3;
}
if (j > 2)
{
j = 0;
}
else
{
j = 1;
}
if (j < 1)
{
j = 1;
}
else
{
j = 0;
}
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n4, j, j, x1, x2, x3, x4);
}
#endif
/* Module 5: Omitted
* Module 6: Integer arithmetic
*/
j = 1;
k = 2;
l = 3;
for (i = 1; i <= n6; i++)
{
j = j * (k - j) * (l - k);
k = l * k - (l - j) * k;
l = (l - k) * (k + j);
e1[l - 1] = j + k + l;
e1[k - 1] = j * k * l;
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n6, j, k, e1[1], e1[2], e1[3], e1[4]);
}
#endif
/* Module 7: Trigonometric functions */
x = 0.5;
y = 0.5;
for (i = 1; i <= n7; i++)
{
x = t * DATAN(t2 * DSIN(x) * DCOS(x) /
(DCOS(x + y) + DCOS(x - y) - 1.0));
y = t * DATAN(t2 * DSIN(y) * DCOS(y) /
(DCOS(x + y) + DCOS(x - y) - 1.0));
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n7, j, k, x, x, y, y);
}
#endif
/* Module 8: Procedure calls */
x = 1.0;
y = 1.0;
z = 1.0;
for (i = 1; i <= n8; i++)
{
p3(x, y, &z);
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n8, j, k, x, y, z, z);
}
#endif
/* Module 9: Array references */
j = 1;
k = 2;
l = 3;
e1[1] = 1.0;
e1[2] = 2.0;
e1[3] = 3.0;
for (i = 1; i <= n9; i++)
{
p0();
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n9, j, k, e1[1], e1[2], e1[3], e1[4]);
}
#endif
/* Module 10: Integer arithmetic */
j = 2;
k = 3;
for (i = 1; i <= n10; i++)
{
j = j + k;
k = j + k;
j = k - j;
k = k - j - j;
}
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n10, j, k, x1, x2, x3, x4);
}
#endif
/* Module 11: Standard functions */
x = 0.75;
for (i = 1; i <= n11; i++)
x = DSQRT(DEXP(DLOG(x) / t1));
#ifdef PRINTOUT
IF (jj == ii)
{
pout(n11, j, k, x, x, x, x);
}
#endif
/* THIS IS THE END OF THE MAJOR loop. */
if (++jj <= ii)
{
goto IILOOP;
}
/* Stop benchmark timing at this point. */
finisec = time(0);
/* Performance in Whetstone KIP's per second is given by
*
* (100*loop*ii)/TIME
*
* where TIME is in seconds.
*/
printf("\n");
if (finisec - startsec <= 0)
{
printf("Insufficient duration- Increase the loop count\n");
return 1;
}
printf("Loops: %ld, Iterations: %d, Duration: %ld sec.\n",
loop, ii, finisec - startsec);
KIPS = (100.0 * loop * ii) / (float)(finisec - startsec);
if (KIPS >= 1000.0)
{
printf("C Converted Double Precision Whetstones: %.1f MIPS\n",
KIPS / 1000.0);
}
else
{
printf("C Converted Double Precision Whetstones: %.1f KIPS\n", KIPS);
}
if (continuous)
{
goto LCONT;
}
return 0;
}
void
pa(double e[])
{
j = 0;
L10:
e[1] = (e[1] + e[2] + e[3] - e[4]) * t;
e[2] = (e[1] + e[2] - e[3] + e[4]) * t;
e[3] = (e[1] - e[2] + e[3] + e[4]) * t;
e[4] = (-e[1] + e[2] + e[3] + e[4]) / t2;
j += 1;
if (j < 6)
{
goto L10;
}
}
void
p0(void)
{
e1[j] = e1[k];
e1[k] = e1[l];
e1[l] = e1[j];
}
void p3(double x, double y, FAR double *z)
{
double x1;
double y1;
x1 = x;
y1 = y;
x1 = t * (x1 + y1);
y1 = t * (x1 + y1);
*z = (x1 + y1) / t2;
}
#ifdef PRINTOUT
void
pout(long n, long j, long k, double x1, double x2, double x3, double x4)
{
printf("%7ld %7ld %7ld %12.4e %12.4e %12.4e %12.4e\n",
n, j, k, x1, x2, x3, x4);
}
#endif