如何分析异常处理的性能开销

发布于 2024-07-04 22:11:46 字数 221 浏览 11 评论 0原文

在 C++ 中衡量异常处理开销/性能的最佳方法是什么?

请提供独立的代码示例。

我的目标是 Microsoft Visual C++ 2008 和 gcc。

我需要从以下情况获得结果:

  1. 没有 try/catch 块时的开销
  2. 有 try/catch 块但不抛出异常
  3. 时的开销 抛出异常时的开销

What is the best way to measure exception handling overhead/performance in C++?

Please give standalone code samples.

I'm targeting Microsoft Visual C++ 2008 and gcc.

I need to get results from the following cases:

  1. Overhead when there are no try/catch blocks
  2. Overhead when there are try/catch blocks but exceptions are not thrown
  3. Overhead when exceptions are thrown

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

清醇 2024-07-11 22:11:47

Kevin Frei 在他的演讲中谈论异常处理性能成本“Windows 上 C++ 异常处理的成本"。 (在“摘要和结论”下,有一个列表项表示“[异常处理性能成本]并不总是可衡量的”。)

Kevin Frei talks about exception handling performance cost in his speech "The Cost of C++ Exception Handling on Windows". (Under "Summary & Conclusions" there is one list item that says "[Exception handling performance cost is] not always measurable".)

少年亿悲伤 2024-07-11 22:11:47

没有真正好的方法可以在代码中测量这一点。 您需要使用分析器。

这不会直接显示您在异常处理上花费了多少时间,但通过一些研究,您将发现哪些运行时方法处理异常(例如,对于 VC++.NET,它是 __cxx_exc[...])。

把他们的时间加起来,你就得到了开销。 在我们的项目中,我们使用了 Intel 的 vTunes,它可以与 Visual C++ 和 gcc 配合使用。

编辑:好吧,如果您只需要一个可能有效的通用号码。 认为您有一个实际的应用程序来分析,您不能只关闭异常。

There's no really good way to meassure that in code. You would need to use a a profiler.

This won't show you directly how much time is spent with exception handling but with a little bit of research you will find out which of the runtime methods deal with exceptions (for example for VC++.NET it's __cxx_exc[...]).

Add their times up and you have the overhead. In our project we used vTunes from Intel which works with both Visual C++ and gcc.

Edit: Well, if you just need a generic number that might work. Thought you had an actual application to profile where you can't just turn off exceptions.

弱骨蛰伏 2024-07-11 22:11:47

关于异常处理性能的另一个注意事项:简单的测试不考虑缓存。 try 代码和 catch 代码都非常小,以至于所有内容都适合指令和数据缓存。 但编译器可能会尝试将 catch 代码移至远离 try 代码的位置,这会减少正常保留在缓存中的代码量,从而提高性能。

如果将异常处理与传统的 C 样式返回值检查进行比较,则还应该考虑这种缓存效果(在讨论中通常会忽略这个问题)。

卡尔

Another note on exception handling performance: simple tests don't take caching into account. The try-code and the catch-code are both so small that everything fits in the instruction and data caches. But compilers may try to move the catch-code far away from the try-code, which reduces the amount of code to keep in cache normally, thus enhancing performance.

If you compare exception handling to traditional C-style return-value checking, this caching effect should be taken into account as well (the question is usually ignored in discussions).

Carl

眉目亦如画i 2024-07-11 22:11:47

答案不是取决于抛出后必须进行什么清理吗? 如果引发异常,导致整个对象负载超出堆栈范围,那么这将增加开销。

换句话说,我不确定第三个问题是否有独立于代码细节的答案。

Won't the answer depend on what cleanup has to happen as a result of a throw? If an excpetion is thrown that causes a whole load of objects to go out of scope up the stack, then that will add to the overhead.

In other words, I'm not sure if there is a an answer to the 3rd question that is independent of the specifics of the code.

恍梦境° 2024-07-11 22:11:47

有关 g++ 如何处理异常的完整详细信息请参见此处。 它将其描述为适用于 Itanium 架构,但所使用的一般技术是相同的。 它不会告诉您确切的时间开销,但是您可以了解粗略的代码开销是多少。

Full details on how g++ handles exceptions is shown here. It describes it as being for the Itanium architecture, however the general techniques used are the same. It won't tell you exact overhead in terms of time, however you can glean what the rough code overhead will be.

心的位置 2024-07-11 22:11:47

C++ 性能技术报告草案的第 5.4 节是完全致力于异常的开销。

Section 5.4 of the draft Technical Report on C++ Performance is entirely devoted to the overhead of exceptions.

享受孤独 2024-07-11 22:11:47

建议:抛出异常时不要太担心开销。 异常处理实现通常会使抛出速度不快而捕获速度慢。 没关系,因为这些情况都是特殊情况。

卡尔

As a suggestion: don't bother too much with the overhead when exceptions are thrown. Exception handling implementations usually make not throwing fast and catching slow. That's ok since those cases are, well, exceptional.

Carl

在你怀里撒娇 2024-07-11 22:11:47

这是我想出的测量代码。 您看到它有什么问题吗?

到目前为止,可在 Linux 和 Windows 上运行,使用以下编译器进行编译:

g++ exception_handling.cpp -o exception_handling [ -O2 ]

或例如 Visual C++ Express

要获得基本情况(“从语言中完全删除异常支持”),请使用:

g++ exception_handling.cpp -o exception_handling [ -O2 ] -fno-exceptions -DNO_EXCEPTIONS

或 MSVC 中的类似设置。

此处提供了一些初步结果。 由于机器负载不同,它们可能都是做作的,但它们确实给出了一些关于相对异常处理开销的想法。 (执行摘要:当没有抛出异常时,没有或很少,当实际抛出异常时,则很大。)

#include <stdio.h>

// Timer code

#if defined(__linux__)
#include <sys/time.h>
#include <time.h>

double time()
{
    timeval tv;
    gettimeofday(&tv, 0);
    return 1.0 * tv.tv_sec + 0.000001 * tv.tv_usec;
}
#elif defined(_WIN32)
#include <windows.h>

double get_performance_frequency()
{
    unsigned _int64 frequency;
    QueryPerformanceFrequency((LARGE_INTEGER*) &frequency); // just assume it works
    return double(frequency);
}

double performance_frequency = get_performance_frequency();

double time()
{
    unsigned _int64 counter;
    QueryPerformanceCounter((LARGE_INTEGER*) &counter);
    return double(counter) / performance_frequency;
}
#else
# error time() not implemented for your platform
#endif

// How many times to repeat the whole test
const int repeats = 10;

// How many times to iterate one case
const int times = 1000000;

// Trick optimizer to not remove code
int result = 0;



// Case 1. No exception thrown nor handled.

void do_something()
{
    ++result;
}

void case1()
{
    do_something();
}



// Case 2. No exception thrown, but handler installed

#ifndef NO_EXCEPTIONS
void do_something_else()
{
    --result;
}

void case2()
{
    try
    {
        do_something();
    }
    catch (int exception)
    {
        do_something_else();
    }
}



// Case 3. Exception thrown and caught

void do_something_and_throw()
{
    throw ++result;
}

void case3()
{
    try
    {
        do_something_and_throw();
    }
    catch (int exception)
    {
        result = exception;
    }
}
#endif // !NO_EXCEPTIONS

void (*tests[])() =
{
    case1,
#ifndef NO_EXCEPTIONS
    case2,
    case3
#endif // !NO_EXCEPTIONS
};

int main()
{
#ifdef NO_EXCEPTIONS
    printf("case0\n");
#else
    printf("case1\tcase2\tcase3\n");
#endif
    for (int repeat = 0; repeat < repeats; ++repeat)
    {
        for (int test = 0; test < sizeof(tests)/sizeof(tests[0]); ++test)
        {
            double start = time();

            for (int i = 0; i < times; ++i)
                tests[test]();

            double end = time();

            printf("%f\t", (end - start) * 1000000.0 / times);
        }
        printf("\n");
    }

    return result; // optimizer is happy - we produce a result
}

Here's the measuring code I came up with. Do you see any problems with it?

Works on Linux and Windows so far, compile with:

g++ exception_handling.cpp -o exception_handling [ -O2 ]

or for example Visual C++ Express.

To get the base case ("exception support removed from the language altogether"), use:

g++ exception_handling.cpp -o exception_handling [ -O2 ] -fno-exceptions -DNO_EXCEPTIONS

or similar settings in MSVC.

Some preliminary results here. They are probably all hokey because of varying machine load, but they do give some idea about the relative exception handling overhead. (Executive summary: none or little when no exceptions are thrown, huge when they actually are thrown.)

#include <stdio.h>

// Timer code

#if defined(__linux__)
#include <sys/time.h>
#include <time.h>

double time()
{
    timeval tv;
    gettimeofday(&tv, 0);
    return 1.0 * tv.tv_sec + 0.000001 * tv.tv_usec;
}
#elif defined(_WIN32)
#include <windows.h>

double get_performance_frequency()
{
    unsigned _int64 frequency;
    QueryPerformanceFrequency((LARGE_INTEGER*) &frequency); // just assume it works
    return double(frequency);
}

double performance_frequency = get_performance_frequency();

double time()
{
    unsigned _int64 counter;
    QueryPerformanceCounter((LARGE_INTEGER*) &counter);
    return double(counter) / performance_frequency;
}
#else
# error time() not implemented for your platform
#endif

// How many times to repeat the whole test
const int repeats = 10;

// How many times to iterate one case
const int times = 1000000;

// Trick optimizer to not remove code
int result = 0;



// Case 1. No exception thrown nor handled.

void do_something()
{
    ++result;
}

void case1()
{
    do_something();
}



// Case 2. No exception thrown, but handler installed

#ifndef NO_EXCEPTIONS
void do_something_else()
{
    --result;
}

void case2()
{
    try
    {
        do_something();
    }
    catch (int exception)
    {
        do_something_else();
    }
}



// Case 3. Exception thrown and caught

void do_something_and_throw()
{
    throw ++result;
}

void case3()
{
    try
    {
        do_something_and_throw();
    }
    catch (int exception)
    {
        result = exception;
    }
}
#endif // !NO_EXCEPTIONS

void (*tests[])() =
{
    case1,
#ifndef NO_EXCEPTIONS
    case2,
    case3
#endif // !NO_EXCEPTIONS
};

int main()
{
#ifdef NO_EXCEPTIONS
    printf("case0\n");
#else
    printf("case1\tcase2\tcase3\n");
#endif
    for (int repeat = 0; repeat < repeats; ++repeat)
    {
        for (int test = 0; test < sizeof(tests)/sizeof(tests[0]); ++test)
        {
            double start = time();

            for (int i = 0; i < times; ++i)
                tests[test]();

            double end = time();

            printf("%f\t", (end - start) * 1000000.0 / times);
        }
        printf("\n");
    }

    return result; // optimizer is happy - we produce a result
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文