C 冗余if else如何帮助优化?
我正在阅读C 冗余if else如何帮助优化?,c,numpy,if-statement,optimization,macros,C,Numpy,If Statement,Optimization,Macros,我正在阅读Python的numpy库的源代码,并找到以下代码片段。它似乎对向量执行元素操作(numpy.ndarray)。例如,numpy.multiply([1,2,3],[4,5,6])将得到结果[4,10,18] #define BASE_UNARY_LOOP(tin, tout, op) \ UNARY_LOOP { \ const tin in = *(tin *)ip1; \ tout * out = (tout *)op1; \
Python
的numpy
库的源代码,并找到以下代码片段。它似乎对向量执行元素操作(numpy.ndarray
)。例如,numpy.multiply([1,2,3],[4,5,6])
将得到结果[4,10,18]
#define BASE_UNARY_LOOP(tin, tout, op) \
UNARY_LOOP { \
const tin in = *(tin *)ip1; \
tout * out = (tout *)op1; \
op; \
}
#define UNARY_LOOP_FAST(tin, tout, op) \
do { \
/* condition allows compiler to optimize the generic macro */ \
if (IS_UNARY_CONT(tin, tout)) { \
if (args[0] == args[1]) { \
BASE_UNARY_LOOP(tin, tout, op) \
} \
else { \
BASE_UNARY_LOOP(tin, tout, op) \
} \
} \
else { \
BASE_UNARY_LOOP(tin, tout, op) \
} \
} \
while (0)
我觉得很奇怪,尤其是一元循环\u FAST
中的注释。
如果使用
if A then X else X
逻辑进行优化,这里会发生什么?如果没有更多的上下文,您无法判断numpy
代码片段可以实现什么样的优化,但它可能类似于此简化示例:
#define LOOP(op) for (int i = 0; i < n; i++) op
void f(int *a, int *b, int n, int c) {
if (c == 1) {
LOOP(a[i] += b[i] * c);
}
else {
LOOP(a[i] += b[i] * c);
}
}
#为(int i=0;i
现代的编译器可以。在上面的示例中,您可以简单地在第一个分支中编写循环(a[i]+=b[i])
,但是如果if
语句是另一个以op
为参数的宏的一部分,这是不可能的
基本思想是强制编译器为多个路径生成代码,其中一些路径具有可用于某些优化的先决条件。此剪辑来自
此特定片段为单个参数ufunc
定义循环宏,类似于np.abs
此剪辑之前的评论是
/**具有连续专门化的循环*op应该是在tin-in
上工作的代码,并且*将结果存储在tout*out
*与NPY\u GCC\u OPT\u 3结合以允许自动矢量化*应该仅在值得避免代码膨胀的情况下使用*/
ufunc
设计允许类似于np.sin(a,out=b)
的使用。显然,它告诉编译器考虑特殊的情况:<代码> tout 数组与<代码> TIN /代码>相同,如<代码> NP.Sin(A,OUT=A)
类似地,快速二进制ufunc宏允许三个数组之间的标识,np.add(a,b,out=c)
,这可以实现为c=a+b
,a+=b
,b+=a
这些时间差异表明,在
args[0]==args[1]
In [195]: a=np.ones((100,100))
In [197]: %%timeit b=np.ones((100,100))
...: np.sin(a, out=b)
1000 loops, best of 3: 343 µs per loop
In [198]: %%timeit b=np.ones((100,100))
...: np.sin(b, out=b)
1000 loops, best of 3: 279 µs per loop
同样,如果事情只需要做一次,那么为什么
do{…}while(0)代码>?@ SAMErkn DO {…}(0)是通用的并且有目的,参见。也许它告诉编译器考虑特殊的情况,其中<代码> tout 数组与<代码> TIN /代码>相同,例如<代码> NP.Sin(A,out = A)
。我认为分支本身要比乘法运算昂贵得多。但分支只执行一次。在分支后多次乘法。后一种情况下产生的时间差是否不需要malloc
新的b空间?b
在这两种情况下都是预定义的。无论如何,《纽约时报》只是暗示,而不是证明。