我有2个阵列的16个元素(chars),我需要"比较",并看到如何的许多要素是平等这两者之间。

这个程序是要被使用的数以百万计的时间(一个常运行是大约60或70万次),所以我需要尽可能快。我的工作C++(C++生成器2007年,为了记录在案)

现在,我有一个简单的:

matches += array1[0] == array2[0];

重复16次(为分析这似乎是30%的速度比它为循环)

是否有任何其他方式,可以工作得更快?

一些数据有关的环境和数据本身:

  • 我是用C++建设者,它没有任何速度的优化,以考虑。我会尝试最终的另一个编译器,但是现在我被困的这一个。
  • 数据将不同的大部分时间。100%的同等数据通常是非常非常罕见的(可能低于1%)
有帮助吗?

解决方案

更新:这个答案已经修改,以使我的意见相匹配的源代码,下文提供。

有一个优化可如果你有能力使用SSE2和popcnt说明。

16字节发生于非常适合在一个SSE登记册。使用c++和组件/内部函数,装载两16字节的数组成xmm寄存器,和《议定书》。这产生一位代表true/false状况的比较。你再使用movmsk指令载的一位代表的位成x86登记册;然后,这变得有点领域里,你可以指望所有的1是确定如何许多的真正价值你了。硬件popcnt指令可以是一个快速的方式来计算所有的1在登记册。

这要求知识的组件/内部函数和SSE尤其如此。你应该能够找到网资源。

如果你跑这个代码的计算机上不支持SSE2或popcnt,你必须再循环的阵列数的差异与你展开循环的方法。

祝你好运

编辑:因为你表示你不知道会这里的一些样品代码为了说明我的回答:

#include "stdafx.h"
#include <iostream>
#include "intrin.h"

inline unsigned cmpArray16( char (&arr1)[16], char (&arr2)[16] )
{
    __m128i first = _mm_loadu_si128( reinterpret_cast<__m128i*>( &arr1 ) );
    __m128i second = _mm_loadu_si128( reinterpret_cast<__m128i*>( &arr2 ) );

    return _mm_movemask_epi8( _mm_cmpeq_epi8( first, second ) );
}

int _tmain( int argc, _TCHAR* argv[] )
{
    unsigned count = 0;
    char    arr1[16] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 };
    char    arr2[16] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 };

    count = __popcnt( cmpArray16( arr1, arr2 ) );

    std::cout << "The number of equivalent bytes = " << count << std::endl;

    return 0;
}

一些注意事项:这种功能使用SSE2说明和popcnt指令引入飞鸿处理(也就是机器那我使用)。我相信最近的英特尔处理器SSE4还有popcnt.这个功能的不检的指令支持与CPUID;功能是不确定的,如果用于一个处理器,这并没有SSE2或popcnt(你可能会得到一个无效的操作码指令)。这检测码是一个独立的螺纹。

我还没有定时这一编码;原因我认为这是快是因为它比较16字节的时间,无网点.你应该修改,以适应环境,及时它自己,看看如果它对你的作品。我写和测试,这在VS2008SP1。

SSE喜欢的数据,对准一个自然的16字节的边界;如果你可以保证,然后你应该得到加速的改进,并且可以改变_mm_loadu_si128说明_mm_load_si128,这需要对齐。

其他提示

关键是要做的比较中使用的最大注册的CPU支持,然后回退到字节,如果有必要的。

以下代码显示了与使用4个字节的整数,但是如果你是上运行一个单指令构(任何现代的英特尔或AMD芯片),你可以比较这两个阵列中的一项指令之前下降回到一个基于整数的循环。最编译器,这些天有内在支持128位类型,因此将不需要ASM。

(注意,对于单指令comparisions你的阵列必须16字节的结盟,有的处理器(e。g MIPS)将要求该阵列可以4-byte盟int基于比较。

E.g。

int* array1 = (int*)byteArray[0];
int* array2 = (int*)byteArray[1];

int same = 0;

for (int i = 0; i < 4; i++)
{
  // test as an int
  if (array1[i] == array2[i])
  {
    same += 4;
  }
  else
  {
    // test individual bytes
    char* bytes1 = (char*)(array1+i);
    char* bytes2 = (char*)(array2+i);

    for (int j = 0; j < 4; j++)
    {
      same += (bytes1[j] == bytes2[j];
    }
  }
}

我记不起来究竟是什么MSVC编译器支持为单指令,但是你可以做一些事情等;

// depending on compiler you may have to insert the words via an intrinsic
__m128 qw1 = *(__m128*)byteArray[0];
__m128 qw2 = *(__m128*)byteArray[1];

// again, depending on the compiler the comparision may have to be done via an intrinsic
if (qw1 == qw2)
{
    same = 16;
}
else
{
    // do int/byte testing
}

如果你有能力控制的位置阵列,把一项权利之后,其他存储例如,它可能导致他们被加载到CPU的高速缓存在的第一次访问。

它取决于CPU和其缓存的结构,将改变从一个机到另一个。

你可以阅读关于记忆的层次结构和高速缓存在 Henessy&帕特森的机构:一定量的方法

如果你需要的绝对最低的足迹,我会去与会代码。我没有这样做在一段时间,但我想试试吧(或更可能SSE2/3)必须说明,可以使你能够做到的是,在非常少数的说明。

如果相匹配的共用的情况下然后试着装载的数值为32位整数而不是16所以,你可以比较2一个(以及计数为2比赛).

如果两个32位数值是 同样的,然后你会需要测试它们分开(出的顶部和底部的16位值)。

该编码将更加复杂,但应更快。

如果针对某一64位系统的你可以做同样的把戏有64位整数,如果你真的想要推动限制,然后看看在下降到的汇编和使用的各种矢量基于说明这会让你的工作与128位在一次。

神奇的编译器的选择会有所不同时间很大。特别是使其产生上证矢量化将有可能得到你一个巨大的加速比。

这必须是独立的平台,或者将这种代码一直运行在相同类型的CPU?如果你将自己局限于现代x86Cpu,你可能能够使用 试试吧 指令,应该让你来操作上的一系列8个字节在一个钟打勾。据我所知,海湾合作委员会允许你嵌入会在C码,并在英特尔的compiler(icc)支持内部函数,这是包装,允许你打电话的具体组件的说明。其他单指令的指令组,如上证,也可能是有用的。

是否有任何连接值之间的阵?一些字节更有可能是相同的,那么其他人?可能会有一些固有秩序的价值?然后你可以优化用于最可能的情况下。

如果你解释什么的数据实际上表示,则可能是一个完全不同的方式表示的数据存储,这将使这种类型的暴力比较不必要的。护理详细阐述这些数据实际上表示了??

它更快,因为一个声明吗?

matches += (array1[0] == array2[0]) + (array1[1] == array2[1]) + ...;

如果编写的,16次是快于一个简单的循环,然后编译器或吸或者你没有优化转。

简短的回答:有没有更快的方法,除非你做的矢量上的操作平行硬件。

尝试使用的指针,而不是阵列:

p1 = &array1[0];
p2 = &array2[0];
match += (*p1++ == *p2++);
// copy 15 times.

当然你必须衡量这对其他的办法看看哪些是最快的。

而你确定这个惯例是一个瓶颈在你处理?你实际上是加速性能的应用程序作为一个整体,通过优化这个吗?同样,只有测量会告诉我们。

是否有任何方法可以修改方式阵列储存的?比较1字节的时间是极其缓慢的考虑你可能是使用的一个32位编译器。相反,如果存储16字节在4整数(32-bit)或2longs(64位),你只需要执行的4个或2的比较分别。

这个问题要问问你自己是多少成本的存储数据为4-整数或2-长阵列。你经常需要访问的数据,等等。

总有美好的旧x86REPNE CMPS指令。

一个额外的可能的优化:如果你期待的大多数时间阵列是相同的,那么它可能是稍微快做memcmp()作为第一步,设置'16'作为回答,如果试验返回正确的。如果当然如果你是不是希望阵列是相同的很多时候,只会缓慢下来的东西。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top