【GD32E503评测】——04.MCU CoreMark性能测试
[复制链接]
本帖最后由 xld0932 于 2021-2-14 21:46 编辑
CoreMark是用来衡量嵌入式系统中中心处理单元(CPU,或叫做微控制器MCU)性能的标准。该标准于2009年由EEMBC组织的Shay Gla-On提出,并且试图将其发展成为工业标准,从而代替陈旧的Dhrystone标准。代码使用C语言写成,包含如下的运算法则:列举(寻找并排序),数学矩阵操作(普通矩阵运算)和状态机(用来确定输入流中是否包含有效数字),最后还包括CRC(循环冗余校验)。
为什么不用Dhrystone,而用CoreMark呢?Dhrystone是测量处理器运算能力的最常见基准程序之一,常用于处理器的整型运算性能的测量。程序是用C语言编写的,因此C编译器的编译效率对测试结果也有很大影响,所以Dhrystone还有许多漏洞,比如易被非法利用、人为痕迹明显、代码长度太短、缺乏验证及标准的运行规则等。
一、准备工作
1.1.到CoreMark官网上去下载开源的源代码:https://www.eembc.org/coremark/index.php(点击网页上的Download,然后跳转到GitHub上下载源代码)
1.2.在下载的CoreMark源码中,我们只使用到了simple中的port接口适配文件和根目录下的源文件
1.3.基础工程是基于上篇文章的代码上进行添加的;
二、移植CoreMark
2.1.将CoreMark源代码添加到项目工程,如下图所示
2.2.将工程的Optimization配置到O3级别,添加CoreMark的头文件路径,如下图所示:
2.3.修改原先的main函数,因为CoreMark代码自带一个main入口函数,所以需要屏蔽之前我们自己写的main函数,如所示:
/*******************************************************************************
* @brief * @param
* @retval
* @attention *******************************************************************************/
int user_main(void)
{
InitSystem();
while(1)
{
TASK_Scheduling();
MCU_DAC_OutputHandler();
}
}
2.4.修改SysTick_Handler函数,用于CoreMark运算过程中的计时处理,如所示:
/*!
\brief this function handles SysTick exception
\param[in] none
\param[out] none
\retval none
*/
void SysTick_Handler(void)
{
#if 0
SysTick_Tick++;
TASK_TimeSlice(SysTick_Tick);
#else
CoreMark_IncTick();
#endif
}
2.5.在core_portme.c文件中添加移植的代码,如下所示:
/**
* Copyright 2018 Embedded Microprocessor Benchmark Consortium (EEMBC)
*
* Licensed 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.
*
* Original Author: Shay Gal-on
*/
/* Includes ------------------------------------------------------------------*/
#include "config.h"
#include "coremark.h"
/* Private defines ----------------------------------------------------------*/
#define ITERATIONS 6000
/* Private variables --------------------------------------------------------*/
volatile uint8_t stop_time_flg = 1;
/* Exported function prototypes ---------------------------------------------*/
extern void InitSystem(void);
#if VALIDATION_RUN
volatile ee_s32 seed1_volatile = 0x3415;
volatile ee_s32 seed2_volatile = 0x3415;
volatile ee_s32 seed3_volatile = 0x66;
#endif
#if PERFORMANCE_RUN
volatile ee_s32 seed1_volatile = 0x0;
volatile ee_s32 seed2_volatile = 0x0;
volatile ee_s32 seed3_volatile = 0x66;
#endif
#if PROFILE_RUN
volatile ee_s32 seed1_volatile = 0x8;
volatile ee_s32 seed2_volatile = 0x8;
volatile ee_s32 seed3_volatile = 0x8;
#endif
volatile ee_s32 seed4_volatile = ITERATIONS;
volatile ee_s32 seed5_volatile = 0x0;
/**
* Porting : Timing functions
* How to capture time and convert to seconds must be ported to whatever is supported by the platform.
* e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc.
* Sample implementation for standard time.h and windows.h definitions included.
*/
/**
* Define : TIMER_RES_DIVIDER
* Divider to trade off timer resolution and total time that can be measured.
*
* Use lower values to increase resolution, but make sure that overflow does not occur.
* If there are issues with the return value overflowing, increase this value.
*/
#define NSECS_PER_SEC 1000
#define CORETIMETYPE clock_t
#define MYTIMEDIFF(fin,ini) ((fin)-(ini))
#define TIMER_RES_DIVIDER 1
#define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER)
/**
* Define Host specific (POSIX), or target specific global time variables.
*/
static CORETIMETYPE start_time_val = 0, stop_time_val = 0;
/**
* Function : start_time
* This function will be called right before starting the timed portion of the benchmark.
*
* Implementation may be capturing a system timer (as implemented in the example code)
* or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0.
*/
void start_time(void)
{
stop_time_flg = 0;
stop_time_val = 0;
}
/**
* Function : stop_time
* This function will be called right after ending the timed portion of the benchmark.
*
* Implementation may be capturing a system timer (as implemented in the example code)
* or other system parameters - e.g. reading the current value of cpu cycles counter.
*/
void stop_time(void)
{
stop_time_flg = 1;
}
/**
* Function : get_time
* Return an abstract "ticks" number that signifies time on the system.
*
* Actual value returned may be cpu cycles, milliseconds or any other value,
* as long as it can be converted to seconds by <time_in_secs>.
* This methodology is taken to accomodate any hardware or simulated platform.
* The sample implementation returns millisecs by default,
* and the resolution is controlled by <TIMER_RES_DIVIDER>
*/
CORE_TICKS get_time(void)
{
CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val));
return elapsed;
}
/**
* Function : time_in_secs
* Convert the value returned by get_time to seconds.
*
* The <secs_ret> type is used to accomodate systems with no support for floating point.
* Default implementation implemented by the EE_TICKS_PER_SEC macro above.
*/
secs_ret time_in_secs(CORE_TICKS ticks)
{
secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC;
return retval;
}
ee_u32 default_num_contexts = 1;
/**
* Function : portable_init
* Target specific initialization code
* Test for some common mistakes.
*/
void portable_init(core_portable *p, int *argc, char *argv[])
{
InitSystem();
if (sizeof(ee_ptr_int) != sizeof(ee_u8 *))
{
ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n");
}
if (sizeof(ee_u32) != 4)
{
ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n");
}
p->portable_id=1;
}
/**
* Function : portable_fini
* Target specific final code
*/
void portable_fini(core_portable *p)
{
p->portable_id=0;
}
/**
* @brief : time.h
* @param :
* @returns:
* @details:
*/
void CoreMark_IncTick(void)
{
if(stop_time_flg == 0) stop_time_val++;
}
/************************ (C) COPYRIGHT ************************END OF FILE****/
三、运行调试
将程序都移植完成后,对项目工程进行编译,编译无误后下载到开发板进行运行测试;
在第一次下载运行后,串口就输出“ERROR! Must execute for at least 10 secs for a valid result!”的错误提示,如下图所示:
执行的时间小于了10秒钟,我们修改了core_portme.c中的ITERATIONS这个宏定义值,将原先的2500修改到6000,再次尝试运行时,程序运行正常,测试结果如下所示:
从上图我们可以看到CoreMark的测试结果值为576.6,当然这是基于上一个工程的基础上做的一个移植,程序运行还有可优化的空间,后面再继续研究!
四、源代码
Project_CoreMark.zip
(438.96 KB, 下载次数: 5)
|