Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 对具有间接访问的循环进行矢量化_C_Performance_Optimization_Vectorization_Simd - Fatal编程技术网

C 对具有间接访问的循环进行矢量化

C 对具有间接访问的循环进行矢量化,c,performance,optimization,vectorization,simd,C,Performance,Optimization,Vectorization,Simd,我有下面的代码片段,它是应用程序中的一个热点。 由于向量依赖性,循环的未向量化。 是否有方法重写此循环以使其运行更快 #define NUM_KEYS (1L << 20) #define NUM_BUCKETS (1L << 10) int i,k; int shift = (1L << 11); int key_array[NUM_KEYS],key_buff[NUM_KEYS]; int bucket_ptrs[NUM_BUCKETS];

我有下面的代码片段,它是应用程序中的一个热点。 由于向量依赖性,循环的
未向量化。
是否有方法重写此循环以使其运行更快

#define  NUM_KEYS  (1L << 20)
#define  NUM_BUCKETS (1L << 10)    
int i,k;
int shift = (1L << 11);
int key_array[NUM_KEYS],key_buff[NUM_KEYS];
int bucket_ptrs[NUM_BUCKETS];

for( i=0; i<NUM_KEYS; i++ )  
{
    k = key_array[i];
    key_buff[bucket_ptrs[k >> shift]++] = k;
}

这里,第一个循环被矢量化。但总体而言,性能并没有改善。

可能让您感到头疼的是,虽然您对key_数组的访问是连续的,bucket_ptr足够小,可以放入L1,但对key_buff的访问却无处不在


不过,您所做的看起来像是基数排序中的一步。如果这就是您实际正在做的,那么您可以通过首先将存储桶的数量减少到32或64个左右,并按最重要的5或6位进行排序来获得性能。然后你有一大堆小数组,其中大部分可能适合缓存,你可以使用另一个基数排序过程对它们进行排序。

可能让你头疼的是,虽然你对key_数组的访问是顺序的,bucket_ptr足够小,可以放入L1,但你对key_buff的访问到处都是

不过,您所做的看起来像是基数排序中的一步。如果这就是您实际正在做的,那么您可以通过首先将存储桶的数量减少到32或64个左右,并按最重要的5或6位进行排序来获得性能。然后你有一大堆小数组,其中大部分可能适合缓存,你可以使用另一个基数排序过程对它们进行排序

为什么循环不能矢量化

这是因为您在此处具有非顺序内存访问:

key_buff[bucket_ptrs[k >> shift]++] = k;
bucket\u ptrs
确定访问
key\u buff
的索引。因为这些索引到处都是,所以内存访问是非顺序的

目前,x86处理器仅支持将SIMD加载/存储到连续的内存块。(也是理想的对齐方式)

如果希望它矢量化,则需要AVX2的聚集/分散指令。这些都不存在,但应该在下一代英特尔处理器中出现

这里,第一个循环被矢量化。但总的来说没有 业绩的改善

这是因为您正在添加额外的循环开销。因此,您现在对
键数组进行了两次传递。如果有什么不同的话,我很惊讶它没有变慢

是否有方法重写此循环以使其运行更快

#define  NUM_KEYS  (1L << 20)
#define  NUM_BUCKETS (1L << 10)    
int i,k;
int shift = (1L << 11);
int key_array[NUM_KEYS],key_buff[NUM_KEYS];
int bucket_ptrs[NUM_BUCKETS];

for( i=0; i<NUM_KEYS; i++ )  
{
    k = key_array[i];
    key_buff[bucket_ptrs[k >> shift]++] = k;
}
我怀疑它——至少不改变算法。至少,您希望
key\u buff
能够舒适地放入一级缓存中

AVX2会让它矢量化,但问题是
key\u buff
是4MB。这不适合放在较低级别的缓存中。因此,即使是AVX2也可能没有多大帮助。您将完全被内存访问绑定

为什么循环不能矢量化

这是因为您在此处具有非顺序内存访问:

key_buff[bucket_ptrs[k >> shift]++] = k;
bucket\u ptrs
确定访问
key\u buff
的索引。因为这些索引到处都是,所以内存访问是非顺序的

目前,x86处理器仅支持将SIMD加载/存储到连续的内存块。(也是理想的对齐方式)

如果希望它矢量化,则需要AVX2的聚集/分散指令。这些都不存在,但应该在下一代英特尔处理器中出现

这里,第一个循环被矢量化。但总的来说没有 业绩的改善

这是因为您正在添加额外的循环开销。因此,您现在对
键数组进行了两次传递。如果有什么不同的话,我很惊讶它没有变慢

是否有方法重写此循环以使其运行更快

#define  NUM_KEYS  (1L << 20)
#define  NUM_BUCKETS (1L << 10)    
int i,k;
int shift = (1L << 11);
int key_array[NUM_KEYS],key_buff[NUM_KEYS];
int bucket_ptrs[NUM_BUCKETS];

for( i=0; i<NUM_KEYS; i++ )  
{
    k = key_array[i];
    key_buff[bucket_ptrs[k >> shift]++] = k;
}
我对此表示怀疑——至少在不改变算法的情况下是这样。至少,您希望
key\u buff
能够舒适地放入一级缓存中


AVX2会让它矢量化,但问题是
key\u buff
是4MB。这不适合放在较低级别的缓存中。因此,即使是AVX2也可能没有多大帮助。您将完全被内存访问绑定。

Man。。首先对其进行分析,找出瓶颈所在。然后优化。为什么猜测?不,它是不可矢量化的,因为内存访问不是连续的。您需要AVX2的收集/分散指令。我相信,明年将推出的英特尔Haswell处理器中也会出现这种情况。我的第二种循环拆分方法没有任何改进。在这种方法中,第一个循环被矢量化。因此,我期望获得一些性能提升。这可能是因为非顺序访问非常昂贵,它会淹没其他所有内容(例如额外的循环开销)。第二种方法会带来伤害,因为您正在进行额外的缓存活动。我不太相信即使使用AVX2指令,您也能使代码更快,因为对
key\u buff
的访问的局部性很差。。首先对其进行分析,找出瓶颈所在。然后优化。为什么猜测?不,它是不可矢量化的,因为内存访问不是连续的。您需要AVX2的收集/分散指令。我相信,明年将推出的英特尔Haswell处理器中也会出现这种情况。我的第二种循环拆分方法没有任何改进。在这种方法中,第一个循环被矢量化。因此,我期望获得一些性能提升。这可能是因为非顺序访问非常昂贵,它会淹没其他所有内容(例如额外的循环开销)。第二种方法会带来伤害,因为您正在进行额外的缓存活动。即使使用AVX2指令,我也不太相信您会使代码更快,因为对
key\u buff
的访问的局部性很差。