D 的异常处理开销高过 g++

redsea 2007-09-07
测试平台 debian lenny.

这个测试是测试 happy path 开销, 就是异常实际不发生, 但是为了catch 做准备的代码的开销.
结果我不是太满意, 比 g++ 还是高不少.

代码看起来比较复杂: 循环次数用参数提供, 要调用的函数用函数指针而不是直接调用, 这是为了避免编译器聪明优化; 例如判断出异常实际上不会发生, 不必提供准备代码.



D 1.018

loop 8G times, without try/catch

real    0m24.452s
user    0m23.911s
sys     0m0.005s

loop 8G times, with try/catch
real    0m31.455s
user    0m30.749s
sys     0m0.008s

add 28.6% cost
----------------
g++  (gcc version 4.1.3 20070812 (prerelease) (Debian 4.1.2-15)
loop 8G times, without try/catch

real    0m20.971s
user    0m20.623s
sys     0m0.004s

loop 8G times, with try/catch
real    0m24.481s
user    0m23.949s
sys     0m0.004s

add 16.7% cost

-------------------
D's cost is larger.


-------------------
code:
D:

module test;

import tango.io.Stdout;

int turn=0;
int count;


void fooFunc()
{
    ++ count;
};

alias void function() foo_t;


void test(int c1, int c2, foo_t foo)
{
    for (int j=0;j<c1;j++)
    {
        ++ turn;
        count = 0;
        for (int i=0;i<c2;i++)
        {
            try
            {
                foo();
            }
            catch (Exception e)
            {

            }
        }
    }

    Stdout("\nturn ")(turn)(" count ")(count);

}


int main()
{
    test(8*1024, 1048576, &fooFunc);
    return 0;
}

compile with -O -release -inline

no catch version, comment the try & catch line
-------------------
code:
c++

#include <stdio.h>
#include <exception>

volatile int turn=0;
volatile int count;


void fooFunc(void)
{
    ++ count;
};

typedef void (*foo_t)(void);


void test(int c1, int c2, foo_t foo)
{
    for (int j=0;j<c1;j++)
    {
        ++ turn;
        count = 0;
        for (int i=0;i<c2;i++)
        {
            try
            {
                foo();
            }
            catch (std::exception &e)
            {

            }
        }
    }

    printf("\nturn %d, count %d", turn, count);

}


int main()
{
    test(8*1024, 1048576, fooFunc);
    return 0;
}

compile with -O2
no catch version, comment the try & catch line

Colorful 2007-09-07
请问,这个是在Linux平台上的测试结果吗?
redsea 2007-09-07
Colorful 写道
请问,这个是在Linux平台上的测试结果吗?


是的, 发行版是 debian lenny

oldrev 2007-09-07
有没有测试过 phobos 的效率?

异常嘛,毕竟是罕见的东西,性能底一些也无伤大雅。
redsea 2007-09-07
oldrev 写道
有没有测试过 phobos 的效率?


我的环境使用 dsss 装的, 无法编译 phobos 程序.
根据原理, 异常栈框架代码是编译器准备的, 不是库准备的, 所以性能应该没有什么差别才对.

oldrev 写道
异常嘛,毕竟是罕见的东西,性能底一些也无伤大雅。


异常可以认为不多见, 但是我的测试是 happy path, 就是你用了 catch, 但是实际上异常没有发生带来的额外开销, 这个可是无法省掉的.

今天进行测试的原因是, 我有一个循环数目比较多的循环, 里面会调用一个函数链, 但是整个函数链相关的函数体积都不大, 可以被 inline 化.

但是我犹豫, 这些函数出问题的时候, 用不用异常进行报告.

如果用异常报告, 我必须在循环体内 catch, 因为不能放弃没有出现异常的其他循环项.

所以我测试了一下性能开销.

结果我不是很满意, 比 g++ 还是高了不少.

g++ 的开销, 勉勉强强可以认为是较小的开销, D 的就不太小了, 近 3 成.

Colorful 2007-09-07
晚上有空,我在Windows上做下试验。
郁闷,还要再安装MinGW。

在C#中,只要没有捕获到异常,catch所带来的影响几乎可以忽略不计。
不知道在D中是不是也这样。

PS: 如果在循环中有异常存在,可以让异常循着异常链路径,在循环体结束之后捕获它。
redsea 2007-09-07
Colorful 写道
晚上有空,我在Windows上做下试验。
郁闷,还要再安装MinGW。

在C#中,只要没有捕获到异常,catch所带来的影响几乎可以忽略不计。
不知道在D中是不是也这样。

PS: 如果在循环中有异常存在,可以让异常循着异常链路径,在循环体结束之后捕获它。


循环结束之后捕获? 那剩下没有完成循环的项目就不做循环了? 我的程序中不能这样的.
DavidL 2007-09-07
redsea 写道
Colorful 写道
晚上有空,我在Windows上做下试验。
郁闷,还要再安装MinGW。

在C#中,只要没有捕获到异常,catch所带来的影响几乎可以忽略不计。
不知道在D中是不是也这样。

PS: 如果在循环中有异常存在,可以让异常循着异常链路径,在循环体结束之后捕获它。


循环结束之后捕获? 那剩下没有完成循环的项目就不做循环了? 我的程序中不能这样的.


goto语句就是拿来干这个的,别死搬教条不用goto语句。
DavidL 2007-09-07
另外GCC的异常处理应该是慢的,因为没有使用系统SEH架构。patent issue
Windows平台上DMD编译的结果应该和其他语言的效率是一样的,没必要测试,测了也是浪费时间。
Colorful 2007-09-07
不清楚你的项目。
但是一般情况下如果出现了异常,就说明已经有状态不一致的情况了。再继续下去,可能会导致不可测的情况。
停止循环或在循环结束之后进行异常处理也是合理的事情。

如果其他的循环必须进行下去或者出现了性能严重下降,可以不采用异常机制,比如使用异步的通知机制等。

Global site tag (gtag.js) - Google Analytics