了解 For 循环的每个元素的循环数
Understanding Cycles Per Element for For Loops
我(模糊地)理解每条指令的周期数 (CPI) 和每周期指令数 (IPC) 的含义。 CPI 是执行程序所需的时钟周期数除以程序执行的指令数运行。另一方面,IPC 是 运行 执行程序时执行的指令数除以执行程序所需的时钟周期数。
但是,当与循环关联时,我无法理解每个元素的循环数是什么意思。
例如,在下面的代码中,
void combine4(vec_ptr v, data_t *dest) {
long i;
long length = vec_length(v);
data_t *d = get_vec_start(v);
data_t t = IDENT;
for (i = 0; i < length; i++)
t = t OP d[i];
*dest = t;
}
我们可以通过改变for循环的方式来进行多重优化
一种方法称为循环展开
/* Combine 2 elements at a time */
for (i = 0; i < limit; i += 2) {
x = (x OP d[i]) OP d[i + 1];
}
/* Finish any remaining elements */
for (; i < length; i++) {
x = x OP d[i];
}
为了进一步改进它,我们可以在数组访问周围加上括号。
x = x OP (d[i] OP d[i + 1]);
我相信我们开始计算下一个循环的信息是因为我们没有相关数据。术语 CPE 如何应用于此优化? CPE会下降吗?因为 运行 通过所有元素需要更少的周期?
Cycles Per Element 是指当您迭代数组、向量或其他元素容器时,循环每次迭代的 CPU 周期数的术语。对于 combine4()
,您将测量 运行 整个 for
循环所需的 CPU 循环总数,并将其除以 length
得到CPE.
如今的编译器非常擅长优化代码,例如,它们可能会自动展开或向量化循环。他们还可以改变操作的执行顺序,利用指令时序和其他微架构细节的知识来产生最佳的指令序列,只要它能证明这种重新排序不会改变最终结果。因此,手动更改可能无法达到您预期的效果。除了对您的更改进行基准测试外,您还应该查看编译器的汇编输出以查看它生成的机器代码类型。当然不要忘记启用编译器优化。 https://godbolt.org/.
是一个很好的基于 Web 的工具来执行此操作
(您的代码示例来自教科书《计算机系统:程序员的视角》。)
这里每个元素的循环数是一个更高级别的指标。与测量 CPI 或 IPC 不同,对示例循环重要的实际单位是向量的元素。因此,在 运行 跨越数百或数千个元素并测量整个执行所需的循环的循环中,我们可以绘制结果测量值并计算斜率(即每个元素的循环数)。
括号的移动改变了操作的关联,从而使两个数据元素的OP独立。如果有足够的硬件资源来执行额外的独立操作,这可以提高循环的 CPE。
结论应该是,即使对代码进行简单的更改也很难确定是否会缩短执行时间,因为它依赖于系统的所有部分。通常,程序员应该依靠编译器及其出色的优化来获得良好的性能,而无需求助于细粒度调整。
我(模糊地)理解每条指令的周期数 (CPI) 和每周期指令数 (IPC) 的含义。 CPI 是执行程序所需的时钟周期数除以程序执行的指令数运行。另一方面,IPC 是 运行 执行程序时执行的指令数除以执行程序所需的时钟周期数。
但是,当与循环关联时,我无法理解每个元素的循环数是什么意思。
例如,在下面的代码中,
void combine4(vec_ptr v, data_t *dest) {
long i;
long length = vec_length(v);
data_t *d = get_vec_start(v);
data_t t = IDENT;
for (i = 0; i < length; i++)
t = t OP d[i];
*dest = t;
}
我们可以通过改变for循环的方式来进行多重优化
一种方法称为循环展开
/* Combine 2 elements at a time */
for (i = 0; i < limit; i += 2) {
x = (x OP d[i]) OP d[i + 1];
}
/* Finish any remaining elements */
for (; i < length; i++) {
x = x OP d[i];
}
为了进一步改进它,我们可以在数组访问周围加上括号。
x = x OP (d[i] OP d[i + 1]);
我相信我们开始计算下一个循环的信息是因为我们没有相关数据。术语 CPE 如何应用于此优化? CPE会下降吗?因为 运行 通过所有元素需要更少的周期?
Cycles Per Element 是指当您迭代数组、向量或其他元素容器时,循环每次迭代的 CPU 周期数的术语。对于 combine4()
,您将测量 运行 整个 for
循环所需的 CPU 循环总数,并将其除以 length
得到CPE.
如今的编译器非常擅长优化代码,例如,它们可能会自动展开或向量化循环。他们还可以改变操作的执行顺序,利用指令时序和其他微架构细节的知识来产生最佳的指令序列,只要它能证明这种重新排序不会改变最终结果。因此,手动更改可能无法达到您预期的效果。除了对您的更改进行基准测试外,您还应该查看编译器的汇编输出以查看它生成的机器代码类型。当然不要忘记启用编译器优化。 https://godbolt.org/.
是一个很好的基于 Web 的工具来执行此操作(您的代码示例来自教科书《计算机系统:程序员的视角》。)
这里每个元素的循环数是一个更高级别的指标。与测量 CPI 或 IPC 不同,对示例循环重要的实际单位是向量的元素。因此,在 运行 跨越数百或数千个元素并测量整个执行所需的循环的循环中,我们可以绘制结果测量值并计算斜率(即每个元素的循环数)。
括号的移动改变了操作的关联,从而使两个数据元素的OP独立。如果有足够的硬件资源来执行额外的独立操作,这可以提高循环的 CPE。
结论应该是,即使对代码进行简单的更改也很难确定是否会缩短执行时间,因为它依赖于系统的所有部分。通常,程序员应该依靠编译器及其出色的优化来获得良好的性能,而无需求助于细粒度调整。