打印
[活动专区]

【AT-START-F405测评】Whetstone浮点性能测试与软硬浮点性能差别

[复制链接]
1258|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 xhackerustc 于 2024-5-10 00:17 编辑

#申请原创# @21小跑堂

whetstone benchmark简介

whetsone是一个浮点性能测试工具,主要用来测量cpu浮点运算性能的,使用了不少c库的math函数比如sin、cos、sqrt、exp和log,也有纯粹的浮点四则计算,也有分支测试和函数调用,所以也有部分整数运算,但重点应该集中在浮点上。测试结果的单位是KWIPS或MWIPS,越大越好。大家常用的源码版本来自https://netlib.org/benchmark/whetstone.c 或者https://github.com/kdlucas/byte-unixbench/blob/master/UnixBench/src/whets.c。来自unixbench的版本用得多一些,而且有pc、server和各种SBC数据做参考,所以笔者选择unixbench版本

测试工程的准备
whetstone依赖两部分:printf打印和计时,笔者使用cmake模板开发环境,这两部分都验证过,可参见笔者第一篇测评贴,这里不再赘述,只讲改动部分。

因为要计时,所以选择example中的用到systick的例子即project/at_start_f405/examples/cortex_m4/systick_interrupt,把这个目录复制一份到新目录project/at_start_f405/examples/whetstone/。再把从unixbench下载的whets.c拷贝到project/at_start_f405/examples/whetstone/src

修改project/at_start_f405/examples/whetstone/src/main.c中的systick_handler函数如下:
volatile uint32_t ticks;
void systick_handler(void)
{
  ticks ++;
}
修改main函数如下:
extern int whets_main(int argc, char *argv[]);
int main(void)
{
  system_clock_config();

  /* config systick clock source */
  systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV);

  /* config systick reload value and enable interrupt */
  systick_interrupt_config(MS_TICK);

  uart_print_init(115200);

  while(ticks < 2000);

  whets_main(1, NULL);

  for(;;)
          __WFI();
}
在whets.c中加一行宏定义:
#define UNIXBENCH
注意:cortex-m4仅支持单精度浮点,所以不要定义DP这个宏,当然我们下面可以改代码测试double运算性能。

whets.c中加入dtime的实现:
extern volatile unsigned int ticks;
SPDP dtime()
{
    return (float)ticks / 1000;
}


whets.c中把main改成whets_main。

修改CMakeLists.txt(原始CMakeLists.txt在第一篇测试帖中)如下:
<blockquote>diff --git a/CMakeLists.txt b/CMakeLists.txt


编译过程中会发现很多即使只用单浮点,gcc会报很多double-promotion的警告,说明这个whetstone的没完全做好单浮点修改,我们需要修改代码修正除printf处其余所有double-promotion警告,否则测试得到的浮点性能数据不准确,因为cortex-m4仅支持单浮点,double需要sw模拟。笔者的源码改动如下
@@ -392,9 +392,9 @@
     count--;

#ifndef UNIXBENCH
-    if (TimeUsed > 2.0)
+    if (TimeUsed > 2.0f)
#else
-    if (TimeUsed > 0.5)
+    if (TimeUsed > 0.5f)
#endif
       {
        count = 0;
@@ -619,7 +619,7 @@
                      e1[2] = (e1[0] - e1[1] + e1[2] + e1[3]) * t;
                      e1[3] = (-e1[0] + e1[1] + e1[2] + e1[3]) * t;
                  }
-               t = 1.0 - t;
+               t = 1.0f - t;
              }
            t =  t0;
         }
@@ -637,7 +637,7 @@
                  {
                     pa(e1,t,t2);
                  }
-               t = 1.0 - t;
+               t = 1.0f - t;
              }
            t =  t0;
         }
@@ -698,10 +698,10 @@
              {
                for(i=1; i<n5; i++)
                  {
-                    x = t*atan(t2*sin(x)*cos(x)/(cos(x+y)+cos(x-y)-1.0));
-                    y = t*atan(t2*sin(y)*cos(y)/(cos(x+y)+cos(x-y)-1.0));
+                    x = t*atanf(t2*sinf(x)*cosf(x)/(cosf(x+y)+cosf(x-y)-1.0f));
+                    y = t*atanf(t2*sinf(y)*cosf(y)/(cosf(x+y)+cosf(x-y)-1.0f));
                  }
-               t = 1.0 - t;
+               t = 1.0f - t;
              }
            t = t0;
         }
@@ -756,7 +756,7 @@
              {
                for(i=0; i<n8; i++)
                  {
-                    x = sqrt(exp(log(x)/t1));
+                    x = sqrtf(expf(logf(x)/t1));
                  }
              }
         }


编译&烧录

mkdir build
cd build
cmake ..
make



测试结果

由此可以得到at32f405的whetstone性能数据为234.666MWIPS,作为对比笔者一台i5-2520M老旧笔记本的whetstone性能数据为4927.64MWIPS。

强制只用软浮点看看软件模拟的性能如何
阅读libraries/cmsis/cm4/device_support/system_at32f402_405.c的SystemInit()函数发现如下这两行代码:
#if defined (__FPU_USED) && (__FPU_USED == 1U)
  SCB->CPACR |= ((3U << 10U * 2U) |         /* set cp10 full access */
                          (3U << 11U * 2U)  );       /* set cp11 full access */
#endif
对于CPACR这个寄存器参考cortex-m4的TRM,简单说就是如果__FPU_USED宏未定义或定义为0,那么cortex-m4浮点就不会开启了。我们看看__FPU_USED的定义libraries/cmsis/cm4/core_support/core_cm4.h,笔者toolchain是gcc所以走如下代码:
#elif defined ( __GNUC__ )
  #if defined (__VFP_FP__) && !defined(__SOFTFP__)
    #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)
      #define __FPU_USED       1U
    #else
      #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)"
      #define __FPU_USED       0U
    #endif
  #else
    #define __FPU_USED         0U
  #endif
而__VFP_FP__宏应该来自gcc,选不同的float abi,会决定__VFP_FP__宏定义与否。综上只需修改CFLAGS从-mfloat-abi=hard变成-mfloat-abi=soft即可。

软件模拟浮点测试结果:

结果表明:单精度硬浮点性能大概是单精度软浮点的11倍。

如果反汇编生成elf文件也会发现很多的__eabi_xxx函数调用,这是软件模拟浮点运算用的。

mfloat-abi=hard + 双精度浮点性能如何
用原始下载的whets.c文件,只用加两行宏定义:
#define UNIXBENCH

/*PRECISION PRECISION PRECISION PRECISION PRECISION PRECISION PRECISION*/

#define DP
测试截图:

cortex-m4仅支持单精度浮点,开启其硬浮点对双精度浮点无帮助(下面的测试可以证明此猜想),双精度浮点性能是很弱的。单精度硬浮点性能是双精度浮点的21倍


mfloat-abi=soft + 双精度浮点性能如何

开启cortex-m4的硬浮点与否,基本不影响双精度浮点性能,因为都是软件模拟的。

总结
0.本文首创在裸机环境中bring up whetstone benchmark,并在AT32F405平台上做了测试
1.就whetsone测试工具而言,cortex-m4单精度硬浮点的性能可达到单精度软浮点的11倍左右;
2.开启cortex-m4硬浮点,对双精度浮点运算没啥帮助;
3.就whetsone测试工具而言,cortex-m4单精度硬浮点的性能可达双精度浮点的21倍左右

综上cortex-m4的应尽可能使用单精度硬浮点。





使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

68

帖子

0

粉丝