本帖最后由 252669569 于 2016-8-22 01:43 编辑
这里使用三块NUCLEO板子进行测试,分别是NUCLEO-F401RE,NUCLEO-F411RE,NUCLEO-F767ZI,选择两块F4芯片,主要是探讨相同框架下频率对于运算速度的影响,401和411的框架和DMIPS/MHz是相同的,F7由于架构的改变,速度的提升是更加显著的。 实物图: 芯片参数对比: 实验步骤: F7: 在官方STM32Cube_FW_F7固件STM32F767ZI-NucleoàExamplesàUART例程,使用KEIL5打开,打开Manage Run-time Environment,勾选DSP,如下图所示: 这个时候会发现在Project中多了一个CMSIS,里面的库文件是arm_cortexM7lfsp_math.lib,相关的库文件区别如下: 在Drivers\CMSIS\Lib\ARM下:
- arm_cortexM7lfdp_math.lib (Little endian and Double Precision Floating Point Unit on Cortex-M7)
- arm_cortexM7lfsp_math.lib (Little endian and Single Precision Floating Point Unit on Cortex-M7)
- arm_cortexM7l_math.lib (Little endian on Cortex-M7)
- arm_cortexM4lf_math.lib (Little endian and Floating Point Unit on Cortex-M4)
- arm_cortexM4l_math.lib (Little endian on Cortex-M4)
也就是说调用的库是单精度浮点运算的,无法使用双精度浮点运算。解决办法是在Option的Device中选择另外一种芯片然后再选回来就可以了,具体可以参考这篇帖子:STM32F767ZI如何开启双精度浮点运算:bbs.21ic.com/icview-1622220-1-1.html 然后在OptionàC/C++的Define中添加ARM_MATH_CM7,__FPU_PRESENTF4。 开启FPU的方法是在Option—>TargetàCode GenerationàFloatingPoint Hardware后面的下拉菜单中可以选择NotUsed,Use SinglePrecision, Use Double Precision。这是选择是否使用浮点运算器,是单精度还是双精度的。 由MATLAB随机生成32个浮点数,为了结果更加准确分别对这32个数字进行10000次乘法运算和1000次三角函数运算,测试的项目包括,整形运算,单精度浮点运算,DSP库单精度浮点运算,双精度浮点运算,三角函数运算,DSP库三角函数运算,通过Floating Point Hardware的选项来切换使用的浮点运算库。 测试主要程序: 测试数据: #define MAX_BLOCKSIZE 32//测试数据个数
//单精度浮点测试数据
float32_t testInput_f32[MAX_BLOCKSIZE] =
{
-1.244916875853235400f, -4.793533929171324800f, 0.360705030233248850f, 0.827929644170887320f, -3.299532218312426900f, 3.427441903227623800f, 3.422401784294607700f, -0.108308165334010680f,
0.941943896490312180f, 0.502609575000365850f, -0.537345278736373500f, 2.088817392965764500f, -1.693168684143455700f, 6.283185307179590700f, -0.392545884746175080f, 0.327893095115825040f,
3.070147440456292300f, 0.170611405884662230f, -0.275275082396073010f, -2.395492805446796300f, 0.847311163536506600f, -3.845517018083148800f, 2.055818378415868300f, 4.672594161978930800f,
-1.990923030266425800f, 2.469305197656249500f, 3.609002606064021000f, -4.586736582331667500f, -4.147080139136136300f, 1.643756718868359500f, -1.150866392366494800f, 1.985805026477433800f
};
//双精度浮点测试数据
float64_t testInput_f64[MAX_BLOCKSIZE] =
{
-1.244916875853235400, -4.793533929171324800, 0.360705030233248850, 0.827929644170887320, -3.299532218312426900, 3.427441903227623800, 3.422401784294607700f, -0.108308165334010680,
0.941943896490312180, 0.502609575000365850, -0.537345278736373500, 2.088817392965764500, -1.693168684143455700, 6.283185307179590700, -0.392545884746175080f, 0.327893095115825040,
3.070147440456292300, 0.170611405884662230, -0.275275082396073010, -2.395492805446796300, 0.847311163536506600, -3.845517018083148800, 2.055818378415868300f, 4.672594161978930800,
-1.990923030266425800, 2.469305197656249500, 3.609002606064021000, -4.586736582331667500, -4.147080139136136300, 1.643756718868359500, -1.150866392366494800f, 1.985805026477433800
};
//32位整形测试数据
int32_t testInput_q32[MAX_BLOCKSIZE] =
{
244916875, 171324800, 33248850, 70887320, 83124269, 27623800, 94607700, 4010680,
240312180, 500365850, 36373500, 965764500, 143455700, 79590700, 46175080, 278930951,
56292300, 884662230, 39607010, 446796300, 65066009, 83148808, 868300111, 78930800,
266425800, 6249500, 64021000, 586736582, 36136300, 868359500, 664948001, 77433800
};
测试函数: while (1)
{
//1000次sincos运算不使用DSP库耗时
tickstart=HAL_GetTick();
for(int j=0;j<1000;j++){
for(int i=0; i< blockSize; i++)
{
cosOutput = cos(testInput_f32[i]);
sinOutput = sin(testInput_f32[i]);
}
}
tick_sincos=HAL_GetTick()-tickstart;
//1000次sincos运算使用DSP库耗时
tickstart=HAL_GetTick();
for(int j=0;j<1000;j++){
for(int i=0; i< blockSize; i++)
{
cosOutput = arm_cos_f32(testInput_f32[i]);
sinOutput = arm_sin_f32(testInput_f32[i]);
}
}
tick_sincos_dsp=HAL_GetTick()-tickstart;
//10000次32位数据相乘运算耗时
tickstart=HAL_GetTick();
for(int j=0;j<10000;j++){
for(int i=0; i< blockSize; i++)
{
Output_q32 = testInput_q32[i]*testInput_q32[i];
}
}
tick_mult_q32=HAL_GetTick()-tickstart;
//10000次单精度数据相乘运算耗时
tickstart=HAL_GetTick();
for(int j=0;j<10000;j++){
for(int i=0; i< blockSize; i++)
{
Output_f32 = testInput_f32[i]*testInput_f32[i];
}
}
tick_mult_f32=HAL_GetTick()-tickstart;
//10000次双精度数据相乘运算耗时
tickstart=HAL_GetTick();
for(int j=0;j<10000;j++){
for(int i=0; i< blockSize; i++)
{
Output_f64 = testInput_f64[i]*testInput_f64[i];
}
}
tick_mult_f64=HAL_GetTick()-tickstart;
//10000次单精度数据相乘运算使用DSP库耗时
tickstart=HAL_GetTick();
for(int j=0;j<10000;j++){
arm_mult_f32(&testInput_f32[0], &testInput_f32[0], &Output_f32_A[0], blockSize);
}
tick_mult_f32_dsp=HAL_GetTick()-tickstart;
//10000次for循环耗时
tickstart=HAL_GetTick();
for(int j=0;j<10000;j++){
}
tickfor=HAL_GetTick()-tickstart;
//输出测试结果
printf("tick_sincos=%d,tick_sincos_dsp=%d,tick_mult_q32=%d,tick_mult_f32=%d,tick_mult_f64=%d,tick_mult_f32_dsp=%d\n\r",tick_sincos,tick_sincos_dsp,tick_mult_q32,tick_mult_f32,tick_mult_f64,tick_mult_f32_dsp);
}
完整函数和使用方法请见帖子最下方github链接。 F4: 两款F4芯片的实验步骤与F7类似,使用官方的M4库选择对应芯片的UART例程,OptionàC/C++的Define中添加ARM_MATH_CM4就可以了。 最后将串口输出数值记录下来。 实验结果: 注:尾缀null代表浮点运算器选择Not Used,尾缀sf代表Use Single Precision,尾缀df代表Use DoublePrecision,表中的数据代表耗时,单位ms。 结论: 1. 相同框架的F4芯片,所有类型(整形,浮点,DSP库)的运算速度与芯片的频率成正比 2. F4芯片使用单精度浮点运算器,在单精度浮点的运算上比不使用的提高5倍以上,对双精度没有影响,DSP库三角函数速度调高9倍以上,DSP的单精度浮点运算有提高明显,不过相对于直接使用并没有太大的提升,不知道在大量数据的情况下会不会有所改善。 3. F7芯片使用单精度浮点运算器,在单精度浮点的运算上比不使用的提高7倍以上,对双精度没有影响,DSP库三角函数速度调高6倍以上,DSP的单精度浮点运算有提高明显,不过相对于直接使用并没有太大的提升 4. F7芯片使用双精度浮点运算器,在双精度浮点的运算上比不使用的提高11倍以上,对单精度没有影响,三角函数的运算提高10倍以上。 5. 可以推测出,如果M4芯片的处理速度也达到216M,开启FPU,那么相同频率下的M7在32位整数相乘上速度是M4的1.8倍,单精度浮点:2.1倍,单精度DSP:2.2倍,双精度:19.6倍,三角函数:16倍,DSP三角函数不变。 以上测试方法并不是十分专业,欢迎拍砖,测试所有的代码均放到github托管: github.com/flyloong/STM32F7_F4_Performance_test
欢迎重复测试,提出异议。
|