c - 这种指针和循环的组合有什么好处吗?
问题描述
我正在研究 Cheng 的 CUDA C Programming,并遇到了这段代码:
void sumMatrixOnHost (float *A, float *B, float *C, const int nx, const int ny) {
float *ia = A;
float *ib = B;
float *ic = C;
for (int iy=0; iy<ny; iy++) {
for (int ix=0; ix<nx; ix++) {
ic[ix] = ia[ix] + ib[ix];
}
ia += nx; ib += nx; ic += nx;
}
}
这是用于矩阵加法,其中矩阵以行优先格式存储。
据我了解,内部 for 循环遍历一行并执行元素添加,然后使用外部 for 循环将指针递增到下一行的开头。
为什么这种方法比在整个矩阵上使用指针更好,即
for (int i=0; i<ny*nx; i++) {
ic[i] = ia[i] + ib[i];
}
或双重for循环,即
for (int iy=0; iy<ny; iy++) {
for (int ix=0; ix<nx; ix++) {
ic[iy*nx+ix] = ia[iy*nx+ix] + ib[iy*nx+ix];
}
}
这与编译器如何优化它有关吗?
解决方案
最简单的方法,总是最好的方法:
for (int i=0; i<ny*nx; i++) {
C[i] = A[i] + B[i];
}
这将比第一个解决方案更快。按行拆分矩阵的问题在于矢量化器将执行以下操作:
- 32bytes批量处理线(YMM大小)
- 在行尾处理剩余的少数值。
- 现在重复每一行!
但是,如果您使用单个循环执行此操作,则生成的代码将是:
- 以 32 字节为单位处理所有数据(YMM 大小)
- 处理矩阵末尾未与 32 字节块对齐的剩余少数值。
第一个版本只是添加了无意义的代码来处理内部循环。不需要这些代码,它只是破坏了向量化整个矩阵的能力。
推荐阅读
- sql - 无法使服务器上的任何数据库联机
- apache-kafka - Kafka - 添加自定义标头以记录元数据
- angular - 错误:类型 'string' 不可分配给类型 '"body"'。在角度 8
- django - 如何允许 Django 中的用户查看来自同一模型的特定数据
- c++ - C ++从二叉树中删除所有节点
- javascript - How to parse and concatenate whit specific separator
- python - 沿xarray中的单个维度分组多个坐标
- clojurescript - 如何让 CKEditor react 组件在 ClojureScript 中可用
- xml - Azure Devops 中的 IIS Web App Deploy 无法为 .netcore 项目正确转换 web.config
- sql-server - 如何结合使用 datepart 函数和 count 函数?