全新 Android* 世界的可信赖工具:优化技术 — 从英特尔® SSE 内部指令到英特尔® Cilk™ Plus

作者: 英特尔高级软件应用工程师 Zvi Danovich

简介

大部分的 Android 应用 — 即使是仅基于脚本和管理语言 (Java*, HTML5,…) 的应用 — 最终都会使用中间件功能,因为该功能能够利用优化特性。

本文将介绍基于 Android 的优化需求和方法,并详述一个优化多媒体和增强现实应用的案例。

英特尔为 Android 平台(智能手机和平板电脑)提供了多种不同的英特尔® 凌动™ 处理器,至少包括英特尔® SIMD 流指令扩展补充版(英特尔® SSSE3)级别的矢量功能,通常包括两个内核和超线程。

理解并使用这些优化功能吧!

iOnRoad* 案例研究

iOnRoad* 是一款增强现实应用,可提供实时个人驾驶协助函数,如碰撞报警将现代计算机视觉算法用于智能手机。

为了保证实时,iOnRoad 应用需要在处理前将手机摄像头生成的每帧 YUV420/NV21 输入转换为 RGB 形式。

iOnRoad 执行此转换的最初代码需要 40% 的CPU 运行时,这限制了图像处理的使用并使优化强制执行。

我们发现唯一可以使用的优化软件是英特尔® 集成性能基元例程 YUV420ToRGB,但是它没有 iOnRoad 应用需要的基本输入和输出格式组合。 除此之外,此例程不是多线程!

因此,我们决定创建新的优化代码来执行所需的转换。

YUV420/NV21 向 RGB 转换

YUV420/NV21 格式拥有 8 位亮度(黑白)Y 和 2 度色度(彩色)的 U & V 组件。

四个为一组的 Y 组件仅需要一对相应的 V & U 组件便可生成标准的 RGB 格式(在一个像素中包含其 3 种颜色元素)。

上图中的 Y (四个为一组并着有相同的颜色)配备了成对的 V & U。

此格式(广泛称为 YUV)相比 RGB 可提供双倍的压缩。

YUV 向 RGB 的转换 — 整数查找表方法

YUV 向 RGB 的转换使用了简单的线性公式。

为了避免转换(cast)为浮点,我们使用了众所周知的整数近似值:

这些公式可得出中间结果 >216,这一点我们在稍后的矢量讨论中将会提及。

对于标量计算,iOnRoad 使用了查找表 (LUT) 方法:由于 Y、U 和 V 为 8 位,上述乘法公式可在 32-bit-out LUT 的 5 个 256 条目中预先计算 。

YUV 向 RGB 的转换 — 使用英特尔 SSE 的固定点方法

英特尔® SSE 不包括矢量化的 LUT (收集)指令。 打包的 16 位乘法通常比后续打包的标量 LUT 操作快。

但是无法使用基本的英特尔 SSE 16 位乘法 (PMULLW),因为预计的中间结果 >216

英特尔® SSSE3 包含 _mm_mulhrs_epi16() 指令,该指令将完整的 16 位乘法与将中间状态的 32 位结果向右漂移(shift)相结合,为最终的 16 位结果提供了凑整。

为了提供最终结果中有效位的最大数量,需要将最初的乘法操作数向左漂移(在我们的案例中,我们能够达到 13 位的最终结果)。

YUV 向 RGB 的转换 — 固定点 SSE 方法的实施

该流程首先需要加载两份 16x8 位 Y 和 8 对 8 位 (U,V) 。

最后,该数据将会转换为 16x32 位 RGB 像素(格式为 FRGB,最高字节是 0xff)。

使用 8 位饱和减法运算从 16x8 位 Y 中减去 16,这样我们便无需检查和纠正不是负数的结果。

8 对 (U,V) 可为 2 行 16 Y “服务”。

为了对输入数据解包,使用了字节 shuffle 运算,生成两份的:

  • 2 组 8x16 位 Y
  • 1 组 4x16 位双 U
  • 1 组 4x16 位双 V

以下是生成一份的具体方案:

在使用 U & V 前,使用打包的 16 位 _mm_sub_epi16() 指令减去 128。

减去后,所有 8x16 位 Y、U & V 打包数据都将向左漂移,以最佳的方式配合 _mm_mulhrs_epi16() 指令,该指令使用了适当打包的系数

注: 在标量算法中准备上述步骤(减法和漂移)而非执行 LUT 操作。

将乘法结果相加以接收最后的 16 位打包值,该值使用 _mm_min_epi16() 和 _mm_max_epi16() 裁剪并落在 0 和 213-1 (8191) 之间。

所有运算完成后,结果将以 13/16 位分离的 R、G 和 B 值的打包形式呈现。

可通过两个阶段将这些值重新打包为 FRGB 形式(其中 F 是用所有值填充的 alpha 通道,这是应 iOnRoad 应用的要求)。

在第一个阶段,我们将用采用 16 位 <0xff00> 值填充的寄存器把 13/16 位分离的 R、G 和 B 重新打包到 16 位对 FR 和 GB。

此阶段由逻辑左和右漂移和逻辑 OR/AND 操作构成,如下图所示:

在第二个阶段中,最终使用 interleaving _mm_unpacklo_epi16() 和 _mm_unpackhi_epi16() instructions 将 FR & GB 中间结果打包到 FRGB:

上述用于从 YUV 向 RGB 转换的基于英特尔 SSE 指令的代码比最初基于标量 LUT 的代码提高了 4 倍Ω

为并行化使用英特尔® Cilk™ Plus

智能手机和平板电脑中使用的大部分的英特尔凌动处理器至少包括两个逻辑内核(目前,有些机型使用了双核和超线程)。 未来核心数量肯定会增长,因此并行算法将会越来越重要。

大部分的并行方法由英特尔® 编译器中的英特尔® Cilk™ Plus 扩展提供,可用于 C 和 C++ 代码(但是英特尔® 线程构建模块仅可用于 C++!)

英特尔 Cilk Plus 最简单的并行运算符 “cilk_for” (用于 YUV 向 RGB 转换的外层循环而非标准的 C/C++ “for”)可将基于双核英特尔凌动处理器 Z2760 的设备(代号 Clover Trail)的性能提高 2 倍Ω

将针对矢量化的英特尔 SSE 指令与英特尔 Cilk Plus 并行化一起使用可使总体性能提高 8 倍Ω

Ω 性能测试中的软件和工作负载可能仅在英特尔微处理器上针对性能进行了优化。 诸如 SYSmark 和 MobileMark 等测试均系基于特定计算机系统、硬件、软件、操作系统及功能, 上述任何要素的变动都有可能导致测试结果的变化。 请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对目标产品进行全面评估。 配置: [基于双核 Clover Trail 凌动 2.00Ghz Z2760 处理器的工程样例系统,采用 1Gb RAM 内存,运行 Android 4.1.2 (Jelly Bean) 操作系统和特定的 iOnRoad 测试应用]。 如欲了解更多信息,请访问:http://www.intel.com/performance

结论和行动号召

英特尔® SSE 指令(英特尔 SSSE3 级别)可显著提升性能,英特尔® Cilk™ Plus 非常适合在基于英特尔凌动处理器并运行 Android 的设备上对应用执行并行化处理。

我们建议针对基于英特尔凌动处理器的设备编写应用的 Android 开发人员使用英特尔® SSE 和英特尔® Cilk™ Plus 优化多媒体应用和游戏。 这些可信赖的工具可带来出色的性能提升!

关于 iOnRoad

关于公司的描述,请访问 iOnRoad 网站

英特尔、Intel 标识、凌动和 Cilk 是英特尔公司在美国和/或其他国家(地区)的商标。
英特尔公司 © 2014 年版权所有。 所有权保留。
* 其他的名称和品牌可能是其他所有者的资产。