如何为给定C语言矩阵操作代码实现memory blocking缓存优化
优化思路
- 原代码的访问瓶颈:你用到的数组是行优先存储的二维方阵,访问
i * dimension + j是连续的行访问,空间局部性好,但访问j * dimension + i是步长为dimension的列访问,当dimension远大于缓存行大小时,会频繁触发缓存失效。 - 你之前的优化利用了矩阵对称特性减少了一半计算量,确实有性能提升,但没有解决大维度下列访问跨度过大的缓存命中率低的问题。
- Cache blocking的核心逻辑是把大矩阵切割为B×B的小分块,B的取值通常参考CPU L1缓存大小调整(常用值为32、64,保证单个分块的所有数据可以装入L1缓存),每次仅处理一个分块内的元素,让分块内的数据被多次复用,大幅提升时间和空间局部性。
带Cache Blocking的优化代码
// 块大小可根据CPU L1缓存实际大小调整,常用取值为32或64 #define BLOCK_SIZE 32 void randFunction1(int *arrayb, int dimension) { // 外层遍历分块的行起始索引 for (int ii = 0; ii < dimension; ii += BLOCK_SIZE) { // 外层遍历分块的列起始索引 for (int jj = 0; jj < dimension; jj += BLOCK_SIZE) { // 计算当前分块的实际边界,处理dimension不是BLOCK_SIZE整数倍的情况 int i_bound = (ii + BLOCK_SIZE < dimension) ? (ii + BLOCK_SIZE) : dimension; int j_bound = (jj + BLOCK_SIZE < dimension) ? (jj + BLOCK_SIZE) : dimension; // 内层处理当前B×B分块内的元素 for (int i = ii; i < i_bound; ++i) { // 兼容你之前的对称优化逻辑,避免重复计算对角区域 int j_start = (jj > i) ? jj : i; for (int j = j_start; j < j_bound; ++j) { int idx_ji = j * dimension + i; int idx_ij = i * dimension + j; arrayb[idx_ji] = arrayb[idx_ji] || arrayb[idx_ij]; arrayb[idx_ij] = arrayb[idx_ij] || arrayb[idx_ji]; } } } } }
调优建议
- 可以根据部署环境的CPU缓存大小调整
BLOCK_SIZE的取值:比如L1数据缓存为32KB的场景下,4字节的int单块最大可放8192个元素,BLOCK_SIZE取32的话单个分块仅1024个元素,完全可以装入L1缓存,命中率最高。 - 编译时开启-O2及以上优化等级,编译器会自动完成循环展开、指令重排等额外优化,进一步提升运行效率。
内容的提问来源于stack exchange,提问作者Megan Darcy
相关产品推荐
相关产品推荐

