嵌入式里如何给内存做压力测试?不妨试试memtester


大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是内存读写正确性压力测试程序memtester

在嵌入式系统中,内存(RAM)的重要性不言而喻,系统性能及稳定性都与内存息息相关。关于内存性能有很多个不同指标,其中最基础的指标便是访问可靠性(即读写的正确性),只有稳定可靠的内存访问才能确保系统正常运行。很多时候简单地内存读写测试并不能发现隐藏的问题,因此我们需要一个完备的内存访问压力测试程序,今天痞子衡就和大家详细聊一聊memtester。

一、内存性能测试程序集

在讲memtester之前,痞子衡先给大家科普一下Linux系统下常用的内存性能测试工具,它们分别是mbw、memtester、lmbench、sysbench。这几个测试工具(程序)各有侧重点:

内存带宽测试工具            --mbw;
内存压力测试工具            --memtester;
内存综合性能测试工具        --lmbench;
内存申请与读写速度测试工具   --sysbench;

二、memtester程序

memtester是Simon Kirby在1999年编写的测试程序(v1版),后来由Charles Cazabon一直维护更新(v2及之后版本),主要面向Unix-like系统,官方主页上介绍的是“A userspace utility for testing the memory subsystem for faults.”,其实就是为了测试内存(主要DDR)的读写访问可靠性(仅正确性,与速度性能无关),这是验证板级硬件设备必不可少的一项测试。

整个memtester测试的视角就是从用户的角度来看的,从用户角度设立不同的测试场景即测试用例,然后针对性地进行功能测试,注意是从系统级来测试,也就是说关注的不单单是内存颗粒了,还有系统板级的连线、IO性能、PCB等等相关的因素,在这些因素的影响下,内存是否还能正常工作。

2.1 获取程序

memtester程序的最新版本是4.5.0,早期的v1/v2/v3版本目前下载不到了,2012年Charles Cazabon重写了程序并发布了全新v4.0.0,此后一直不定期更新,v4.x也是当前最流行的版本。

核心程序下载:http://pyropus.ca/software/memtester/

核心程序包下载后,在\memtester-4.5.0\下可找到源代码。详细源文件目录如下:

\memtester-4.5.0\memtester.h\memtester.c        --主程序入口\sizes.h            --关于系统位数(32/64bit)的一些定义\types.h            --所用数据类型的定义\tests.h\tests.c            --测试算法子程序

如果是移植到ARM Cortex-M平台下裸系统运行,一般只需要简单修改memtester.c文件即可,其他源文件就是一些头文件包含方面的改动,memtester本身并没有太多移植工作,其源码本是用作在Unix-like系统上运行的,而在嵌入式系统里运行仅需要把一些跟系统平台相关的代码删除即可,此外就是打印函数的实现。

2.2 配置参数

memtester源码里的配置选项主要是如下五个宏:

/* 如下需用户自定义 */
ULONG_MAX             -- 确定系统是32bit还是64bit
TEST_NARROW_WRITES    -- 确定是否要包含8/16 bit写测试/* 如下借助linux头文件 */
_SC_VERSION           -- posix system版本检查
_SC_PAGE_SIZE         -- 内存page大小获取
MAP_LOCKED            -- Linux里mmap里的swap特性

2.3 程序解析

让我们尝试分析memtester主函数入口main,main()函数最开始都是一些输入参数解析,其实主要就是为了获取三个重要变量:内存测试起始地址、内存测试总长度、压力测试循环次数,有了这三个变量值之后便开始逐一跑tests.c文件里各项测试算法小函数:

struct test {char *name;int (*fp)();
};struct test tests[] = {{ "Random Value", test_random_value },{ "Compare XOR", test_xor_comparison },{ "Compare SUB", test_sub_comparison },{ "Compare MUL", test_mul_comparison },{ "Compare DIV",test_div_comparison },{ "Compare OR", test_or_comparison },{ "Compare AND", test_and_comparison },{ "Sequential Increment", test_seqinc_comparison },{ "Solid Bits", test_solidbits_comparison },{ "Block Sequential", test_blockseq_comparison },{ "Checkerboard", test_checkerboard_comparison },{ "Bit Spread", test_bitspread_comparison },{ "Bit Flip", test_bitflip_comparison },{ "Walking Ones", test_walkbits1_comparison },{ "Walking Zeroes", test_walkbits0_comparison },
#ifdef TEST_NARROW_WRITES    { "8-bit Writes", test_8bit_wide_random },{ "16-bit Writes", test_16bit_wide_random },
#endif{ NULL, NULL }
};/* Function definitions */
void usage(char *me) {fprintf(stderr, "\n""Usage: %s [-p physaddrbase [-d device]] <mem>[B|K|M|G] [loops]\n",me);exit(EXIT_FAIL_NONSTARTER);
}int main(int argc, char **argv) {ul loops, loop, i;size_t bufsize, halflen, count;void volatile *buf, *aligned;ulv *bufa, *bufb;ul testmask = 0;// 省略若干变量定义代码printf("memtester version " __version__ " (%d-bit)\n", UL_LEN);printf("Copyright (C) 2001-2020 Charles Cazabon.\n");printf("Licensed under the GNU General Public License version 2 (only).\n");printf("\n");// 省略若干初始检查代码// 从输入参数里获取physaddrbase计算出内存测试起始地址aligned// 从输入参数里获取mem及B|K|M|G计算出内存测试总长度bufsizehalflen = bufsize / 2;count = halflen / sizeof(ul);bufa = (ulv *) aligned;bufb = (ulv *) ((size_t) aligned + halflen);// 压力测试的重要变量, loops即重复次数for(loop=1; ((!loops) || loop <= loops); loop++) {printf("Loop %lu", loop);if (loops) {printf("/%lu", loops);}printf(":\n");printf("  %-20s: ", "Stuck Address");fflush(stdout);// 第一个测试 stuck_addressif (!test_stuck_address(aligned, bufsize / sizeof(ul))) {printf("ok\n");} else {exit_code |= EXIT_FAIL_ADDRESSLINES;}// 遍历tests.c里的所有测试子程序for (i=0;;i++) {if (!tests[i].name) break;if (testmask && (!((1 << i) & testmask))) {continue;}printf("  %-20s: ", tests[i].name);// 可以看到将内存测试总空间一分为二,传给子程序做处理的if (!tests[i].fp(bufa, bufb, count)) {printf("ok\n");} else {exit_code |= EXIT_FAIL_OTHERTEST;}fflush(stdout);/* clear buffer */memset((void *) buf, 255, wantbytes);}printf("\n");fflush(stdout);}
}

tests.c文件里才是最核心的压力测试算法子程序,一共17个函数,涉及各种内存访问经验操作,具体可以看网上的一篇详细解析文章 https://www.jianshu.com/p/ef203c360c4f。

测试函数名测试作用
test_stuck_address先全部把地址值交替取反放入对应存储位置,然后再读出比较,重复n次
test_random_value等效test_random_comparison(bufa, bufb, count):数据敏感型测试用例
test_xor_comparison与test_random_value比多了个异或操作
test_sub_comparison与test_random_value比多了个减法操作
test_mul_comparisone与test_random_value比多了个乘法操作
test_div_comparison与test_random_value比多了个除法操作
test_or_comparison在test_random_comparison()里面合并了
test_and_comparison在test_random_comparison()里面合并了
test_seqinc_comparison是 test_blockseq_comparison的一个子集;模拟客户压力测试场景
test_solidbits_comparison固定全1后写入两个buffer,然后读出比较,然后全0写入读出比较;这就是Zero-One算法
test_blockseq_comparison一次写一个count大小的块,写的值是拿byte级的数填充32bit,然后取出对比,接着重复256次;也是压力用例,只是次数变多了;
test_checkerboard_comparison把设定好的几组Data BackGround,依次写入,然后读出比较
test_bitspread_comparison还是在32bit里面移动,只是这次移动的不是单单的一个0或者1,而是两个1,这两个1之间隔着两个空位/td>
test_bitflip_comparison也是32bit里面的一个bit=1不断移动生成data pattern然后,每个pattern均执行
test_walkbits1_comparison与test_walkbits0_comparison同理
test_walkbits0_comparison就是bit=1的位置在32bit里面移动,每移动一次就全部填满buffer,先是从低位往高位移,再是从高位往低位移动
test_8bit_wide_random以char指针存值,也就是每次存8bit,粒度更细;
test_16bit_wide_random以unsigned short指针存值,也就是每次存16bit,不同粒度检测;

2.4 结果格式

在Unix-like系统下使用make && make install命令进行编译可得到一个可执行的memtester,可以随便执行memtester 10M 1,即申请10M的内存测试1次,结果如下:

[root@as150 ~] memtester 10M 1memtester version 4.5.0 (64-bit)
Copyright (C) 2001-2020 Charles Cazabon.
Licensed under the GNU General Public License version 2 (only).pagesize is 4096
pagesizemask is 0xfffffffffffff000
want 10MB (10485760 bytes)
got  10MB (10485760 bytes), trying mlock ...locked.
Loop 1/1:Stuck Address: okRandom Value: okCompare XOR: okCompare SUB: okCompare MUL: okCompare DIV: okCompare OR: okCompare AND: okSequential Increment: okSolid Bits: okBlock Sequential: okCheckerboard: okBit Spread: okBit Flip: okWalking Ones: okWalking Zeroes: ok8-bit Writes: ok16-bit Writes: okDone.

至此,内存读写正确性压力测试程序memtester痞子衡便介绍完毕了,掌声在哪里~~~


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

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

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

相关文章

一位嵌入式工程师的成长之路

有些事并不是因为有希望才去坚持&#xff0c;而是因为坚持了才有希望。分享一位嵌入式工程师的成长之路&#xff0c;希望能给朋友一点勉励。刚毕业找不着工作2008年大专毕业后&#xff0c;意气风发南下深圳找工作&#xff0c;想找一份电子技术员的工作&#xff0c;白天上班&…

分享GitHub上一些嵌入式相关的高星开源项目

关于GitHub&#xff0c;可能很多人误以为这是互联网人的专属&#xff0c;其实并不是&#xff0c;那上面嵌入式相关的开源项目是有很多的。现分享一些高星开源项目&#xff08;像RT-Thread、AWTK等大家都熟知的就不介绍了&#xff09;&#xff1a;Avem项目链接&#xff1a;https…

安全四部曲之一---***工具简单使用

所需工具&#xff1a;ASP小旋风5.asp(黑防)鸽子2006ie_xpsp2网马生成器##############Michael分割线################先给大家几个外网路由的地址你们进去捣乱捣乱,没事的,因为没有日志记录用户名密码 全都是admin,别搞太破坏哦如果改动里面的设置,记得把登录密码改了,否则他们…

第 8 章 配置listener监听器

第 8 章 配置listener监听器注意 还记得我们之前讲过的在线列表吗&#xff1f;第 4.2 节 “例子&#xff1a;在线列表”。我们曾经说过那个在线列表无法判断用户非法退出&#xff0c;很可能造成在线列表无限增大&#xff0c;现在我们可以用listener来弥补这一问题了。如果你不满…

集合(collection)

使用数组存放数据的弊端&#xff1a;长度不可变&#xff0c;而集合可以动态的添加值 java集合类不仅可以存储数量不等的多个对象&#xff0c;还可以保存具有映射关系的关联数组 /* * 1.存储对象可以考虑&#xff1a;①数组 ②集合 * 2.数组存储对象的特点&#xff1a;Student[]…

聊培训跳槽的事

■原来跟我沟通有压力这是我最近跟一个微信好友聊天才知道的事情&#xff0c;说跟我沟通还挺有压力的。实话说&#xff0c;我多少对这样的感觉感同身受&#xff0c;记得刚毕业那会&#xff0c;跟我师傅聊天说事情&#xff0c;总担心自己会说错了什么&#xff0c;有问题的时候也…

iOS开发针对对Masonry下的FPS优化讨论

今天博客的内容就系统的讨论一下Masonry对FSP的影响&#xff0c;以及如何更好的使用Masonry。如果你对iOS开发足够熟悉的话&#xff0c;那么对Masonry框架应该不陌生。简单的说&#xff0c;Masonry的诞生让AutoLayout的使用更为优雅&#xff0c;让控件的布局更为方便。使用辩证…

导师带学生卡Bug,这波操作~

本文来自知乎https://www.zhihu.com/question/455891395/answer/1847953969事情的起因是明尼苏达大学计算机科学&工程系的助理教授 Kangjie Lu 和他的 Ph. D. 学生 Qiushi Wu 的论文《通过伪君子提交在开源软件中隐蔽地引入漏洞的可行性》&#xff0c;据称将在 2021 年五月…

我想做个MP3,要怎么入手?

从我更新的频率&#xff0c;大家应该猜出来了&#xff0c;最近有点忙。忙完了设备调试的工作&#xff0c;又来了个画图的活。本来改动不大&#xff0c;但怎料...哎&#xff0c;一言难尽。今天回答一个粉丝的提问&#xff1a;看完这个回复&#xff0c;我依然没明白他到底想做哪部…

[内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析

关于进程上下文&#xff0c;中断上下文&#xff0c;请看这篇文章Linux进程上下文和中断上下文内核空间和用户空间自旋锁的初衷&#xff1a;在短期间内进行轻量级的锁定。一个被争用的自旋锁使得请求它的线程在等待锁重新可用的期间进行自旋(特别浪费处理器时间)&#xff0c;所以…

网络流24题 洛谷 3355 骑士共存

转换成最小割&#xff1b; #include <bits/stdc.h>using namespace std ;const int mx [ 9 ] { 2 , 2 , -2 , -2 , -1 , 1 , -1 , 1 } ; const int my [ 9 ] { -1 , 1 , -1 , 1 , 2 , 2 , -2 , -2 } ; const int N 100000 10 , inf 1e8 7 ;queue < int …

从零开始设计CPU

CPU&#xff0c;中文全称为中央处理单元&#xff0c;简称处理器&#xff0c;是现代电子计算机的核心器件。如果你想了解一台计算机是如何构建并工作的&#xff0c;那么深入了解CPU的设计非常有用。不过&#xff0c;这个美好的愿望是否会遭遇“骨感”的现实呢&#xff1f;毕竟一…

嵌入式OS入门笔记-以RTX为案例:一.简介

嵌入式OS入门笔记-以RTX为案例&#xff1a;一.简介 最近在做OS相关的项目&#xff0c;一方面涉及到大量&#xff08;通用&#xff09;操作系统的概念和理解&#xff0c;另一方面要深入到一个小实时操作系统的源代码中&#xff0c;并在此操作系统上开发应用。虽然说内容上并不难…

Linux进程O(1)调度算法,面试必考哦

进程调度有很多方法&#xff0c;这里只讨论Linux下的进程调度&#xff0c;先说下&#xff0c;这个是高端面试必考题&#xff0c;既然我发文了&#xff0c;大家最好看看&#xff0c;而且目前看到的写得最好的文章&#xff0c;推荐给大家。Linux是一个支持多任务的操作系统&#…

让Visual Studio 也支持JS代码折叠 —— 续 [ Visual Studio | Js | ScriptOutline | SmallOutline ]...

前言 上文让JS代码折叠的功能能用了&#xff0c;本文将对代码继续改进以期更好用、更实用&#xff0c;随后有介绍Visual Studio JS方面的几个插件。 文章 1. VS2003折叠代码的Micro 2. MSDN 3. Document Outline for Client Script in Visual Studio 2005 正文 …

嵌入式OS入门笔记-以RTX为案例:二.快速移植到RTX

嵌入式OS入门笔记-以RTX为案例&#xff1a;二.快速移植到RTX本篇笔记将简单介绍RTX&#xff0c;包括基本架构&#xff0c;如何在Keil中配置。需要安装ARM-MDK和一块硬件板&#xff0c;笔记以STM32F4Discovery为例子。1.为什么要用RTOS&#xff1f;尽管把所有程序放在一个大的循…

再解析下内核自旋锁和优先级翻转问题

[内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼&#xff1f;Linux内核自旋锁之前写的自旋锁的文章&#xff0c;现在再加一篇&#xff0c;可能单纯的一两次说明不能把问题说清楚。所以再写一篇文…

ios 逆向编程(环境搭建)

首先如果你想要逆向其他的APP 动态的查看 或者修改人家APP里面的东西 1&#xff0c; 首先要有一台越狱的手机 最好是9.1以下的&#xff0c;因为9.2以上&#xff08;包括9.2&#xff09;就不能完美越狱了 2&#xff0c;手机也要5s以上的&#xff08;因为从5S开始支持arm64架构&…

最大、最小堆的实现

最大最小堆 堆是一种经过排序的完全二叉树&#xff0c;其中任一非终端节点的数据值均不大于&#xff08;或不小于&#xff09;其左子节点和右子节点的值。 最大堆和最小堆是二叉堆的两种形式。 最大堆&#xff1a;根结点的键值是所有堆结点键值中最大者。 最小堆&#xff1a;根…

嵌入式OS入门笔记-以RTX为案例:四.简单的时间管理

嵌入式OS入门笔记-以RTX为案例&#xff1a;四.简单的时间管理 上一节简单记录了进程task。有了进程以后&#xff0c;我们需要关心怎么样分配CPU资源&#xff08;或者运行时间&#xff09;给每个进程。那么就要引入排程&#xff08;scheduling&#xff09;的概念。排程一般都是O…