ARMv7+NEON 快速正弦/余弦:寻找测试人员...

15

请有 iPhone 3GS 或 Pandora 访问权限的人测试我刚刚编写的以下汇编程序吗?

它应该能够在 NEON 向量 FPU 上非常快地计算正弦和余弦。我知道它可以编译,但没有足够的硬件来测试。如果您只能计算几个正弦和余弦,并将结果与 sinf() 和 cosf() 的结果进行比较,那将非常有帮助。

谢谢!

#include <math.h>

/// Computes the sine and cosine of two angles
/// in: angles = Two angles, expressed in radians, in the [-PI,PI] range.
/// out: results = vector containing [sin(angles[0]),cos(angles[0]),sin(angles[1]),cos(angles[1])]
static inline void vsincos(const float angles[2], float results[4]) {
    static const float constants[]  = { 
    /* q1 */  0,                M_PI_2,           0,                M_PI_2,
    /* q2 */  M_PI,             M_PI,             M_PI,             M_PI,
    /* q3 */  4.f/M_PI,         4.f/M_PI,         4.f/M_PI,         4.f/M_PI,
    /* q4 */ -4.f/(M_PI*M_PI), -4.f/(M_PI*M_PI), -4.f/(M_PI*M_PI), -4.f/(M_PI*M_PI),
    /* q5 */  2.f,              2.f,              2.f,              2.f,
    /* q6 */  .225f,            .225f,            .225f,            .225f
    };  
    asm volatile(
        // Load q0 with [angle1,angle1,angle2,angle2]
        "vldmia %1, { d3 }\n\t"
        "vdup.f32 d0, d3[0]\n\t"
        "vdup.f32 d1, d3[1]\n\t"
        // Load q1-q6 with constants
        "vldmia %2, { q1-q6 }\n\t"
        // Cos(x) = Sin(x+PI/2), so
        // q0 = [angle1, angle1+PI/2, angle2, angle2+PI/2]
        "vadd.f32 q0,q0,q1\n\t"
        // if angle1+PI/2>PI, substract 2*PI
        // q0-=(q0>PI)?2*PI:0
        "vcge.f32 q1,q0,q2\n\t"
        "vand.f32 q1,q1,q2\n\t"
        "vmls.f32 q0,q1,q5\n\t"
        // q0=(4/PI)*q0 - q0*abs(q0)*4/(PI*PI)
        "vabs.f32 q1,q0\n\t"
        "vmul.f32 q1,q0,q1\n\t"
        "vmul.f32 q0,q0,q3\n\t"
        "vmul.f32 q1,q1,q4\n\t"
        "vadd.f32 q0,q0,q1\n\t"
        // q0+=.225*(q0*abs(q0) - q0)
        "vabs.f32 q1,q0\n\t"
        "vmul.f32 q1,q0,q1\n\t"
        "vsub.f32 q1,q0\n\t"
        "vmla.f32 q0,q1,q6\n\t"
        "vstmia %0, { q0 }\n\t"
        :: "r"(results), "r"(angles), "r"(constants)
        : "memory","cc","q0","q1","q2","q3","q4","q5","q6"
    );  
}

只是好奇——你使用了什么算法来快速计算正弦和余弦? - gahooa
如果您添加一个测试程序,我可以在我的BeagleBoard上运行它。同样的CPU。 - Nils Pipenbrinck
@gahooa:我使用Nicolas Capens在http://www.devmaster.net/forums/showthread.php?t=5784上描述的方法,以及cos(x)=sin(x+90°)这个事实。 - jcayzac
2个回答

10

我已在我的beagleboard上进行了测试,正如评论中所说:使用相同的CPU。

您的代码大约比C库快15倍。做得好!

我测量了每次调用您的实现需要82个周期,而调用四个C库则需要1260个周期。请注意,我是使用软浮点ABI进行编译的,而我的OMAP3是早期硅片,因此每次调用C库版本都至少有40个周期的NEON停顿。

我将结果压缩在一起。

http://torus.untergrund.net/code/sincos.zip

性能计数器的内容可能无法在iPhone上运行。

希望这就是您一直在寻找的信息。


非常感谢你,尼尔斯。实际上,我有点惊讶它可以直接使用 :-) 对于VFP11实现的相同方法,其速度仅比在我的iPod Touch上调用sinf()+cosf()快两倍左右,因此我使用了查找表。 - jcayzac
啊,我从你的测试程序中看到,你使用了libc函数的双精度变量(sin()/cos(),而不是sinf()/cosf())。这就解释了为什么libc函数表现得如此糟糕了,我想 :-) - jcayzac
刚刚使用sinf/cosf编译并运行了它,但并没有太大的区别。 - Nils Pipenbrinck
你的意思是,与使用sin()/cos()进行测试相比,使用sinf()/cosf()几乎没有差异,或者说我的函数与libc的速度几乎没有差异? - jcayzac
sin和sinf之间没有太大的区别(cos同理)。我测量了双精度版本的每次迭代1260个周期/迭代,而浮点版本的每次迭代为1245个周期/迭代。我敢打赌这是相同的代码,我们只是省略了从双精度到浮点数的转换。 - Nils Pipenbrinck
在编译时使用软浮点就像没有浮点硬件运行它一样。所有的浮点操作都是用整数算术指令模拟的,这可能会导致性能差10倍。 - Sogartar

3

是的,我知道这些函数。我希望有一部iPhone 3GS来玩NEON,这肯定比在我的iPod的VFP11上工作更有趣。随着iPhone的出现,FPU热潮开始了,但在此之前的规则是:不要使用浮点数,使用定点数。我开始认为那些使用浮点数编码iPhone的人是错的。ARM在整数方面非常出色,而设置浮点寄存器的开销很大。 - jcayzac
事实上,我知道另一个相关的项目,不是这个。我想到的那个只有矩阵/向量函数。 刚刚检查了你提供链接的那个,看起来它有所有的math.h函数!我把它加星标了,谢谢! :-) - jcayzac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接