英特尔® 数学核心函数库并行性

摘要

软件库可帮助程序员轻松地即刻获得多核、多处理器和集群计算系统的卓越性能优势。英特尔® 数学核心函数库(英特尔® MKL)内含有大量函数,可为数学密集型应用带来巨大优势。本文将着重描述英特尔 MKL 可如何帮助程序员在普通应用领域获得超凡的串行和并行性能。此处信息适用于 Windows*、Linux* 和 Mac OS* X 操作系统上的 IA-32 和英特尔® 64 处理器。

本文是《英特尔® 多线程应用开发指南》系列文章中的一篇,旨在为开发人员开发适用于英特尔® 平台的高效多线程应用提供指导。

背景

一般来说,若要在当前的多核和多处理器系统上获得最优性能,需要充分开发和把握并行化机会,以及有效管理架构的基本内存特征。顺序代码要达到最高性能必须在极大程度上依赖指令和寄存器级 SIMD 并行性以及高速缓存分块功能。线程化应用必须通过先进的分块战略来确保多个核心和处理器均能得到充分利用,并行任务也得到均匀分配。在部分实例中,还可以使用核外实施来处理无法在内存中解决的大型问题。

建议

在数学密集型应用中添加并行性的一种最轻松的方法便是使用经优化的线程化函数库。这样不但能够节省程序员大量的开发时间,还可减少必要的测试与评估行为。另外,标准化的 API 还能帮助增加最终代码的可移植性。

英特尔 MKL 提供有一系列完整的数学函数,这些函数经过优化和线程化,可充分利用最新英特尔® 处理器的全部特性。第一次从库中调用函数时,MKL 将执行运行时检查,确定程序正在什么硬件上运行。根据该检查结果,MKL 会选择一条合适的代码路径,最大限度发挥指令和寄存器级 SIMD 并行性的优势,同时选择最出色的高速缓存分块战略。英特尔 MKL 在设计时还集成了线程安全性 (threadsafe),这意味着当同时从多条应用线程调用库中的函数时,这些函数能够保持正常运行。

英特尔 MKL 基于英特尔® C++ 和 Fortran 编译器构建而成,并使用 OpenMP* 实现了线程化。该函数库的算法能够平均分配数据和任务,充分利用多个核心和处理器。下表列出了包含线程化应用的数学域(该信息基于英特尔 MKL 10.2 Update 3):

线性代数 用于包括有限元素分析工程设计代码和现代动画在内的各种应用。
BLAS(基本线性代数子程序) 所有矩阵间运算(三级)均面向密集和稀疏 BLAS 实现了线程化。许多矢量间运算(一级)和矩阵与矢量的运算(二级)均面向英特尔® 64 架构上 64 位程序中的密集型矩阵实现了线程化。对于稀疏矩阵,除三角形稀疏矩阵解算器外的所有二级运算均实现了线程化。
LAPACK(线性代数程序包) 部分计算例程针对以下某类型的问题实现了线程化:线性方程解算器、正交因子分解、单值分解和对称特征值问题。LAPACK 也调用 BLAS,因此即使是非线程化函数也可能并行运行。
ScaLAPACK(可扩展 LAPACK) 面向集群的 LAPACK 分布式内存并行版本。
PARDISO 该并行直接稀疏矩阵解算器的三个阶段均实现了线程化:重新排序(可选)、因子分解和解算(如果采用多个右侧项)。
快速傅立叶转换 用于信号处理和石油开采及医疗成像等。
线程化FFT(快速傅立叶转换) 除 1 维实数和分裂复数 FFT 外均实现了线程化。
集群 FFT 适用于集群的分布式内存并行 FFT。
矢量数学 在多种财务代码中使用。
VML(矢量数学库) 算数、三角函数、指数/对数函数、约数等。

由于线程的创建和管理流程涉及一定的开销,因此使用多条线程并非总是物有所值的。考虑到这一点,英特尔 MKL 不会针对小问题创建线程。问题的大小是相对域和函数而言的。对于三级 BLAS 函数,可能小至 20 的维数也会经过线程化处理,而在一级 BLAS 和 VML 函数中,小于 1000 的矢量都不会分配到线程。

当从应用的线程化区域进行调用时,英特尔 MKL 应在单条线程上运行,以免过渡占用系统资源。对于使用 OpenMP 实现了线程化的应用而言,该流程可自动完成。如果使用其它方法对应用进行线程化处理,则应通过下文描述的控件设置英特尔 MKL 的行为。如果需要通过多条线程依次使用该函数库,英特尔 MKL 的部分功能可以起到关键作用。例如,矢量统计库 (VSL) 提供了一系列矢量化的随机数生成器,这些生成器虽然没有经过线程化,但却可以帮助在应用线程间划分随机数流。SkipAheadStream() 函数可将随机数流划分为多个独立的块,每条线程一个。LeapFrogStream() 函数对随机数流进行划分后可确保每条线程均获得原始流的一个子序列。例如,在两条线程之间划分流时,Leapfrog 方法会将带奇指数的数字分配给一条线程,然后将带偶指数的数字分配给另一条线程。

性能

图 1 举例说明了用户使用英特尔 MKL 中的双精度一般矩阵乘法函数 DGEMM 可实现的性能级别。该 BLAS 函数在提升许多应用的性能方面均发挥着重要作用。下图列出了 DGEMM 处理不同大小三角形矩阵的性能(以 Gflops 计),同时展示了性能如何在多个处理器之间扩展(处理两条线程的速度提高了 1.9 倍,处理四条线程的速度提高了 3.8 倍,处理八条线程的速度则提高了 7.9 倍),最终达到峰值性能的 94.3%,即 96.5 Gflops。


图 1. BLAS 矩阵乘法函数的性能与可扩展性。

使用指南

鉴于英特尔 MKL 是通过 OpenMP 实现的线程化,它的行为可能会受到 OpenMP 控件的影响。对于新增的线程化行为控制,英特尔 MKL 可提供多个服务函数来反映相关的 OpenMP 控件。这些函数支持用户控制函数库使用的线程数量,既可对整个库进行控制,也可以域为单位进行控制(即单独控制 BLAS、LAPACK 等)。这些独立控件的一项重要应用便是部署嵌套式并行处理。例如,程序员可使用 OMP_NUM_THREADS 环境变量或 omp_set_num_threads() 函数来设置使用 OpenMP 实现线程化的应用的行为,使用专门面向英特尔 MKL 的控件单独设置英特尔 MKL 的线程化行为。该控件可以是MKL_NUM_THREADS 或 mkl_set_num_threads(),视具体情况而定。最后,对于必须在单条线程上运行英特尔 MKL 函数的应用,系统将提供一个对线程运行时无任何依赖关系的顺序库。

当每条线程分别执行不同类型的运算且处理器上存在未充分利用的资源时,英特尔® 超线程技术将发挥最大的作用。然而,英特尔 MKL 完全不符合这两项标准,因为该函数库的线程化部分高效运行,占用了大部分可用资源,并且每条线程上所执行的运算完全相同。鉴于此,英特尔 MKL 在默认情况下只使用与物理内核数一样多的线程。

更多资源

英特尔® 软件网络并行编程社区

英特尔® 数学核心函数库

Netlib:有关 BLAS、LAPACK 和 ScaLAPACK 的信息
分类:
如需更全面地了解编译器优化,请参阅优化注意事项