比较一个字节数组与其他字节数组的最快方法?

时间:2014-01-17 10:35:10

标签: c algorithm assembly x86-64 sse

我有一个具有以下结构的循环:

  • 计算长度为k(某处慢)的字节数组
  • 查找计算出的字节数组是否与我拥有的N个字节数组列表中的任何一个匹配。
  • 重复

我的循环被多次调用(这是我程序的主循环),我希望第二步尽可能快。

第二步的简单实现是使用memcmp

char* calc;
char** list;
int k, n, i;
for(i = 0; i < n; i++) {
  if (!memcmp(calc, list[i], k)) {
    printf("Matches array %d", i);
  }
}

你能想到更快的方法吗?一些事情:

  • 我的列表在我的程序开始时修复,任何预计算都没问题。
  • 假设k很小(<= 64),N是中等(约100-1000)。
  • 此处是性能目标,可移植性不是问题。内在/内联装配很好,只要它更快。

以下是我的一些想法:

  • 鉴于k <64并且我在x86_64上,我可以将查找数组排序为长数组,并对其进行二进制搜索。 O(日志(N))。即使k很大,我也可以对查找数组进行排序,并使用memcmp进行二进制搜索。
  • 鉴于k很小,我可以计算一个8/16/32位校验和(最简单的是使用xor将我的数组折叠到自己的所有查找数组上)并使用内置{ {1}}与How to compare more than two numbers in parallel?一样。我知道这里有SSE4.2。

你认为去矢量化/ sse是一个好主意吗?如果是,您认为最好的方法是什么? 我想说这不是早期优化,但性能在这里至关重要,我需要外循环尽可能快。 感谢

EDIT1:看起来http://schani.wordpress.com/tag/c-optimization-linear-binary-search-sse2-simd/提供了一些有趣的想法。在PCMPGT列表上进行二进制搜索似乎是要走的路..

4 个答案:

答案 0 :(得分:7)

最佳解决方案将取决于要匹配的阵列数量,阵列的大小以及它们更改的频率。我会考虑避免进行比较。

假设要比较它的数组列表不会经常更改并且你有很多这样的数组,我会创建每个数组的哈希值,然后当你进行比较时,哈希你正在测试的东西。然后,您只需要比较哈希值。使用像SHA256这样的散列,你可以依赖它作为正指针和负指示符(即散列匹配足以说明数组匹配以及不匹配的散列足以说明数组不同)。如果您有(比方说)1,000,000个阵列进行比较而几乎没有变化,这将非常有效,因为计算哈希值将比1,000,000个阵列比较更快。

如果您的阵列数量稍微小一点,您可能会考虑使用更快的非加密哈希值。例如,简单地将数组模块256中的字节相加的“散列”(这是一个可怕的散列并且你可以做得更好)将消除比较(例如)目标数组空间的255/256的需要。然后,您可以只比较那些所谓的'哈希'匹配的那些。有很多类似哈希的东西,比如CRC-32,可以快速计算。

在任何一种情况下,您都可以通过哈希(模数X)查找以确定实际比较哪些数组。

你建议k很小,N是中等的(即大约1000)。我猜速度将围绕内存缓存。不在这里访问1,000个小阵列将非常有帮助。

如果阵列的变化频率与比较相似,那么以上所有内容都将毫无用处。

添加(假设您正在查看64字节或类似字节)。我会研究一个非常快速的非加密哈希函数。例如,请查看:https://code.google.com/p/smhasher/wiki/MurmurHash3

每32位字看起来像3-4个指令来生成哈希。然后,您可以将结果截断为(例如)12位,用于4096条目哈希表,冲突很少(每个桶都链接到目标数组)。这意味着您将查看大约30条指令来计算哈希值,然后查看每个桶条目的一条指令(期望值1)以查找列表项,然后按预期命中(即介于0和1之间)进行一次手动比较。因此,不是比较1000个数组,而是比较0和1个数组,并生成一个哈希。如果你不能比较30个指令中的999个阵列(我猜不是!),这显然是一个胜利。

答案 1 :(得分:2)

  

我们可以假设我的东西适合64位,甚至32位。如果它   不是,我可以哈希它,所以它可以。但现在,最快的方法是什么   查找我的哈希是否存在于预先计算的哈希值列表中?

这是一种元回答,但是......如果你的问题归结为:如何有效地找出某个32位数字是否存在于其他32位数字的列表中,这是一个问题IP路由器一直处理,因此可能值得研究网络文献,看看是否有一些东西可以从他们的算法中适应。例如见http://cit.mak.ac.ug/iccir/downloads/SREC_07/K.J.Poornaselvan1,S.Suresh,%20C.Divya%20Preya%20and%20C.G.Gayathri_07.pdf

(虽然,我怀疑它们已针对搜索大量项目进行了优化,而不是用例...)

答案 2 :(得分:0)

你可以做一个XOR而不是memcmp吗?

或对数组中每个元素进行caclulate哈希并对其进行排序以搜索哈希

但哈希会花费更多时间。除非你能提出更快的哈希

答案 3 :(得分:0)

另一种方法是从列表中预构建树并使用树搜索 例如,列表:

aaaa
aaca
acbc
acca
bcaa
bcca
caca

我们可以得到这样的树

root
-a
--a
---a
----a
---c
----a
--c
---b
----c
---c
----a
-b
--c
---a
----a
---c
----a
-c
--a
---c
----a

然后在树的每个级别进行二元搜索