《函数分解编程模型》由会员分享,可在线阅读,更多相关《函数分解编程模型(35页珍藏版)》请在金锄头文库上搜索。
1、函数分解编程模型,林继鹏 编著,基于多核平台的嵌入式系统设计方法,长安大学 电子与控制工程学院,2,函数分解编程模型,本章介绍如何采用线程开发周期(TDC)实现应用程序的并行化,并通过函数分解实现并行任务。在介绍函数分解之前,需要先明确3个注意事项: (1)如果函数分解引起过量的同步开销或无效的缓存,多线程应用程序将得不到很好的运行,并因此影响其性能,使之比串行的应用程序性能更差; (2)通过图表配置调用说明如何有效地对应用程序进行函数分解; (3)理论上存在的线程错误在实际中并不一定是错误的,即理论分析与实际运行存在差异性,因此实施不必要的同步前需要对其作适当的正确性评估。,前言,基于多核平
2、台的嵌入式系统设计方法,3,函数分解编程模型,Snort是一个常用的开源入侵检测系统,它对网络流量进行深度检测,并利用用户设置规则对执行可疑行为的用户发出警告。Snort基于Libpcap,Libpcap是一个开源库,可以为捕获用户层数据包提供系统独立界面。本例中所用的Snort2.20 和Snort2.4.4都是单线程的。,8.1 Snort,基于多核平台的嵌入式系统设计方法,4,函数分解编程模型,1.1 Snort概述 图8-1所示的是Snort处理数据流的基本过程及主要模块。Snort处理数据流以读取网络数据包开始,即利用Libpcap读取用户空间的数据包。接着对数据包进行解码并决定其类
3、型,目的是识别链接层协议(例如Ethernet)以及网络层和传输层协议(TCP、UDP),以使这些协议头得到核实并及时处理失真协议头的数据包。完成数据包捕获后进行预处理,预处理阶段由一系列过滤器组成,它们可以识别潜在危险数据包并将这些信息传送给检测引擎。检测引擎查找数据包中的具体模式,程序员可人工对检测引擎的分析行为进行设置,且必须指定用于数据包的引擎规则。,8.1 Snort,基于多核平台的嵌入式系统设计方法,图8-1 Snort框架,5,函数分解编程模型,Snort本身带有大量的预定义插件,用于说明Snort的相关操作,如下所述: (1)Portscan插件:包括检测端口扫描攻击的代码。
4、(2)Http_inspect插件:监视包括网络请求的数据包; (3)Frag3插件:处理零碎的IP 数据包; (4)Stream4插件:对包含TCP会话的数据包进行重组,并将重组的数据流提供给探测引擎。,1 Snort,基于多核平台的嵌入式系统设计方法,6,函数分解编程模型,1.2 创建过程 Snort的基本创建过程如表8-1所示。,1 Snort,基于多核平台的嵌入式系统设计方法,7,函数分解编程模型,2.1 串行优化 对应用程序线程化之前,先要利用两个或多个编译器对串行代码优化。串行优化是并行优化的前提条件,它有两个目的:第一,串行优化为并行优化工作提供性能基准;第二,增加程序人员对应用
5、程序的熟悉度。表8-2所示是对串行优化的概述。,2 分析,基于多核平台的嵌入式系统设计方法,8,函数分解编程模型,分析应用程序的特征可得如下结论: (1)Snort体现的是关于大量数据包的数据流存取模式,数据存取优化有利于提升Snort处理数据包的效率; (2)Snort是整型应用程序,表明自动矢量化不会对串行优化有太大的帮助作用; (3)优化有利于缓存的利用,包括有益于代码量的配置文件导引优化,它可提高应用程序的性能。,2 分析,基于多核平台的嵌入式系统设计方法,9,函数分解编程模型,2.2 基准程序 将串行优化后的Snort作为基准程序。执行基准程序的时间输出结果如图8-2所示,表示时间输
6、出的语句为: Snort total run time was 0.162837 seconds,8.2 分析,基于多核平台的嵌入式系统设计方法,10,函数分解编程模型,8.2.3 串行优化结果 串行优化采用多编译器优化来提高应用程序的性能,表8-3列出了编译器、优化设置和执行时间结果。,.2 分析,基于多核平台的嵌入式系统设计方法,11,第8章 函数分解编程模型,表8-4总结了使用icc 10.0以及-ipp和iprof-use选项创建snort时的命令行。从性能结果可以观察到不同优化设置对性能的影响存在明显差异。,8.2 分析,基于多核平台的嵌入式系统设计方法,12,第8章 函数分解编程模
7、型,8.2.4 执行时间表 执行时间表是分析应用程序的重要工具,通过它可以得到各函数的执行时间情况。本例使用VTuneTM Performance Analyzer获得程序执行时间表,表8-5所示的是执行基准程序时获得的系统级(时钟周期)EBS图表。,8.2 分析,基于多核平台的嵌入式系统设计方法,13,第8章 函数分解编程模型,进一步分析snort组件可以得出表8-6中所列的函数,它们是耗时较多的函数,需要注意该组件的运行时间占整个程序的24.11%。,8.2 分析,基于多核平台的嵌入式系统设计方法,14,第8章 函数分解编程模型,8.2.5 调用图表 图8-3所示是由VTuneTM Per
8、formance Analyzer所获取的部分调用图表,从中可以看出函数InterfaceThread()以及所有由它调用的和引起的函数消耗了99%的执行时间,所以需要注意函数InterfaceThread()后的图表。,8.2 分析,基于多核平台的嵌入式系统设计方法,图8-3 snort调用图表,15,第8章 函数分解编程模型,表8-7列出了图8-3中所有函数的总执行时间和各自执行时间,总时间(total time)指的是某个指定函数以及它所调用的所有子函数的时间总微秒数,自时间(self-time)代表某个函数的运行时间,而不包括被特定函数调用的函数时间。,8.2 分析,基于多核平台的嵌入
9、式系统设计方法,16,第8章 函数分解编程模型,8.3.1 线程化Snort 对Snort串行优化的同时,还收集了一些应用程序的初始特征,接下来要考虑的如何能进一步加快应用程序执行速度。最简单的方法是改变系统中存在的核,此时,需要创建多线程Snort,实现并行后就可以通过多个线程同时工作的办法获得一定的加速比。由于Snort模块对数据包进行处理,可以使每个线程处理一个不同的数据包,则多个线程的并行执行可以加快总的处理速度。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,17,第8章 函数分解编程模型,图8-4所示的是单线程Snort运行的图解示意图,用来说明四个处理器核(IA代表处理器
10、核,DC代表数据缓存)分别执行各自线程的过程,其中每个线程都包含了所有的Snort处理步骤。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,图8-4 Snort单线程化,18,第8章 函数分解编程模型,8.3.2 代码修改 实现Snort的程化需要对代码进行修改,图8-5所示的是高级别的修改。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,图8-5 代码修改1,19,第8章 函数分解编程模型,线程化Snort工作的一个主要内容是理解其所包含的状态和共享模式。表8-8对共享状态进行了大致的分类,并说明了如何对每一种分类进行处理。,8.3 设计和执行,基于多核平台的嵌入式系统设计方
11、法,20,第8章 函数分解编程模型,图8-7 是Snort2.2 的原版本和单线程版本在不同线程上执行时的性能比较,其中吞吐量(throughtput)的计算方法是跟踪尺寸(单位:位)除以执行时间,单位为每秒兆位,图中结果是应用程序在一个双处理器且每个处理器含有四个核的系统上执行时所获得的。对于大部分的输入跟踪来说并没有明显的性能改善。实际上,在许多情况下,还会因为在多核处理器上执行多线程应用程序而导致性能下降。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,图8-7 单线程性能示例,21,第8章 函数分解编程模型,表8-9 是单线程性能结果,8.3 设计和执行,基于多核平台的嵌入式系
12、统设计方法,由表8-9可知,原始版本和4线程版本的吞吐量分别是566Mbps 和543Mbps,而二级缓存命中率是99%和 86%。从吞吐量来看,是很难得出任何结论的。然而,缓存命中率的降低却可以表明存在缓存失效。,22,第8章 函数分解编程模型,可以利用应用程序的线程图表来分析不良的性能结果。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,图8-8 简单线程Snort 线程表,23,第8章 函数分解编程模型,8.3.3 数据流定位(Flow Pinning) 本节讨论数据流定位的概念,主要包括以下内容: (1)数据流的定义; (2)数据流如何影响Snort的运行; (3)如何使用数据
13、流提高Snort的性能。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,24,第8章 函数分解编程模型,流定位的实现方法是在Snort数据流中插入一个 “分类符”,分类符决定某个数据包属于哪个数据流,并因此确定应该由哪个处理器核处理该数据包。图8-9 所示是修改后的应用程序结构。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,图8-9 Snort流定位,25,第8章 函数分解编程模型,如上所述,对Snort数据流进行函数分解后可避免以下问题: (1)由于每次只有一个线程对pacp 库进行调用,故存取pacp库时不再需要死锁; (2)在分类符和剩余代码之间,不存在对队列的存取竞争
14、,因为总是只有一个生产者(pacp+分类阶段)和一个消费者(即在一个给定的处理器核上负责执行其余阶段的线程)。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,26,第8章 函数分解编程模型,8.3.4 对流定位的代码修改 本节将详细介绍前面提到的对应用程序所做的代码修改。首先应该注意的是,由于线程模式的改变,每次只有一个线程读入数据包数据,然后再将输入数据包传给其他线程进行处理。它指出需要把由同一个线程分配的不同数据包传递给其他线程处理,这种方法所花的代价很高。不过,实质的执行过程是:Snort读入一个固定数量(4KB)的数据包数据,预先配置一个数据包缓冲池。接着,计算得出一个带有指向
15、这些缓冲区的指针队列。此时,分配数据包的代价会降低为从队列中获取一个缓冲器指针,Snort处理数据包时,数据包指针只是返回到队列。因此,可以通过单线程数据包缓冲池避免由所有试图访问全局数据包池的线程引起的同步消耗。,8.3 设计和执行,基于多核平台的嵌入式系统设计方法,27,第8章 函数分解编程模型,为验证程序正确性,需要对程序做大量的修改以实现多线程的执行。但是,人工验证100,000行包括链接系统库的、带有多个共享状态的C代码,不但会浪费大量时间,而且实施起来也非常困难。本例通过英特尔线程检查器(Intel Thread Checker)对完成数据流定位后正确性验证,它可以产生一份包含已识
16、别线程错误的诊断清单。,8.4 过滤虚假错误,基于多核平台的嵌入式系统设计方法,28,第8章 函数分解编程模型,对于英特尔线程检查器,只要右击诊断并选择“Filter Diagnostic”菜单选项即可完成对诊断中虚假错误的过滤。图8-15 是在Snort 应用程序上使用英特尔线程验证工具的一幅诊断视图。,8.4 过滤虚假错误,基于多核平台的嵌入式系统设计方法,图8-15 线程验证诊断视图,29,第8章 函数分解编程模型,分析线程错误时,另一个有用的工具是源代码视图,它允许程序员查看与源代码相关的错误。使用英特尔线程检查器时,只要双击某个错误诊断即可获得对应的源代码视图。图8-16 所示的源代码视图标出了一个数据竞争问题,将此诊断为错误的原因是因为原始单线程代码使用了含有掩码的全局结构,该全局结构可以加速检测过程。,8.4 过滤虚假错误,基于多核平台的嵌入式系统设计方法,图8-16 线程验证源代码视图,30,第8章 函数分解编程模型,完成Snort调试以后,接下来是Snort的调整阶段,重点是对性能结果进行分析评价,以弄清楚数据流定位是否能顺利执行,并且得到期望的结果。除此之外,性能的进一步提升也是调整阶段的目标之一,且仍可以考虑从简单线程到流定位重新设计,不过这样要求返回TDC并重新设计。因此,这里讨论的调整将仅仅局限于从数字方面对性能进行评估和分析。,