【问题标题】:32bit floating division is not as slow as I expected32bit浮点除法没有我想象的那么慢
【发布时间】:2014-10-06 02:13:00
【问题描述】:

我的环境:

  • Xilinx Zynq(基于 ARM Cortex A9)
  • PetaLinux V2014.2

我正在使用 PetaLinux 在 Zynq 上开发一个 Linux 应用程序。

我目前的问题是四个算术运算的处理时间 (+/-/*/div)。

我使用以下代码通过clock_gettime() 计时了处理时间。

加法(+):

static void funcToBeTimed_floatAdd(void)
{
    int idx;
    float fval = 0.0;
    for(idx=0; idx<100; idx++) {
        fval = fval + 3.14;
    }
}

除法(/):

static void funcToBeTimed_floatDiv(void)
{
    int idx;
    float fval = 314159000.00;
    for(idx=0; idx<100; idx++) {
        fval = fval / 1.001;
    }
}

对于时间测量,使用以下代码。 procNo 使用 main(int argc, char *argv[]) 设置

static void disp_elapsed(int procNo)
{
    struct timespec tp1, tp2;
    long dsec, dnsec;

    /***/
    switch(procNo) {
    case 0:
        printf("add\n");
        clock_gettime(CLOCK_REALTIME, &tp1);
        funcToBeTimed_floatAdd();
        clock_gettime(CLOCK_REALTIME, &tp2);
        break;
    case 1:
        printf("multi\n");
        clock_gettime(CLOCK_REALTIME, &tp1);
        funcToBeTimed_floatMulti();
        clock_gettime(CLOCK_REALTIME, &tp2);
        break;
    default:
        printf("div\n");
        clock_gettime(CLOCK_REALTIME, &tp1);
        funcToBeTimed_floatDiv();
        clock_gettime(CLOCK_REALTIME, &tp2);
        break;
    }

    dsec = tp2.tv_sec - tp1.tv_sec;
    dnsec = tp2.tv_nsec - tp1.tv_nsec;
    if (dnsec < 0) {
        dsec--;
        dnsec += 1000000000L;
    }

    printf("Epalsed (nsec) = %ld\n", dnsec);
}

因此,加法 (+) 和除法 (/) 的处理时间都在 2500 纳秒左右。

我认为通常除法比加法成本更高,但在这种情况下差别不大。

我想知道

  • ARM 应用了什么样的优化
  • 用于搜索有关此类优化的更多信息的关键字
  • (如果有)检查处理时间的代码中的一些错误(例如,避免循环内自动优化等)

【问题讨论】:

  • 尝试展开一点,加法应该会更快,而除法不会。
  • 为了获得更好的帮助,还请发布您用于计时的代码。例如,this 是一个潜在问题。
  • 32 位浮点数只能精确到 6-7 位。这意味着使用 32 位浮点数你甚至不能将值 314159265.35 存储到它的小数点
  • @BenVoigt 感谢您提供关键字“unroll”。
  • 会有很多无用的加载和存储周期没有开启优化,这些将主导IMO的计时。

标签: c linux performance floating-point arm


【解决方案1】:

您的代码可能有几个问题:

  • 您没有向函数传递任何参数,因此优化可能会预先计算其结果。
  • 调用计时函数和调用函数的开销很大,因此速度变慢是不可见的。
  • 您使用的计时器的粒度(试试granularity test
  • 您正在使用浮点数作为结果,但您在双精度中执行所有操作 - 3.14 是双精度,3.14f 是浮点数。
  • 100 个周期太少,看不出任何合理的情况,请尝试增加周期数以达到至少 1 秒的执行时间。
  • 您可以尝试禁用这些功能,看看实际情况如何。
  • 您是否使用硬件浮点支持对其进行编译?

【讨论】:

  • 感谢您的各种指示。
  • 我可能会尝试传递参数以避免预先计算。关于调用函数,你有什么建议?关于定时器的分辨率,我想知道“顺序”,而不是详细的处理时间,所以我使用了clock_gettime()。
  • 我会考虑让计算浮动不加倍。在编译过程中,我没有看到 Makefile 中设置了 -O2 或 -O 或其他硬件浮动支持选项。
  • 好的,我编辑了答案。精度并不重要,因为它对您来说以纳秒为单位。重要的是粒度 - “一个刻度的长度”。尝试通过增加周期数将执行时间增加到至少 1 秒。您可能正在使用软件计算,它们非常慢。您可以尝试某种优化,以最大限度地减少除浮点计算之外的所有其他事情的开销。
  • 这就是您可能想要测量的goo.gl/o4gcmh 添加volatile 关键字会增加如此大的开销。
猜你喜欢
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多