有两个非常大的系列元素,第二个比第一个大 100 倍。对于第一个系列的每个元素,第二个系列中有 0 个或多个元素。这可以通过 2 个嵌套循环进行遍历和处理。但是第一个数组的每个成员的匹配元素数量的不可预测性使得事情变得非常非常缓慢。
第二系列元素的实际处理涉及逻辑与 (&) 和人口计数。
我找不到使用 C 的良好优化,但我正在考虑对第一个系列的每个元素进行内联 asm、rep* mov* 或类似操作,然后对第二个系列的匹配字节进行批处理,可能在缓冲区中1MB什么的。但是代码会变得非常混乱。
有人知道更好的方法吗?首选 C,但 x86 ASM 也可以。非常感谢!
为了清楚起见,带有简化问题的示例/演示代码,第一个系列是“人”,第二个系列是“事件”。(原来的问题其实是 100m 和 10,000m 条目!)
#include <stdio.h>
#include <stdint.h>
#define PEOPLE 1000000 // 1m
struct Person {
uint8_t age; // Filtering condition
uint8_t cnt; // Number of events for this person in E
} P[PEOPLE]; // Each has 0 or more bytes with bit flags
#define EVENTS 100000000 // 100m
uint8_t P1[EVENTS]; // Property 1 flags
uint8_t P2[EVENTS]; // Property 2 flags
void init_arrays() {
for (int i = 0; i < PEOPLE; i++) { // just some stuff
P[i].age = i & 0x07;
P[i].cnt = i % 220; // assert( sum < EVENTS );
}
for (int i = 0; i < EVENTS; i++) {
P1[i] = i % 7; // just some stuff
P2[i] = i % 9; // just some other stuff
}
}
int main(int argc, char *argv[])
{
uint64_t sum = 0, fcur = 0;
int age_filter = 7; // just some
init_arrays(); // Init P, P1, P2
for (int64_t p = 0; p < PEOPLE ; p++)
if (P[p].age < age_filter)
for (int64_t e = 0; e < P[p].cnt ; e++, fcur++)
sum += __builtin_popcount( P1[fcur] & P2[fcur] );
else
fcur += P[p].cnt; // skip this person's events
printf("(dummy %ld %ld)\n", sum, fcur );
return 0;
}
gcc -O5 -march=native -std=c99 test.c -o test