自动测试工具这里有一些可以满足不同需求的测试工具供您选择。本节只是简单介绍,不提供详细的操作指南。AuToTestAuToTest是一个全自动测试框架。它存在的主要目的是测试Linux内核。当然,它也可以用来测试其他的东西,比如测试一个新的硬件是否可以稳定工作。AuToTest是一个开源软件,由GPL授权,运行在server-client架构(即C/S架构)上。您可以配置服务器来初始化、运行和监视运行客户端的系统,或者您可以自己在目标系统上运行客户端。此外,您还可以为该测试框架添加测试用例,具体请参考AuToTest白皮书。LinaroAutomatedValidationArchitectureLAVA自动化测试框架,用于自动安装和运行测试。例如:你只需要在LAVA中运行几个命令就可以运行LTP(LCTT:LinuxTestProject,中文是Linux测试计划,由SGI发起,IBM维护,目的是为开源社区提供测试套件以验证Linux的可靠性、健壮性和稳定性)。LAVA命令可以自动为你安装LTP需要的所有依赖包,下载源码,编译代码,将LTP安装到单独的地方,这样在卸载LTP时就可以去掉所有的二进制文件。安装好LTP后,在运行LAVA命令时加入'ltp'选项即可运行LTP测试任务。它将测试结果保存在一个文件中,文件名包括测试名称和时间戳。这些测试结果可以保存以备将来参考。这是发现软件退化(如果软件完全退化)的好方法。以下是LAVA与LTP一起使用的一些命令:显示LAVA支持的测试列表:lava-testlist-tests安装测试套件:lava-testinstallltp运行测试:lava-testrunltp查看结果:lava-测试结果显示ltp-timestamp.0卸载测试套件:lava-testuninstallltp内核调试功能Linux内核本身包含很多调试功能,例如kmemcheck和kmemleak。kmemcheckkmemcheck是一个动态检查工具,可以检测一些未初始化的内存(LCTT:在内核模式下使用这些内存可能会导致系统崩溃)并发出警告。它的功能与Valgrind类似,只是Valgrind运行在用户态,而kmemchecke运行在内核态。编译内核时加入CONFIG_KMEMCHECK选项,开启kmemcheck调试功能。您可以阅读Documentation/kmemcheck.txt了解如何配置和使用该功能,以及如何理解调试结果。kmemleakkmemleak通过类似垃圾收集器的函数检测内核中的内存泄漏。kmemleak和垃圾收集器的区别是前者不会释放orphantargets(LCTT:memoryareasthatwillnolongerbeused,shouldbereleasebuthavenotreleased),而是会打印到/sys/kernel/debug/kmemleak文件。用户态的valgrind也有类似的功能。使用--leak-check选项可以检测并报告内存泄漏,但不会释放这个孤立内存。编译内核时使用CONFIG_DEBUG_KMEMLEAK选项启用kmemcleak调试。阅读Documentation/kmemleak.txt以了解如何使用此工具并阅读调试结果。内核调试接口Linux内核通过配置选项、调试API、接口和框架支持动态或静态调试。现在就让我们好好学习,学习这些神奇的功能吧,从静态编译选项开始。调试配置选项:大多数Linux内核和内核模块的静态编译包括调试选项。你只需要在编译内核或内核模块时加上这个静态调试选项,调试信息就会在程序运行后产生并记录在dmesg缓存中。.调试API的一个很好的例子是DMA-debug,它用于调试驱动程序是否错误地使用了DMA提供的API。它跟踪每个设备的映射,检测“取消映射”不存在的映射的尝试,并检测代码建立DMA映射后可能发生的“丢失映射”错误。内核配置选项CONFIG_HAVE_DMA_APT_DEBUG和CONFIG_DMA_API_DEBUG向内核提供此功能。其中,CONFIG_DMA_API_DEBUG选项开启后,内核调用DMAAPI的同时也会调用Debug-dma接口。例如,当驱动程序调用dma_map_page()函数映射DMA缓冲区时,dma_map_page()调用debug_dma_map_page()函数跟踪缓冲区,直到驱动程序调用dma_unmap_page()取消映射。有关详细信息,请参阅使用DMA调试API检测潜在的数据污染和内存泄漏。#p#动态调试动态调试功能是在程序运行过程中可以决定是否正常运行函数pr_debug()、dev_dbg()、print_hex_dump_debug()、print_hex_dump_bytes()。什么意思?当程序运行出现错误时,可以指定程序打印有针对性的详细调试信息。这个功能太棒了,我们再也不需要为了添加调试代码来定位问题而重新编译安装内核了。您可以指定CONDIF_DYNAMIC_DEBUG选项来启用动态调试,然后通过/sys/kernel/debug/dynamic_debug/control接口指定打印哪些调试日志。代码级和模块级打印日志的操作方法如下:让kernel/power/suspend.c源码第340行的pr_debug()函数打印日志:echo'filesuspend.cline340+p'>/sys/kernel/debug/dynamic_debug/control允许内核模块在加载过程中开启动态调试功能:使用modprobe命令为模块添加dyndbg='plmft'选项。要在重新启动后启用内核模块的动态调试:编辑/etc/modprobe.d/modname.conf文件(如果没有,则创建一个),并添加dyndbg='plmft'选项。但是对于那些通过initramfs加载的驱动,这个配置基本无效(LCTT:免费赠送点更高级的知识。系统启动时需要先让initramfs挂载一个虚拟文件系统,然后再挂载到启动盘real文件系统。这个虚拟文件系统中的文件是由initramfs自己提供的,也就是说,如果你在真实文件系统下配置文件/etc/modprobe.d/modname.conf,initramfs会完全忽略它。从内核驱动的角度看:如果内核驱动是在initramfs过程中加载到内核中的,驱动读取的/etc/modprobe.d/modname.conf是initramfs提供的,而不是你自己编辑的。所以才会有上面的结论“写完配置文件重启还是无效”)。对于这种捣蛋鬼,呃,刁钻的驱动,我们需要修改grub配置文件,在kernel这一行加入module.dyndbg='plmft'参数,这样你的驱动就可以启动动态调试功能了。如果要打印更详细的调试信息,可以使用dynamic_debug.verbose=1选项。有关详细信息,请参阅Documentation/dynamic-debug-howto.txt文件。设置跟踪点到目前为止,我们已经介绍了各种动态和静态调试方法。静态调试选项和静态调试钩子函数(如DMADebugAPI)需要打开或关闭编译过程,导致需要重新编译和安装内核的悲哀事实。动态编译功能省去了“重新编译”的麻烦,但也有缺点,就是调试代码引入了条件变量来判断是否打印调试信息。这个方法可以让你在程序运行的时候决定是否打印日志,但是需要多做一个判断过程。“跟踪点”代码只有在程序运行时使用“跟踪点”功能才会被触发。换句话说,“跟踪点”代码不同于上面提到的两种方法。不用的时候不会运行(LCTT:动态调试,代码需要每次检查变量,然后判断是否打印日志;而“tracepoint”好像是用了某种触发机制,不需要查看变量)。当你需要使用它时,程序的代码中会包含“跟踪点”代码。它不添加任何条件变量来增加系统的运行负载。有关详细信息,请参阅布局跟踪代码的提示。“tracepoint”的原理Tracepoint使用“跳转标签”,这是一种使用分支跳转的代码修改技术。当跟踪点关闭时,伪代码如下所示:[code1]nopback:[code2]return;tracepoint:[tracepointcode]jmpback;开启tracepoint后,伪代码是这样的:(注意tracepoint代码出现在哪里)[code1]jmptracepointback:[code2]return;tracepoint:[tracepointcode]jmpback;(LCTT:咳咳,解释一下以上两段伪代码,能看懂的高手请无视此注释,不使用tracepoint时,代码运行过程为:code1->code2->returnend;使用tracepoint时,代码运行过程为:code1->jumptotracepointcodetoexecutedebuggingcode->jumpbackcode2->returnends两段代码唯一不同的是第二行,前者是nop(什么都不做),后者是jmptracepoint(跳转到debugcode).)Linux电源管理子系统的测试使用了静态调试、动态调试和跟踪调试技术,我们来运行一下磁盘的电源管理测试。当系统挂起时,内核会为磁盘创建一个休眠映像,使磁盘进入休眠模式。当系统再次被唤醒时,内核将使用这个休眠映像再次唤醒磁盘。设置挂起和唤醒设备所需的时间:echo1>/sys/power/pm_print_timessuspendthediskinrebootmode:echoreboot>/sys/power/diskechodisk>/sys/power/statesuspendthediskinshutdownmode——同reboot模式,只是重新唤醒磁盘需要供电。echoshutdown>/sys/power/diskechodisk>/sys/power/state在平台模式下挂起磁盘——可以测试更多的内容,比如BIOS挂起和唤醒,会涉及到ACPI功能。推荐您使用此方法,拉低BIOS与您一起玩挂机和唤醒游戏。echoplatform>/sys/power/diskechodisk>/sys/power/state#p#LinuxKernelPatchTest你试过写你自己的内核补丁吗?本节描述了在将补丁提交到Linux邮件列表之前要做的事情。另外,我们将介绍如何发送它。代码写好后,编译。将make过程的输出保存到文件中,并检查有关新代码的警告。找到所有警告消息并进行处理。当您的代码编译后没有任何异常输出时,安装内核并开始测试。如果正常启动,查看dmesg是否有错误,并与旧内核生成的dmesg日志进行对比。进行一些压力测试,请参考我们之前介绍的测试内容。如果此补丁用于修复错误,请确保它确实已修复。如果确实修复了它,请确保它通过了系统测试。在你打补丁的模块下找到回归测试工具,并运行它。如果补丁涉及其他架构,需要交叉编译测试。测试工具请在以下目录找到:linux_git/Documentationlinux_git/tools/testing交叉编译参考:Cross-compilingtheLinuxkernelonx86_64architecture:abeginner'stutorial如果您对补丁的测试结果满意,可以提交补丁。请确保提交信息的描述非常清楚。内核维护者和其他开发人员了解补丁更改的内容非常重要。生成补丁后,执行scripts/checkpatch.pl脚本,找到checkpatch生成的错误或警告(如果有的话),并进行修复。重新生成补丁,直到补丁通过这个脚本的测试。重新测试这个补丁。在其他内核源代码上使用此补丁可确保不会出现冲突。现在您已准备好提交您的补丁。首先运行scriptst/get_maintainer.pl以查看您应该将补丁发送给哪个内核维护者。注意不要将补丁作为附件发送,而是将其作为纯文本粘贴到电子邮件中。确保您的电子邮件客户端可以发送纯文本消息,您可以尝试给自己发送一封补丁电子邮件来测试您的电子邮件客户端的功能。收到您自己的电子邮件后,运行checkpatch命令并将您的补丁应用于您自己的内核源代码。如果这两个步骤通过,您可以将补丁发送到Linux邮件列表。使用gitsend-email命令是提交补丁和避免电子邮件兼容性问题的最安全方式。您需要在.gitconfig文件中配置有效的smtp服务器。详细操作请参考git的帮助文档。更多关于提交补丁的规则,请参考以下资料:.txt下面是内核测试教程的一些资源:USBTestingonLinuxLinuxKernelTester'sGuideChapter2LinuxKernelTester'sGuide在eLinux.org上的测试资源eLinuxDebuggingPortal内核测试套件和项目除了我们已经讨论过的测试资源,这里还有很多测试项目值得介绍,包括开源的和厂商自己提供的。这些项目中的每一个都特定于特定领域,例如嵌入式或企业用途。让我们简要回顾一下。Linux测试项目(LTP)测试套件是一组用于测试内核的可靠性、健壮性和稳定性的工具。你可以在这个项目中添加你自己的测试代码,LTP项目欢迎你自己的代码贡献。runltp脚本默认测试以下子系统:文件系统压力测试磁盘IO测试内存管理压力测试IPC(进程间通信)测试调度器测试命令功能验证测试系统调用功能验证测试LTP-DDT是一个LTP(LCTT)的测试应用:是不是LTP的阉割版),主要是测试嵌入式设备驱动。LinuxDriverVerification是一个旨在提高Linux设备驱动程序质量的项目。它开发了一个用于设备驱动程序验证的集成环境平台,并利用当代研究来提高验证工具的质量。一致性测试如果您有将应用程序从一个Unix平台移植到另一个平台的经验,您就会理解LinuxStandardBase(LSB)和LSB一致性测试套件的重要性。LSB由Linux基金会工作组创建,旨在通过减少不同Linux发行版之间的差异并确保应用程序在不同发行版之间的可移植性来减少支持不同Linux平台所需的开销。古今为师,Linux世界必须避免Unix世界的差异。这就是为什么你可以把一个rpm包转成一个deb包,还能正常安装运行的秘诀。静态分析工具静态分析之所以称为“静态分析”,是因为这些工具只分析代码,不执行代码。有许多用于分析Linux内核代码的静态分析工具。Sparse是LinusTorvalds编写的检查内核静态类型的工具。它是一个语义检查器,为C语言的语义构建语义解析树并执行惰性类型评估。内核编译系统支持稀疏,并为编译内核的命令提供了启用稀疏的选项。对内核中所有需要重新编译的C文件执行稀疏语义检查:makeC=1allmodconfig对内核中所有C文件执行稀疏语义检查(即使它们不需要重新编译):makeC=2allmodconfigSparse的资源:SparseArchiveSparseHowToSmatchAnalysis程序代码逻辑错误。它可以检测逻辑错误,例如“为未锁定的自旋锁执行解锁”。内核源码支持smatch:在Linux内核中运行smatch:makeCHECK="~/path/to/smatch/smatch-p=kernel"C=1bzImagemodules|teewarns.txt请参考以下资料获取并编译smatch。需要注意的是,smatch是一个开发中的项目,架构在不断变化。Smatch那么我们如何处理Sparse和Smatch发现的语义和逻辑错误呢?有些错误可以隔离为日常问题或模块问题,这些问题很容易解决。但是有些语义错误涉及整个世界,因为有些代码是剪切和粘贴的。在某些环境下,当某些接口功能被弃用不再使用,或者只做了很小的改动时,就需要大规模更新源码。这时候您需要Coccinelle的帮助,Coccinelle使用SmPL语言(SemanticPackageLanguage)为C代码提供匹配转换功能。Coccinelle自成立以来一直作为Linux的衍生产品不断发展。例如:foo(int)函数突然变成了foo(int,char*)函数,多了一个输入参数(第二个参数可以设置为null)。所有调用foo()的代码都需要更新,这可能是一件苦差事。但如果你使用Coccinelle,这项工作瞬间变得简单。该脚本将帮助您找到调用foo(parameter1)的代码,然后将其替换为foo(parameter1,NULL)。这样做之后,可以运行所有调用该函数的代码,验证第二个参数是否为NULL,是否正常工作。关于Coccinelle的更多信息,以及如何在不同的项目(当然也包括Linux内核项目)中使用,请参考项目主页:Cocinelle。参考文献本文涵盖了很多方面,这里有一些参考文件供读者做进一步的研究。KernelHackingkernelDocumentationLinuxDeviceDrivers,ThirdEditionDynamicEventTracinginLinuxKernel内核测试:工具与技术原文链接:http://linux.cn/article-3682-1.htmlhttp://linux.cn/article-3684-1.html
