Gcc增加的优化降低了Cython的执行速度



我正在使用MingW64为Python 3.7编译Cython。这项任务完全是一个例外,我正在计算一个点网格的Julia集。我正在跟随一本书;高性能Python";,这就是如何使用Cython。我之前曾使用-O标志来设置DSP硬件的优化,并通过将其设置为更高(即-O3(获得了显著的改进。但Cython代码的情况并非如此。

当对Cython代码做同样的事情时,随着优化的增加,它会稳定地产生较慢的结果,这似乎毫无意义。我得到的时间是:
-O1=0.41s
/O2=0.46s
-O3=0.47s
1-Ofast=0.48s
<-Os>2

有人知道为什么这似乎在相反的优化中起作用吗?

cython代码在文件cythonfn.pyx 中

def calculate_z(maxiter, zs, cs):
# add type primitives to improve execution time
cdef unsigned int i, n
cdef double complex z, c
output = [0] * len(zs)
for i in range(len(zs)):
n = 0
z = zs[i]
c = cs
# while n < maxiter and abs(z) < 2:
while n < maxiter and (z.real * z.real + z.imag * z.imag) < 4: # increases performance
z = z * z + c
n += 1

output[i] = n
return output

此处的设置为setup.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass={'build_ext': build_ext},
ext_modules=[Extension("calculate", ["cythonfn.pyx"])]
)

主要代码是

import calculate
import time
c_real,c_imag = -0.62772, -0.42193  # point for investigation
x1, x2, y1, y2 = -1.8, 1.8, -1.8, 1.8
def calc_julia(desired_width, max_iter):
x_step = (float(x2 - x1) / float(desired_width))
y_step = (float(y1 - y2) / float(desired_width))
x = []
y = []
ycoord = y2
while ycoord > y1:
y.append(ycoord)
ycoord += y_step
xcoord = x1
while xcoord < x2:
x.append(xcoord)
xcoord += x_step
zs = []
cs = complex(c_real, c_imag)
for ycoord in y:
for xcoord in x:
zs.append(complex(xcoord, ycoord))
st = time.time()
output = calculate.calculate_z(max_iter, zs, cs)
et = time.time()
print(f"Took {et-st} seconds")
if __name__ == '__main__':
calc_julia(desired_width=1000, max_iter=300)

是的我知道这里有很多可以改进的地方,例如cs可以只是一个标量,因为它们都是一样的。这更多的是一个练习,但它为优化带来了令人惊讶的结果。

这里似乎至少部分解释了这个问题的答案,gcc优化标志-O3使代码比-O2慢。

总结一下结果,使用-O3实际上使用了与-O2不同的比较/分支技术,因此在多次进行比较的任务中,选择如何进行比较很重要。由于循环中的可预测性,它通过使用这种优化来增加执行时间。

这仍然不能解决从-O1到-O2的原因,但这个来源足以描述一个案例。也许另一个人知道答案?

最新更新