打印
[应用相关]

程序的位置与运行时间有关

[复制链接]
511|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一、概述
  在我测量mian函数大循环的周期时,发生了怪事:我一点也没有更改main函数的代码,只在初始化时添加了一些无用的语句,结果测量时间发生了巨大的差异。

使用特权

评论回复
沙发
characteristic|  楼主 | 2019-7-22 15:22 | 只看该作者
二、事件详情

1、测试代码

main函数
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{        
        LED_GPIO_Config();      
        /* USART1 config 115200 8-N-1 */
        USART1_Config();

     /**
      * @brief  通过注释掉程序,可以更改代码的长度
      * @param  当注释的只剩下一个赋值等式的时候,计时长度值是0x116638
      * @retval 当注释的剩下三个赋值等式的时候,计时长度值是0xEA726
      */
        DMA_USART1_Config();
        
        NVIC_Configuration();
        SysTick_Init();     
        SysTick_Time_Init(&UseDMATime);
        for(;;)
        {     
            SysTick_Time_Start();
            LED1(ON);LED2(OFF);LED3(OFF);
            Delay();
            LED1(OFF);LED2(ON);LED3(OFF);
            Delay();
            LED1(OFF);LED2(OFF);LED3(ON);
            Delay();
            SysTick_Time_Stop();
        }
}


Delay函数
static void Delay(void)     //简单的延时函数
{     
   
        uint16_t i;
        
        /*填充将要发送的数据*/
        for(i = 0;i < SENDBUFF_SIZE ; i++)
        {
            SendBuff[i]     = (uint8_t)i;
        }
   
}

使用特权

评论回复
板凳
characteristic|  楼主 | 2019-7-22 15:23 | 只看该作者
说明:

(1)测量代码段
            LED1(ON);LED2(OFF);LED3(OFF);
            Delay();
            LED1(OFF);LED2(ON);LED3(OFF);
            Delay();
            LED1(OFF);LED2(OFF);LED3(ON);
            Delay();


(2)无效代码段

  之所以称之为无效,实际上指的是“这些代码在程序中起到的是很次要的作用,主要是给CPU一些空指令,当然也会起到改变代码量的作用”。
LED_GPIO_Config();      
        /* USART1 config 115200 8-N-1 */
        USART1_Config();

     /**
      * @brief  通过注释掉程序,可以更改代码的长度
      * @param  当注释的只剩下一个赋值等式的时候,计时长度值是0x116638
      * @retval 当注释的剩下三个赋值等式的时候,计时长度值是0xEA726
      */
        DMA_USART1_Config();



(3)与测量计时有关的代码
SysTick_Init();     
SysTick_Time_Init(&UseDMATime);
SysTick_Time_Start();
SysTick_Time_Stop();


关于测量计时代码的实现在随笔STM32之系统滴答定时器中进行了详细讲解。

使用特权

评论回复
地板
characteristic|  楼主 | 2019-7-22 15:24 | 只看该作者
2、奇怪现象

  DMA_USART1_Config是在大循环之前调用的一个无用的函数,实际上可以称之为空函数或者延时函数。通过注释掉里边的语句可以改变排在DMA_USART1_Config代码段之后代码在Flash上的位置,也可以改变整个代码段的量(尽管很小)。
void DMA_USART1_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;   

        /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/   
        DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
        
        /*外设地址不增*/        
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;


}


笔者发现,当这个函数完全保留三行语句的时候,while循环测出来的滴答计时器脉冲数是0xEA726(0d960294);而当注释掉只剩下一行语句时,脉冲数变为0x116638(0d1140280)。这中间的差距是0d179986,占0xEA726的百分比是18.7%。也就是说注释语句后的代码执行时间,比没有注释时的时间多了将近1/5,这值得考虑其中的原因。

使用特权

评论回复
5
characteristic|  楼主 | 2019-7-22 15:25 | 只看该作者
三、分析与结论

1、分析

     测量代码段中有关LED操作的代码执行时间几乎可以忽略,而占主要运行时间的是Delay函数,只要分析Delay函数,就能找到其中的问题。

Delay函数
static void Delay(void)     //简单的延时函数
{     
   
        uint16_t i;
        
        /*填充将要发送的数据*/
        for(i = 0;i < SENDBUFF_SIZE ; i++)
        {
            SendBuff[i]     = (uint8_t)i;
        }
   
}


Delay函数在两种情况下的反汇编代码

在完全保留代码的情况下


在注释掉部分代码的情况下


可以看到Delay函数的反汇编代码内容没有改变,改变的只是代码在Flash中的位置(当然也是程序执行时的位置)。       而后,我有试着在
DMA_USART1_Config代码的基础(3行语句)上不断增加代码,发现计时脉冲数周期性的在0xEA726、0x116638两个中变换。

       由此可以确定,就是由于代码的位置改变了程序的运行时间,也即改变了程序的运行速度。

使用特权

评论回复
6
characteristic|  楼主 | 2019-7-22 15:25 | 只看该作者
2、结论

  即使是同样的代码,通过改变代码的位置可以改变代码的运行时间。而最根本的原因是有些指令的周期给指令所在的Flash中的位置有关。

使用特权

评论回复
7
characteristic|  楼主 | 2019-7-22 15:26 | 只看该作者
3、还未完成的工作

  但是,由于J-link硬件调试时,单步调试误差太大,取得的值很有出入,难以确定究竟是Delay函数中哪些指令引起时间偏差。

使用特权

评论回复
8
wowu| | 2019-8-12 11:49 | 只看该作者

非常感谢楼主分享

使用特权

评论回复
9
xiaoqizi| | 2019-8-12 12:01 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
10
木木guainv| | 2019-8-12 12:05 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
11
磨砂| | 2019-8-12 14:00 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
12
晓伍| | 2019-8-12 14:02 | 只看该作者
非常感谢楼主分享

使用特权

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

本版积分规则

18

主题

367

帖子

1

粉丝