c - 索引内存指针数组与 ANSI C 中的间接整数索引数组

标签 c pointers gcc indexing

声明

a[i] += a[j] * a[k];

会在一个可能执行几千到几百万次的循环中执行几千次。索引 ijk 表示对 a 中条目的随机访问,可以通过语句设置

i = i_index[l];
j = j_index[l];
k = k_index[l];

其中 lfor 循环的索引。整数数组 i_indexj_indexk_index 在程序开始时设置,可能会偶尔更改。

内存指针数组是另一种选择。例如

*ap1[l] += *ap2[l] * (*ap3[l]);

其中内存指针数组ap1ap2ap3是预先设置的,指向最初由i_indexj_indexk_index 数组。它们也可能会偶尔更改。

第一种方法看起来比第二种方法更干净,但它似乎更慢,除非有某种方法可以向编译器提供额外的信息。 XCode 中的 GCC 编译器似乎无法提前发现 i_indexj_indexk_indexap1ap2ap3 大多数时候是不变的。有什么方法可以提醒 gcc 编译器提高性能?

最佳答案

您不太可能找到一个选项让编译器有效地缓存您显式计算并保存在第二个版本代码中的第一个版本代码中的指针值。这是因为编译器需要发出代码来生成和保存一个非常大的数据结构来缓存这些值,这不是典型的编译器行为。

但是,根据您的目标架构,这可能无关紧要。许多体系结构具有“间接基+索引”寻址模式,这将用于访问 a[i] += a[j] * a[k] 中的 a ;,并且在现代内核上,这些与普通的“间接”寻址模式相比没有任何性能损失(即 - 一条指令将 i 乘以 a 的大小[0],将其添加到a 的基地址并解引用结果)。分析您的目标架构并查看。

对于任何一个版本,可能都可以改进的一件事是使用一个 struct 数组而不是三个单独的数组,以便l 的每个值都连续保存在内存中:

i = index[l].i;
j = index[l].j;
k = index[l].k;

*ap[l].i += *ap[l].j * *ap[l].k;

这意味着您的代码正在通过 indexap 数组进行一次线性遍历,而不是同时进行三次线性遍历,这应该有助于预取器识别什么你在做什么。

关于c - 索引内存指针数组与 ANSI C 中的间接整数索引数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10875071/

相关文章:

c - 指针未初始化的问题

c++ - 如何在 Windows 上为 NetBeans 和 gcc 添加库包含路径?

gcc - 如何#define __forceinline 内联?

gcc - 在64位环境下执行32位目标文件

c - C 数组的对齐方式 - 数组元素的对齐方式大于元素大小

c - 彼得森的等待解决方案

c - 如何用C读取X86命中未命中缓存寄存器

wordpress - 如何创建基本的 WordPress 管理指针?

c++ - 如何访问在当前函数范围之外创建的动态创建的对象?

c - 一个地址怎么可以有多个值呢?