热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何实现高效的_mm256_madd_epi8?

如何解决《如何实现高效的_mm256_madd_epi8?》经验,为你挑选了1个好方法。

英特尔提供了一个名为_mm256_madd_epi16的C风格函数,基本上就是这样

__m256i _mm256_madd_epi16(__ m256i a,__ m256i b)

在a和b中多次打包有符号的16位整数,产生中间带符号的32位整数.水平添加相邻的中间32位整数对,并将结果打包为dst.

现在我有两个__m256i变量,每个变量都有32个8位int.

我想实现_mm256_madd_epi16与之相同的功能,但结果__m256i中的每个int32_t元素是四个signed char产品总和,而不是两对signed int16_t.

我可以在标量循环中做到这一点:

  alignas(32) uint32_t res[8];
  for (int i = 0; i <32; ++i)
      res[i / 4] += _mm256_extract_epi8(a, i) * _mm256_extract_epi8(b, i);
  return _mm256_load_si256((__m256i*)res);

请注意,乘法结果在添加之前是符号扩展的int,并且_mm256_extract_epi8辅助函数1 返回signed__int8.没关系总数uint32_t而不是int32_t; 无论如何它只能添加四个8x8 => 16位数字才能溢出.

它看起来非常难看,并且不能高效运行,除非编译器使用SIMD做一些魔术,而不是编写为标量提取.


脚注1: _mm256_extract_epi8不是内在的. vpextrb仅适用于256位向量的低通道,此辅助函数可能允许索引不是编译时常量.



1> Peter Cordes..:

如果您知道其中一个输入始终为非负数,则可以使用pmaddubsw; 8-> 16位相当于pmaddwd.如果总和溢出,它会将饱和度写入16位,这是可能的,所以如果这对您的情况有问题,您可能需要避免它.

但除此之外,您可以pmaddubsw手动将16位元素签名扩展为32并添加它们.或者使用pmaddwd针对_mm256_set1_epi16(1)于HSUM对与迹象正确处理元素.


显而易见的解决方案是将输入字节解压缩为具有零或符号扩展的16位元素.然后你可以使用pmaddwd两次,并添加结果.

如果您的输入来自内存,加载它们vpmovsxbw可能有意义.例如

__m256i a = _mm256_cvtepi8_epi16(_mm_loadu_si128((const __m128i*)&arr1[i]);
__m256i b = _mm256_cvtepi8_epi16(_mm_loadu_si128((const __m128i*)&arr2[i]);

但是现在你有4个字节要分散在两个 dword中,所以你必须改变一个结果_mm256_madd_epi16(a,b).您可以使用vphaddd随机播放并将两个256位的产品向量添加到您想要的一个256位向量结果中,但这是很多改组.

相反,我认为我们希望从每个256位输入向量生成两个256位向量:一个在每个字中的高字节符号扩展为16,另一个用低字节符号扩展.我们可以做3班(每个输入)

 __m256i a = _mm256_loadu_si256(const  __m256i*)&arr1[i]);
 __m256i b = _mm256_loadu_si256(const  __m256i*)&arr2[i]);

 __m256i a_high = _mm256_srai_epi16(a, 8);     // arithmetic right shift sign extends
     // some compilers may only know the less-descriptive _mm256_slli_si256 name for vpslldq
 __m256i a_low =  _mm256_bslli_epi128(a, 1);   // left 1 byte = low to high in each 16-bit element
         a_low =  _mm256_srai_epi16(a_low, 8); // arithmetic right shift sign extends

    // then same for b_low / b_high

 __m256i prod_hi = _mm256_madd_epi16(a_high, b_high);
 __m256i prod_lo = _mm256_madd_epi16(a_low, b_low);

 __m256i quadsum = _m256_add_epi32(prod_lo, prod_hi);

作为vplldq1字节的替代,vpsllw8位__m256i a_low = _mm256_slli_epi16(a, 8);是在每个单词内从低到高移位的更"明显"的方式,如果周围的代码在混洗中出现瓶颈可能会更好.但通常情况会更糟,因为这个代码在shift + vec-int上存在很大的瓶颈.

在KNL上,你可以使用AVX512 vprold z,z,i(Agner Fog没有显示AVX512的时序vpslld z,z,i),因为你移动或随机播放到每个字的低字节无关紧要; 这只是算术右移的设置.

执行端口瓶颈:

Haswell仅在端口0上运行向量移位和向量整数乘法,因此这严重阻碍了它.(Skylake更好:p0/p1). http://agner.org/optimize/.

我们可以使用shuffle(端口5)而不是左移作为算术右移的设置.这通过减少资源冲突来提高吞吐量甚至减少延迟.

但是我们可以通过使用vpslldq矢量字节移位来避免shuffle控制向量.它仍然是一个通道内的shuffle(在每个通道的末尾以零的形式移动),因此它仍然具有单周期延迟.(我的第一个想法是vpshufb使用控制向量14,14, 12,12, 10,10, ...,然后vpalignr,我记得那个简单的旧pslldq版本有一个AVX2版本.同一条指令有两个名字.我喜欢_mm256_bslli_epi128因为bfor byte-shift将它区分为shuffle,不像内部 - 元素位移.我没有检查哪个编译器支持内核的128位或256位版本的名称.)

这也有助于AMD Ryzen.矢量移位仅在一个执行单元(P2)上运行,但是随机播放可以在P1或P2上运行.

我没有看过AMD Ryzen执行端口冲突,但我很确定在任何CPU上都不会更糟(除了KNL Xeon Phi,其中AVX2操作小于dword的元素都非常慢).换档和车道内混音是相同的uop数和相同的延迟.

如果任何元素已知非负,则sign-extend = zero-extend

零扩展比手动符号扩展便宜,并避免端口瓶颈. a_low和/或b_low可以创建_mm256_and_si256(a, _mm256_set1_epi16(0x00ff)).

a_high和/或b_high可以用shuffle而不是shift来创建.(pshufb当混洗控制向量的高位设置时,将元素归零).

 const _mm256i pshufb_emulate_srl8 = _mm256_set_epi8(
               0x80,15, 0x80,13, 0x80,11, ...,
               0x80,15, 0x80,13, 0x80,11, ...);

 __m256i a_high = _mm256_shuffle_epi8(a, pshufb_emulate_srl8);  // zero-extend

在主流英特尔上,随机播放吞吐量也限制为每时钟1个,因此如果您过度使用,可能会出现混乱的瓶颈.但至少它与乘法的端口不同.如果只有高字节被称为非负,替换vpsra/lwvpshufb能有所帮助.未对齐的加载使得那些高字节是低字节可能更有帮助,设置vpandfor a_low和/或b_low.


pmaddubsw:我认为如果至少有一个输入是非负的(因此可以视为无符号),这是可用的

它将一个输入视为有符号,另一个视为无符号,并且i8 x u8 => i16,然后添加水平对以产生16位整数(带有符号饱和,因为总和可能会溢出.这也可能会将其排除在外以供您使用-案件).

但可能只是使用它然后添加水平对与pmaddwd常量1:

__m256i sum16 = _mm256_maddubs_epi16(a, b);
__m256i sum32 = _mm256_madd_epi16(sum16, _mm256_set1(1));

(pmaddwd对于水平16 => 32位总和可能比shift /和/ add更高的延迟,但确实将所有内容视为已签名.而且它只是一个uop,因此它对吞吐量有利.)


推荐阅读
  • 在2022年,随着信息化时代的发展,手机市场上出现了越来越多的机型选择。如何挑选一部适合自己的手机成为了许多人的困扰。本文提供了一些配置及性价比较高的手机推荐,并总结了选择手机时需要考虑的因素,如性能、屏幕素质、拍照水平、充电续航、颜值质感等。不同人的需求不同,因此在预算范围内找到适合自己的手机才是最重要的。通过本文的指南和技巧,希望能够帮助读者节省选购手机的时间。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • 本文记录了作者对x265开源代码的实现与框架进行学习与探索的过程,包括x265的下载地址与参考资料,以及在Win7 32 bit PC、VS2010平台上的安装与配置步骤。 ... [详细]
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
author-avatar
简单d-e独白
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有