增强开源应用程序中的处理器性能

描述

David KatzTomasz Lukasiak, 和 Rick Gentile

随着“开源”C/C++算法在嵌入式处理应用中越来越流行地替代基于版税的代码,它们带来了新的技术挑战。其中最重要的是如何优化获取的代码以在所选处理器上正常工作。这个问题至关重要,因为为给定处理器系列编写的编译器将利用该处理器的优势,但代价可能是其他领域的低效率。当同一算法直接在不同的平台上开箱即用时运行时,性能可能会降低。本文将探讨如何将此类开源算法移植到ADI公司黑鳍金枪鱼处理器®,在此过程中概述了导致代码优化的“攻击计划”。

什么是开源?

“开源”的普遍理解定义是指任何带有源代码的项目,可供其他程序员使用。开源软件通常是在软件程序员社区内协作开发的,并自由分发。例如,Linux操作系统就是以这种方式开发的。如果一切顺利,由此产生的工作将提供一个不断发展的、经过充分测试的健壮应用程序,因为许多不同的应用程序都利用了代码。鼓励程序员使用代码,因为他们不必付费或自己开发代码,从而加快了他们的项目进度。他们成功使用代码提供了进一步的测试信息。

“开源”的认证印章归开源促进会(OSI)所有。如果分发条款符合 OSI 的开源定义,则为自由共享和改进而开发的代码可以使用开源商标。这要求根据某些准则将软件重新分发给其他人。例如,在通用公共许可证(GPL)下,必须提供源代码,以便其他开发人员能够改进或发展它。

什么是奥格?

有一个完整的开发人员社区,他们致力于为数字媒体创建开放标准和应用程序的事业。其中一个团体是 Xiph.Org 基金会,这是一家非营利性公司,其目的是支持和开发免费、开放的协议和软件,为公众、开发者和商业市场服务。这个伞式组织负责监督视频(Theora)、音乐(有损Vorbis和无损Flac)和语音(Speex)编解码器等技术的管理。

术语 Ogg 表示保存多媒体数据的容器格式。它通常用作生成数据的特定编解码器的前缀。Vorbis,我们将在这里讨论的一种音频编解码器,它使用Ogg将其比特流存储为文件,因此通常称为“Ogg Vorbis”。事实上,一些便携式媒体播放器被宣传为支持 OGG 文件,其中“Vorbis”部分是隐含的。Speex是下面讨论的语音编解码器,它也使用Ogg格式将其比特流作为文件存储在计算机上。但是,互联网协议语音(VoIP)和其他实时通信系统不需要文件存储功能,并且使用实时传输协议(RTP)等网络层来封装这些流。因此,即使是 Vorbis 在通过多播分发服务器通过网络传输时也会丢失其 Ogg shell。

什么是沃比斯?

Vorbis 是一种完全开放、无专利、免版税的音频压缩格式。在许多方面,它在功能上与无处不在的MPEG-1 / 2第3层(MP3)格式和较新的MPEG-4(AAC)格式非常相似。该编解码器专为中到高质量(8 kHz 至 48 kHz 带宽,>16 位,复音)音频而设计,比特率为 16 至 128 kbps/通道,因此它是音乐的理想格式。

最初的 Vorbis 实现是使用浮点算法开发的,主要是因为编程简单,导致发布速度更快。由于大多数电池供电的嵌入式系统(如便携式MP3播放器)使用更便宜,电池效率更高的定点处理器,因此开源开发人员社区创建了Vorbis解码器的定点实现。这个定点Vorbis解码器的源代码被称为Tremor,是在允许将其合并到开源和商业系统中的许可证下发布的。

在选择用于移植 Vorbis 解码器的特定定点架构之前,分析从压缩比特流恢复音频所涉及的处理类型非常重要。Vorbis 解码过程(和其他类似算法)的通用处理器流程如图 2 所示。像许多其他解码算法一样,有两个主要阶段:前端和后端。

处理器

图2.Vorbis 解码过程的通用处理器流。

在前端阶段,主要活动是标头和数据包解包、表查找和霍夫曼解码。这类操作涉及大量的条件代码和相对较大的程序空间,因此嵌入式开发人员通常使用微控制器作为前端。

后端处理由筛选函数、逆变换和常规向量运算定义。与前端阶段相比,后端阶段涉及更多的循环构造和内存访问,通常使用较少的代码。由于这些原因,嵌入式系统中的后端处理历来由成熟的DSP主导。

Blackfin处理器架构统一了微控制器(MCU)和DSP功能,因此不再需要两个独立的设备。它可以有效地用于在单个芯片上实现前端和后端处理。

什么是斯皮克斯?

Speex 是一种开源、无专利的音频压缩格式,专为语音而设计。虽然Vorbis用于压缩所有类型的音乐和音频,但Speex仅针对语音。出于这个原因,Speex在相同质量水平的语音上可以比Vorbis取得更好的结果。

正如Vorbis与MP3和AAC等基于版税的算法竞争一样,Speex与GSM-EFR和G.72x算法(如G.729和G.722)共享语音编解码器市场的空间。Speex还具有大多数其他编解码器中不存在的许多功能。其中包括可变比特率 (VBR)、在同一比特流(8 kHz、16 kHz 和 32 kHz)中集成多个采样率以及立体声编码支持。此外,Speex最初的设计目标是促进与互联网应用程序的整合,因此它是VoIP电话系统中非常强大的组件。

除了其独特的技术特性外,Speex还具有“无成本”的主要优势,并且可以分发和修改以符合特定的应用。源代码在类似于Vorbis的许可证下分发。由于项目的维护者意识到将 Speex 嵌入到小型定点处理器中的重要性,因此在主代码分支中合并了定点实现。

优化黑鳍金枪鱼处理器上的 Vorbis 和 Speex

当现有应用程序(如 Vorbis 或 Speex)移植到新处理器时,即时的“开箱即用”代码性能是最重要的考虑因素。但是,软件工程师可以通过熟悉可用于优化整体性能的许多技术来获得丰厚的回报。有些只需要最少的额外努力。

将任何软件移植到像Blackfin这样的嵌入式处理器的第一步是定制低级I / O例程以满足系统需求。例如,Vorbis 和 Speex 的参考代码都假设数据源自文件,并且处理后的输出存储到文件中(主要是因为这两种实现最初都是为在 Unix/Linux 系统上运行的,其中文件I/O 例程可用)。然而,在嵌入式媒体系统中,输入和/或输出通常连接到在数字和现实世界模拟域之间进行转换的A/D和D/A数据转换器。图 3 显示了可能的基于 Vorbis 的媒体播放器实现的概念概述。输入比特流从闪存传输,解码器输出驱动音频DAC。此外,虽然某些媒体应用程序(例如便携式音乐播放器)仍然使用文件来存储数据,但许多系统用网络连接取代了存储。

处理器

图3.示例:Vorbis 媒体播放器实现。

在优化像 Vorbis 解码器这样的系统以高效运行时,最好有一个有组织的攻击计划。一种可能性是首先从 C 中优化算法,然后简化系统数据流,最后在汇编级别调整各个代码片段。图 4 说明了通过连续优化步骤减少处理器负载的代表性,并显示了此方法的效率。

处理器

图4.在Blackfin上优化Vorbis源代码的步骤,导致处理器利用率显着降低。

编译器优化

代码优化最有用的工具可能是好的探查器。使用 Blackfin 的 VisualDSP++ 中的统计分析器,程序员可以快速关注处理器执行代码时变得明显的热点。在许多实现中,20% 的代码占用了 80% 的处理时间。专注于这些关键部分会产生最高的边际回报。事实证明,循环是像 Vorbis 这样的媒体算法中优化的主要候选者,因为密集的数字处理通常发生在它们内部。

还有全局代码优化方法。首先,编译器可以针对内存节省或速度进行优化。此外,还可以考虑将汇编指令自动内联到 C 代码中的函数。(编译器的 inline 关键字用于指示函数应在调用点内联生成代码。这样做可以避免各种成本,例如程序流延迟、函数进入和退出指令以及参数传递开销。这也在空间和速度之间产生了权衡。最后,像Blackfin这样的编译器可以使用两阶段过程来派生单个项目中各种源文件之间的关系,以进一步加快代码执行(过程间分析)。

如上所述,大多数媒体算法参考软件都使用浮点运算。但是,使用分数定点机编写的软件仍然错过了一个关键部分。大多数编解码器算法选择的语言是 C,但 C 语言并不“原生”支持使用分数定点数据。因此,许多分数定点算法都使用整数数学进行仿真。这可能会使代码具有高度的可移植性,但它无法达到通过使用特定于机器的编译器构造重写某些数学函数以实现最高计算效率来实现的性能。

图 5 显示了说明这一点的具体示例。左列显示了适用于所有整数机器的模拟小数算术的 C 代码和 Blackfin 编译器输出。一次调用来执行 32 位小数乘法需要 80 个周期。右列显示了利用 (mult_fr1x32x32) 获得的性能改进,( 是 Blackfin 编译器的固有功能,它利用了底层小数硬件。通过这种相当简单的修改,实现了 86% 的加速。

处理器

图5.编译器内部函数是一个重要的优化工具。

系统优化

系统优化始于适当的内存布局。在最好的情况下,所有代码和数据都可以放入处理器的L1内存中。遗憾的是,这并不总是可行的,尤其是在网络应用程序中实现基于 C 的大型应用程序时。

真正的困境是处理器经过优化,可以通过直接内存访问(DMA)独立于内核移动数据,但MCU程序员通常使用缓存模型运行。虽然核心提取是不可避免的现实,但必须使用 DMA 或缓存进行大型传输以保持性能。

为了介绍讨论,让我们考虑Blackfin总线架构固有支持的几个属性。首先是无需核心干预即可仲裁请求的能力。由于内部存储器通常构建在子库中,因此通过将数据放置在单独的组中,可以在单个周期内完成DMA控制器和内核的同时访问。例如,内核可以对一个子银行中的数据进行操作,而DMA正在填充第二个子银行中的新缓冲区。在某些情况下,也可以同时访问同一子银行。

通常只有一条物理总线可用于访问外部存储器。因此,仲裁功能变得更加重要。这里有一个例子来阐明这一挑战:在任何给定的周期中,可以访问外部存储器位置以填充指令缓存,同时它充当传入和传出数据的源和目的地。

指令执行

Blackfin处理器使用分层内存架构,努力平衡具有不同大小和性能水平的多个内存级别。片上 L1 存储器最接近核心处理器,以全时钟速率运行。此存储器可以配置为SRAM和/或缓存。需要最高确定性的应用可以在单个内核时钟周期内访问片内SRAM。对于需要更大代码大小的系统,可以使用额外的片上和片外存储器,但延迟会增加。

SDRAM比L1 SRAM慢,但它是存储大型程序和数据缓冲区所必需的。但是,程序员有几种方法可以利用快速 L1 内存。如果目标应用程序直接适合 L1 内存,则除了程序员将应用程序代码直接映射到此内存空间之外,不需要执行任何特殊操作,如上述 Vorbis 示例所示。

如果应用程序代码对于内部存储器来说太大,例如在将网络组件添加到 Vorbis 编解码器时,可以使用缓存机制来允许程序员访问更大、更便宜的外部存储器。缓存可根据需要自动将代码导入 L1 内存。一旦进入L1,代码就可以在单个内核周期内执行,就像它最初存储在片上一样。此过程的主要优点是程序员不必管理代码进出缓存的移动。

当正在执行的代码本质上是线性的时,最好使用缓存。指令缓存实际上执行两个角色。首先,它有助于以更有效的方式从外部存储器预取指令。此外,由于缓存通常使用某种类型的“最近最少使用”算法运行,因此运行次数最多的指令通常保留在缓存中。因此,如果代码已提取一次并且尚未被替换,则下次通过循环执行它将准备好执行。

谨慎的实时程序员不信任缓存来获得最佳系统性能,因为如果在需要执行时缓存中没有指令块,系统性能就会下降。通过利用缓存锁定机制可以避免此问题。当关键指令加载到缓存中时,可以锁定缓存行以防止指令被替换。这允许程序员将他们需要的东西保存在缓存中,并允许缓存机制本身管理不太关键的指令。此功能使Blackfin处理器与其他信号处理器区分开来。

数据管理

在讨论了如何最好地管理代码以提高此应用程序的性能之后,现在让我们考虑数据移动的选项。作为缓存的替代方法,可以使用独立于内核的 DMA 控制器将数据移入和移出 L1 内存。当内核在内存的一部分上运行时,DMA 将引入下一个要处理的数据缓冲区。

Blackfin数据存储器架构对整体系统性能的重要性不亚于指令时钟速度。由于多媒体应用中通常同时发生多个数据传输,因此总线结构必须支持对内部和外部存储器所有区域的内核和DMA访问。自动处理 DMA 控制器和内核的仲裁至关重要,否则性能将大大降低。内核到 DMA 交互只需在设置 DMA 控制器时进行,稍后在准备好处理数据时响应中断。此外,数据缓存还可以提高整体性能。

在默认模式下,Blackfin将数据获取作为基本的核心功能执行。虽然这通常是传输数据的效率最低的机制,但它导致了最简单的编程模型。快速暂存器存储器通常作为 L1 存储器的一部分提供;但对于较大的片外缓冲区,如果内核必须获取所有内容,则访问时间将受到影响。不仅需要多个周期来获取数据,而且核心也将忙于获取。

因此,只要有可能,DMA 应始终用于移动数据。Blackfin处理器具有DMA功能,可在外设和内存之间以及不同内存段之间传输数据。例如,我们的 Vorbis 实现使用 DMA 将音频缓冲区传输到音频 D/A 转换器。

对于此音频应用,使用“旋转门”双缓冲方案来容纳 DMA 引擎。当循环双缓冲器的一半被串行端口DMA清空时,另一半被解码的音频数据填充。为了限制压缩数据的解码速率,DMA 中断服务例程 (ISR) 修改解码器可以读取的信号量,以确保写入双缓冲区的特定一半是安全的。在缺少操作系统 (OS) 的设计中,轮询信号量意味着浪费 CPU 周期;但是,在操作系统下,调度程序可以切换到另一个任务(如用户界面),以使处理器忙于实际工作。

如果不考虑数据一致性,使用 DMA 可能会导致不正确的结果。因此,与音频 DAC 关联的音频缓冲区放置在不可缓存的内存空间中,因为缓存可能保存的数据版本比 DMA 要传输的缓冲区更新。

装配优化

优化的最后阶段与用汇编语言重写开源 C 代码的隔离段有关。通过程序集重写提高性能的最佳候选者通常是中断服务例程 (ISR) 和可重用的信号处理模块。

在汇编中编写中断处理程序的动力是,低效的 ISR 会减慢其他中断处理程序的响应速度。例如,某些音频设计必须使用音频 ISR 来格式化绑定到音频 DAC 的 AC97 数据。由于这种情况会定期发生,因此较长的音频 ISR 可能会减慢其他事件的响应速度。减少中断处理程序的周期计数的最佳方法是在汇编中重写它。

可重用信号处理模块的一个很好的例子是后端Vorbis处理中使用的改进的离散余弦变换(MDCT),用于将时域信号转换为频域表示。编译器永远无法像熟练的汇编程序员那样生成“紧凑”的代码,因此 MDCT 的 C 版本效率低下。同一函数的汇编版本可以利用Blackfin架构的硬件功能,例如单周期蝶形加减法和硬件位反转。

今天,Vorbis和Speex的Blackfin端口都存在,并可根据要求提供。这些端口在ADSP-BF533 EZ-KIT Lite上运行。μClinux的开源端口也可在 blackfin.uclinux.org 获得。总之,它们支持各种应用程序,这些应用程序寻求集成免版税的语音或音乐功能,同时为其他特性和功能保留充足的处理空间。例如,新型ADSP-BF536和ADSP-BF537集成以太网MAC,为低成本网络音频和语音应用打开了大门。显然,开源代码预示着嵌入式处理世界的一场革命,Blackfin处理器准备充分利用这种情况。

审核编辑:郭婷

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分