本帖最后由 kai迪皮 于 2023-10-18 17:20 编辑
#申请原创# @21小跑堂
1 前言
CoreMark,是业内认可度较高的衡量MCU性能的一个测试。它的测试分数在一定意义上衡量了该款MCU的性能优劣,也可以使得工程师在芯片选型时有一定的参考。
该测试代码使用C语言进行编写,涵盖列表、数学矩阵等运算操作,并没有与内核相关的操作,单纯是进行运算测试。
由于实现是C语言代码,不同的编译器及优化等级也会影响到该测试分数的最终呈现,刚刚好极海官方提供的APM32F411的demo包含了以下环境:
1. Keil MDK
2. IAR
3. Eclipse + gcc
我对CoreMark进行一个学习的同时,就上面的三个环境进行APM32F411的测试验证CoreMark。
2 CoreMark 的移植
我们先获取CoreMark的源码:
获取APM32F411的SDK:
2.1 移植思路
首先我们先总结一下CoreMark需要的一些底层驱动:
1. printf 重定向。
2. 系统时间的计时。
根据以上需求,结合手上的APM32F411 TINY 板我们需要初始化APM32F411的外设有:
1. USART1
2. 系统滴答时钟。
2.2 测试环境
我的测试目标是看不同编译器环境下的APM32F411的测试分数,那我们需要准备的测试环境有:
1. Keil MDK (AC5/AC6)
2. IAR
3. Eclipse +Gcc
环境的搭建步骤我这里就不赘述,相信我们的小伙伴都可以解决。这里也统一规定各个测试编译器的优化等级都为最高优化等级“-O3”。
2.3 添加源码
我们把CoreMark源码中的以下文件复制至APM32F411的SDK中的Middlewares文件夹里:
2.4 工程包含源码
我这里选取官方提供的Examples中的“SysTick”例程进行CoreMark源码的添加(我复制了一份SysTick并改名为了CoreMark)。由于不同的开发环境对源码的添加方式有些许的差异,我这里就不一一说明(水文)了。
Keil MDK的话就是像图中的添加方式:
2.5 添加头文件包含
由于不同的开发环境对源码的添加方式有些许的差异,我这里就不一一说明(水文)了。
Keil MDK的话就是像图中的添加方式:
2.6 修改例程源码
回过头来看我们的移植思路,首先我们确认一下我们复制的“SysTick”有没有以下要点:
1. printf 重定向。
2. 系统时间的计时。
哦吼,printf 重定向有了,但是系统时间的计时,例程中是用来计时延时的,并不能用来指示当前时间。我们需要简单修改一下。
我们定义一个时间计数变量,让它每进入一次滴答中断(进入中断的时间是1ms 一次),自加一次:
unsigned int system_tick = 0;
void SysTick_Init(void)
{
SystemCoreClock = RCM_ReadSYSCLKFreq();
/* SystemCoreClock / 1000 = 1ms */
if (SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while (1);
}
}
void system_tick_fun(void)
{
system_tick++;
}
与此同时我们也把当前的MCU及系统时钟信息也打印一下:
printf("\r\n");
printf("\r\n");
printf("******************************************\r\n");
printf("APM32F411 CoreMark \r\n");
printf("SystemCoreClock: %d Hz\r\n",SystemCoreClock);
printf("******************************************\r\n");
更重要的是由于CoreMark测试需要更大的堆栈空间,建议把堆栈空间改大至0x1000;
2.7 修改CoreMark源码
2.7.1 core_portme.h
这里我们需要重点修改一下core_portme.h文件:
1. 编译器定义:
/* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION
Initialize these strings per platform
*/
#ifndef COMPILER_VERSION
#ifdef __GNUC__
#define COMPILER_VERSION "GCC"__VERSION__
#elif defined (__ICCARM__)
#define COMPILER_VERSION "ICCARM"__VERSION__
#elif defined (__CC_ARM)
//#define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)"
#define COMPILER_VERSION "Armcc V5.06 update 6 (build 750)"
#endif
#endif
2. 代码优化等级
#ifndef COMPILER_FLAGS
#define COMPILER_FLAGS \
"-O3"
// FLAGS_STR /* "Please put compiler flags here (e.g. -o3)" */
#endif
3. 主测试函数的变量支持
#define MAIN_HAS_NOARGC 1
2.7.2 core_portme.c
接下来我们修改core_portme.c中对于时基相关的定义:
#define ITERATIONS 4000
extern unsigned int system_tick;
ITERATIONS是循环测试多少次CoreMark的相关测试,我这里设置是4000,需要注意的是不同的芯片该值是有差异的,如果你是移植至其他芯片,需要注意这里的取值。
#define NSECS_PER_SEC 1000//CLOCKS_PER_SEC
#define CORETIMETYPE clock_t
//#define GETMYTIME(_t) (*_t = clock())
#define GETMYTIME(_t) (*_t = system_tick)
然后是NSECS_PER_SEC,告诉系统我们的时基(1S)中有多少计数值,由于我的时基是1ms,所以这里设置是“1000”。
GETMYTIME(_t)是获取当前的计数值,这里直接返回我们在滴答定时器中的system_tick变量。
2.7.3 core_main.c
由于我们是已经有一个主函数了,需要在已有的主函数调用CoreMark测试主函数,我们这里修改一下CoreMark的主函数名字(core_main.c中):
#if MAIN_HAS_NOARGC
MAIN_RETURN_TYPE
CoreMark_main(void)
{
int argc = 0;
char *argv[1];
#else
MAIN_RETURN_TYPE
CoreMark_main(int argc, char *argv[])
{
由于测试的分数还有一个衡量,就是“CoreMark/MHz”分数。我们在测试分数输出的地方加入该测试分数的输出:
ee_printf("CoreMark 1.0 : %f / %s %s",
default_num_contexts * results[0].iterations
/ time_in_secs(total_time),
COMPILER_VERSION,
COMPILER_FLAGS);
ee_printf("\r\n");
extern unsigned int SystemCoreClock;
ee_printf("CoreMark/MHz 1.0 : %f / %s %s",
default_num_contexts * results[0].iterations / (SystemCoreClock/1000000)
/ time_in_secs(total_time),
COMPILER_VERSION,
COMPILER_FLAGS);
2.7.4 其他
由于我的串口助手是使用“\r\n”换行,我这里就把CoreMark测试代码里面的“\r”换行全部修改了。这里就不一一赘述。
2.8 设置优化等级
由于我们主要测试最高优化等级的CoreMark分数,我们需要吧各个编译器的优化等级进行调整:
1. Keil MDK
2. IAR
3. Eclipse + gcc
3 进行CoreMark测试
完成代码移植,编译无误后进行测试。
3.1 主频100Mhz
首先是主频100Mhz的测试:
1. Keil MDK AC5
2. Keil MDK AC6
3. IAR 8.5
4. Eclipse +gcc
3.2 主频120Mhz
然后是主频120MHz的测试:
1. Keil MDK AC5
2. Keil MDK AC6
3. IAR 8.5
4. Eclipse +gcc
4 数据总结
经测试汇总,不同主频及编译器情况下CoreMark测试汇总画出折线图。
通过以上数据我们发现:
1. 在相同情况下.AC6编译器的效率是最好的(PS,难怪Keil 不维护 AC5了,(*/ω\*))。
2. 芯片主频提升后,CoreMark分数整体上升但是CoreMark/MHz的分数不一定上升。这个时候如果考虑功耗(主频越高功耗肯定随之上升)等多方面,芯片是否使用高主频去工作得再三思虑。
这里是参考代码
APM32F4xx_SDK_V1.4_CoreMark.zip
(1.23 MB)
。
|
@21小跑堂 :感谢支持,Thanks♪(・ω・)ノ
从MCU主频方向和AC6与AC5对比方向进行***测试,严谨细致,不再是单向测试,值得肯定。