英特尔 MKL 或一些类似的库是不是提供了一种矢量化方式来计算数组中满足 C 中某些条件的元素数量?
Posted
技术标签:
【中文标题】英特尔 MKL 或一些类似的库是不是提供了一种矢量化方式来计算数组中满足 C 中某些条件的元素数量?【英文标题】:Does Intel MKL or some similar library provide a vectorized way to count the number of elements in an array fulfilling some condition in C?英特尔 MKL 或一些类似的库是否提供了一种矢量化方式来计算数组中满足 C 中某些条件的元素数量? 【发布时间】:2020-11-01 05:00:13 【问题描述】:问题
我正在使用一些相当大的数组(从数千万个浮点数及以上)实现和改进优化算法,并主要使用 C 语言中的英特尔 MKL(不是 C++,至少目前不是)来挤出每一个可能的表现。现在我遇到了一个愚蠢的问题——我有一个参数可以为一组(数千万)系数的子集设置最大值和最小值。实际上,使用 MKL 函数应用这些最大值和最小值很容易——我可以为每个元素创建具有限制的大小相等的向量,并使用 V?Fmax 和 V?Fmin 来应用它们。但我还需要在我的错误度量中考虑这种剪裁,这需要我计算超出这些限制的元素数量。
但是,我找不到一个 MKL 函数,它可以让我做一些事情,比如计算满足某些条件的元素的数量,你可以创建和求和逻辑数组的方式,例如Python 或 MATLAB 中的 NumPy。令人恼火的是,当我尝试用谷歌搜索这个问题时,我只能得到与 Python 和 R 相关的答案。
显然,我可以编写一个循环,为满足其中一个条件的每个元素增加一个计数器,但如果有一个已经优化的实现可以让我实现这一点,我更愿意这样做,因为它的大小我的数组。
有没有人知道使用英特尔 MKL(可能使用统计工具箱或一些创造性地使用基本函数?)、类似优化的库或高度优化的方法来实现这一点的聪明方法。手动编码这个?我一直在绞尽脑汁想出一些开箱即用的方法,但我的想法是空的。
请注意,我必须能够在 C 中执行此操作,将这个任务转移到我的 Python 前端对我来说是不可行的,而且我确实有必要编写代码首先是 C 语言中的这个特殊子程序。
谢谢!
【问题讨论】:
如果您使用使用 c++,算法库中的count_if 执行策略为par_unseq
可以并行化和矢量化计数。至少在 Linux 上,它通常使用 Intel TBB 来执行此操作。
在 c 中不太可能那么容易。因为 c 没有可调用对象或 lambdas 之类的概念,所以专门化泛型(库提供)count()
-函数的唯一方法是将函数指针作为回调传递(就像 qsort()
那样)。除非编译器设法对回调进行去虚拟化和内联,否则您根本无法进行矢量化,从而为您留下(可能是线程并行化的)标量代码。 OTOH,如果您使用例如 gcc 向量内在函数(我最喜欢的!),您将获得向量化但不会并行化。您可以尝试结合这些方法,但我会说克服自己并使用 c++
如果你只需要向量化,你几乎可以肯定只写顺序代码并让编译器自动向量化,除非应该计算的谓词写得不好,或者你的编译器脑残。
对于example。如果至少 sse4 指令可用 (-msse4
),gcc 会在 x86 上对代码进行矢量化。使用 AVX[2/512] (-mavx / -max2 / -mavx512f
),您可以获得更宽的向量来一次处理更多元素。一般来说,如果您在运行程序的同一硬件上进行编译,我建议让 gcc 自动检测最佳指令集扩展 (-march=native
)。
除了@EOF 的建议,我强烈建议将钳位与计数结合起来。在您的情况下,这将导致每个元素向量进行 3 次读取和 1 次写入(而不是 7 次读取和 2 次写入,当独立执行这些步骤时)。
【参考方案1】:
如果您使用的是 c++,算法库中的 count_if 执行策略为 par_unseq
可能会并行化和矢量化计数。至少在 Linux 上,它通常使用 Intel TBB 来执行此操作。
在 c 中不太可能那么容易。因为 c 没有模板、可调用对象或 lambda 等概念,所以专门化泛型(库提供)count()
-function 的唯一方法是将函数指针作为回调传递(就像 qsort()
那样)。除非编译器设法对回调进行去虚拟化和内联,否则您根本无法进行矢量化,从而为您留下(可能是线程并行化的)标量代码。 OTOH,如果您使用例如 gcc 矢量intrinsics(我最喜欢的!),您将获得矢量化而不是并行化。您可以尝试结合这些方法,但我会说克服自己并使用 c++。
但是,如果您只需要向量化,您几乎可以肯定只编写顺序代码并让编译器自动向量化,除非应该计算的谓词写得不好,或者您的编译器已损坏。
对于example。如果至少有 sse4 指令可用 (-msse4
),gcc 会将 x86 上的代码向量化。使用 AVX[2/512] (-mavx / -mavx2 / -mavx512f
),您可以获得更宽的向量以同时处理更多元素。一般来说,如果您在运行程序的同一硬件上进行编译,我建议让 gcc 自动检测最佳指令集扩展 (-march=native
)。
请注意,在提供的代码中,条件应该不使用短路或 (||
),因为如果与min
-vector 已经适用于当前元素,严重阻碍了矢量化(尽管 avx512 可能会以某种灾难性的减速方式对此进行矢量化)。
我很确定 gcc 在它为 avx512 生成的代码中几乎不是最优的,因为它可以使用 @987654334 执行 k-reg(掩码寄存器)or
在掩码寄存器中 @,但也许在 avx512 (*coughth* Peter Cordes *cough*) 方面有更多经验的人可以参与其中。
【讨论】:
【参考方案2】:MKL 不提供此类功能,但您可以尝试检查另一个性能库 - IPP,其中包含一组可能对您的情况有用的阈值功能。请参阅 IPP 开发人员参考以查看更多详细信息 - https://software.intel.com/content/www/us/en/develop/documentation/ipp-dev-reference/top/volume-1-signal-and-data-processing/essential-functions/conversion-functions/threshold.html
【讨论】:
非常感谢,我一直在研究 IPP 的 N 维重采样功能,并且可能最终会使用它,尽管现在我对深入研究一个全新的库犹豫不决。但我认为您使用过 IPP 并普遍推荐它有用吗? 是的,IPP 非常有用,因为它针对任何 IA 类型进行了高度优化。以上是关于英特尔 MKL 或一些类似的库是不是提供了一种矢量化方式来计算数组中满足 C 中某些条件的元素数量?的主要内容,如果未能解决你的问题,请参考以下文章
检测是不是在 Visual Studio 项目的属性中启用了 Intel MKL
英特尔至强融核使用的内在函数是不是比自动矢量化获得更好的性能?