一种简单、实用的测量程序运行时间的方法

前言

平时我们可能很少去关注程序运行的时间,但是在一些情况下可能需要对程序进行一个整体的复盘、优化。

那么,程序运行的时间就是一个可以考虑的方面,可以测一下某些代码块、函数、算法的运行时间,然后整体考虑看看有没有必要进行优化。

之前在某工控类项目中,我就有接到一个任务去测试程序中关键代码的执行时间,并输出报告。当时是使用一个GPIO+示波器进行测试的,也可以使用逻辑分析仪来测。

当时测量的方法很简单:

在要测试的代码块/函数之前设置该GPIO的电平为高电平,在要测试的代码块/函数之后设置该GPIO为低电平,使用示波器测高电平的时间,就知道了这一代码块/函数的运行时间。

下面就通过实例来介绍一下这种简单而有效的方法。

我这里使用逻辑分析仪来测量,使用小熊派开发板来验证,小熊派的主控为STM32L431RCT6,系统时钟设置为80MHz

这里顺带提一点题外话,之前有一些初学的读者朋友问我说逻辑分析仪贵不贵。逻辑分析仪有贵的也有便宜的,贵则上千上万元,便宜则有几十、几百。我觉得无论工作、还是学习,都有必要入手一个逻辑分析仪。

本篇笔记的测试用的逻辑分析仪就是某宝上二十几块钱买的,可以满足平时的学习所用。条件有限的学生朋友可以入手。有条件的可以考虑入手几百块钱的。

GPIO+逻辑分析仪测时间

1、测量HAL_Delay函数

STM32的HAL库有给我们提供一个HAL_Delay延时函数,这是一个ms级延时函数。这个延时函数依赖于系统滴答定时器,所以是一个比较精确的延时函数。

这里,我们就使用GPIO+逻辑分析仪的方法来测量一下这个延时函数。为了方便测试,我们在while死循环里进行测量。

代码:

测量结果:

可见,我们通过逻辑分析仪测出了HAL_Delay(100);运行的时间为100.4315ms,符合我们的预期。

这里高电平两侧其实就是低电平部分,只不过低电平持续的时间太短了,在这里看起来像一条竖线,我们放大来看看:

结果已经很准了,可以满足平时的测量。这种测量很难保证百分之百的精确,小数点后面的那一部分可能是受很多不可控因素的影响,这不在我们本篇文章的讨论范围之内。

我们是想通过这个示例来介绍这种测量方法的使用及证明这种方法是可行的。下面再继续看两个实例。

2、测量软件延时函数

我们以前刚开始学单片机的时候,经常有用到一些粗略的延时函数,其实现方法就是循环执行n条空语句,以达到一个延时的效果。

那么,我们怎么来构造一个us级或ms级的粗略延时函数(软件延时函数)。我们之前看到的粗略延时函数类似这样子:

这些函数里面需要给出一些循环的次数,这个值是怎么来确定的呢?比如上面这个函数中123这个值是怎么来确定的?我们可以使用GPIO+逻辑分析仪的方法来进行一个简单的确定。

确定1us:

不同的处理器,结果是不一样的。针对小熊派开发板(主控:STM32L431RCT6),循环运行15条空语句的时间实测结果是1.083us,这算是比较接近1us了。

我们就运用这个结果来构建一个us级软件延时函数如下:

接下来我们测一下soft_delay_us(100);实际运行了多长时间:

可见,结果差不多接近我们想要的结果。构建这样的粗略延时函数可以使用这样的方式来确定一些循环次数的值。

3、查表法VS常规法运行时间

在之前的文章:空间换时间,查表法的经典例子《空间换时间,查表法的经典例子》中,我们有说可以适当使用查表法降低程序的执行时间。这里我们来实际测量对比一下那篇文章中查表法与常规法的优劣。

关键代码:

/* 测试结果 */
struct test_res
{unsigned int data;  /* 数据          */unsigned int count; /* 数据中1的个数 */
};/* ============常规法============ */
#if 1
struct test_res get_test_res(unsigned int data)
{/* 保存测试结果 */struct test_res res;/* 保证数据总会在0~0xf之间 */// unsigned int temp = data & 0xf;  unsigned int temp = data & 0xff;  res.count = 0;res.data = temp;/* 循环判断每一位 */for (int i = 0; i < 16; i++){if (temp & 0x01){res.count++;}temp >>= 1;}return res;
}
#else
/* ============查表法============ */int table[16] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};struct test_res get_test_res(unsigned int data)
{/* 保存测试结果 */struct test_res res;/* 保证数据总会在0~0xf之间 */unsigned int temp = data & 0xff;  /* 获取低4位中1的个数 */unsigned int low_data = temp & 0xf;unsigned int low_cnt = table[low_data];/* 获取高4位中1的个数 */unsigned int high_data = (temp >> 4) & 0xf;unsigned int high_cnt = table[high_data];/* 结果 */res.count = low_cnt + high_cnt;res.data = temp;return res;
}int main(void)
{/* USER CODE BEGIN 1 */struct test_res res = {0};/* 省略部分代码。。。。。。。。。 */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);res = get_test_res(30);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);}/* USER CODE END 3 */
}
#endif

常规法程序的运行时间:

查表法程序的运行时间:

可见,这个例子中常规法程序运行时间约为2ns,而查表法程序运行时间约为500ns。查表法的程序运行之间仅为常规法的1/4,省下了3/4的时间。

随着调用次数的增多,这里的查表法的优势越大。比如循环计算0~31这32个数中每一个数二进制位为1的个数,则相关代码改为:

  int i;while (1){HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);for (i = 0; i < 32; i++){res = get_test_res(i);}HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);}

常规法:

查表法:

可见,随着调用次数的增多,查表法相对于常规法更省时,即查表法的优势越大。

以上就是关于GPIO+逻辑分析仪测程序运行时间的几个实例。下面顺带提一下使用MDK+ST-LINK测STM32程序运行时间的方法。

MDK+ST-LINK测时间

在使用MDK作为开发工具时,可以搭配一些仿真器来查看程序执行时间。这里通过实例来介绍MDK+ST-LINK测STM32程序运行时间的方法。

这里重点是设置Trace里面的系统内核时钟,我们这里使用的是小熊派开发板(主控:STM32L431RCT6),并且配置的系统时钟是80MHz:

所以在Trace中要设置为80MHz。这个得根据实际芯片的型号就需要根据进行修改,比如STM32F103系列默认是72MHz,STM32F429系列默认为180MHz等,根据实际进行修改。

下面我们通过在线调试、打断点的方式看一下 HAL_Delay(1000);运行了多长时间:

可见程序运行到HAL_Delay(1000);前后的时间分别为:

前:0.00008964s
后:1.00108161s

HAL_Delay(1000);走过的时间约为1s,符合预期。

最后

以上就是本次的实践分享,感谢阅读与支持。如有错误,欢迎指出。谢谢!

若觉得文章不错,转发分享、在看,也是我们继续更新的动力。

在公众号内回复更多资源,可免费获取嵌入式资料。期待你的关注~

    推荐阅读:

    专辑|Linux文章汇总

    专辑|程序人生

    专辑|C语言

嵌入式Linux

微信扫描二维码,关注我的公众号 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467483.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可以这样给DataGrid加个序号列。

先给DataGrid加个绑定列&#xff0c;该列设置页眉文本&#xff0c;但“数据字段”留空&#xff0c;然后在ItemDataBound事件中加入下面代码。 privatevoiddgScore_ItemDataBound(objectsender, System.Web.UI.WebControls.DataGridItemEventArgs e) { …

工作几天被裁员,难受

前两天&#xff0c;一个读者朋友私聊我说&#xff0c;自己被公司裁员了&#xff0c;这是他的第一份工作&#xff0c;只工作了不到半个月就收到了裁员信息。他非常不甘心&#xff0c;也非常恐慌&#xff0c;不甘心的是&#xff0c;自己觉得工作已经非常努力&#xff0c;也有做出…

cad2017单段线_没想到啊,我平时用的CAD多段线有这么多学问

很多人都说&#xff0c;CAD用多段线来代替直线绘图会比较方便&#xff0c;因为多段线除了常规直线功能之外&#xff0c;也能画弧线&#xff0c;更重要的是&#xff0c;一次命令执行的线条为一个整体&#xff0c;操作方便。难道多段线PL仅仅只有这明面上的实力吗&#xff1f;当然…

一个超强的逆向分析软件

IDA 超强逆向分析工具先说下&#xff0c;想获取这个工具的同学&#xff0c;请在公众号后台回复 「逆向分析」获取下载链接。IDA Pro&#xff08;交互式反汇编其专业版&#xff0c;后续简称为IDA&#xff09;软件是由Hex-Rays SA公司发布&#xff0c;属于当前最炙手可热的一款世…

你还不知道怎么退出 Vim?

提起文本编辑器&#xff0c;你一定会想到编辑器之神 Vim。据 Stack Overflow 的开发者调查&#xff1a;2015 年程序员中最流行的编辑器是 Notepad&#xff0c;Vim 的使用比例占 15.2%。到了 2019 年&#xff0c;最流行的开发环境变成 VS Code&#xff0c;而 Vim 的使用比例已占…

我的大学6年

这篇文章是郭天祥前辈写的&#xff0c;想起来我上大学那时候&#xff0c;也是看他的视频入门的单片机开发&#xff0c;而且那时候&#xff0c;没有这么多渠道了解外面的东西。当时最喜欢的是一个技术论坛&#xff0c;现在还因为某种原因开始收费了&#xff0c;更甚的是如果不按…

2017.10.25水题大作战题解

rank: T1P1615 西游记公司 https://www.luogu.org/problemnew/show/P1615 scanf直接秒 1 #include<iostream>2 #include<cstdio>3 #include<cstring>4 #include<cmath>5 #define LL long long 6 using namespace std;7 inline LL read()8 {9 char …

功夫熊猫问我要不要从嵌入式转行去互联网

先看问题&#xff0c;因为我平时不怎么看微信公众号的后台&#xff0c;我比较喜欢逛知识星球和微信群&#xff0c;公众号后台的交流不是很友好&#xff0c;所以没怎么关注&#xff0c;不过也会隔三岔五的看看留言&#xff0c;比如谁给我说好听的&#xff0c;或者谁骂我了&#…

进程和线程基础知识全家桶,30 张图一套带走

前言先来看看一则小故事我们写好的一行行代码&#xff0c;为了让其工作起来&#xff0c;我们还得把它送进城&#xff08;进程&#xff09;里&#xff0c;那既然进了城里&#xff0c;那肯定不能胡作非为了。城里人有城里人的规矩&#xff0c;城中有个专门管辖你们的城管&#xf…

前端面试之前要准备的那些事

先说一下关于工作简历的一些常见的问题&#xff0c;这是最基础的一步&#xff0c;万事开头难&#xff0c;写好简历就是求职路上最简单也是最关键的一步&#xff0c;一份好的简历不但可以让你从众多简历中脱颖而出&#xff0c;还能够让公司的人事对你的印象深刻。问题一&#xf…

php ip2long bug,php ip2long函数怎么用-PHP问题

php ip2long函数用于将IPV4的字符串互联网协定转换生长整型数字&#xff0c;其应用语法是“ip2long ( string $ip_address ) : int”&#xff0c;参数“ip_address”示意一个规范格局的地点。php ip2long函数ip2long — 将 IPV4 的字符串互联网协定转换生长整型数字阐明ip2long…

C语言 | 常见数据转化函数

来源&#xff1a;嵌入式云IOT技术圈作者&#xff1a;杨源鑫整理 1、字符串转十六进制代码实现&#xff1a;void StrToHex(char *pbDest, char *pbSrc, int nLen) {char h1,h2;char s1,s2;int i;for (i0; i<nLen/2; i){h1 pbSrc[2*i];h2 pbSrc[2*i1];s1 toupper(h1) - 0x3…

java常用算法分析和实现 amp,Java常用算法实现

0.总结常见算法复杂度.jpgO(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)&#xff0c;logn的底数为21.归并排序package DailyPractice;import java.util.*;public class Test1 {/*** 归并排序的思路&#xff1a;先将数组的左边和右边分开排完…

FMStocks7 , 不错的一个.NET 示例程序

这个示例程序估计很多人都用过。没有用过的话可以从 http://www.microsoft.com/downloads/details.aspx?FamilyID966C3279-2EE9-4E14-A4F7-D4807239A396&displaylangen 下载一个简单的股票买卖程序&#xff0c;数据库访问和部分业务逻辑提供了 COM 企业服务和 DotNet Remo…

这个结构体对齐输出有意思

这个题目是我在群里看到大家讨论的&#xff0c;既然是讨论的了&#xff0c;那我就拿出来说说&#xff0c;因为笔试面试的时候&#xff0c;可能就会遇到这样的题目。实例代码#include "stdio.h" #include "stdint.h"struct Obj {char a; //1uint32_t b;//4u…

声压级 matlab,语音信号处理教程(二)声音的声压级和响度

本节内容我们来看下如何用Matlab和Python计算声音的声压级和响度。声压级1. 声压级定义首先来看声压级&#xff0c;这个就是指的我们平时所说的声音有多少分贝。声压定义为声波在某一点产生的逾量瞬时压强的均方根值。由于声压容易被人耳感知&#xff0c;也易于测量&#xff0c…

javascript 之作用域-06

作用域 作用域&#xff1a;是指变量可访问的范围&#xff0c;他规定了如何查找变量&#xff0c;也就是确定当前执行代码对变量的访问权限。 作用域有两种工作模式&#xff1a; 静态作用域 &#xff1a;又称为词法作用域&#xff0c;在编译阶段就可以决定变量的引用&#xff0c;…

被裁之后才明白:有一种抗风险能力,叫做会讲故事

如果你注意观察&#xff0c;会发现周围总有这么一种人&#xff1a;他说的每句话&#xff0c;单拎出来都没毛病&#xff0c;但一说出口就让人无法接受&#xff0c;很难说服你。尤其在职场里&#xff0c;这种无效沟通特别多&#xff0c;以至于产生了庞大的“沟通成本”&#xff1…

saltstack php,Saltstack快速入门简单汇总

[rootmaster~]# salt \* test.pingminion-1:Trueminion-2:Trueminion-3:Trueminion-4:TrueTrue代表正常&#xff0c;没有响应当然代表客户端没有启动或者没有认证成功之类的。指定目标主要有五种方式一&#xff1a; Global&#xff0c;即salt默认的匹配方式&#xff0c;能识别终…

课下测试03!03!03!题目截图及解析(不完全正确)第四周--信息安全系统设计基础...

课下测试03&#xff0c;也就是第三章内容&#xff0c;以下分析和解析仅供参考哦~ 注意&#xff01;最好是对着题目看一下书&#xff0c;自己思考一下题目&#xff08;毕竟我页数都给你标出来了&#xff09;&#xff0c;不是说这样你就能提高了&#xff0c;而是我正确率真不高&a…