【问题标题】:Measuring exception handling overhead in C++测量 C++ 中的异常处理开销
【发布时间】:2010-09-07 18:43:18
【问题描述】:

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

请提供独立的代码示例。

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

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

  1. 没有 try/catch 块时的开销
  2. 存在 try/catch 块但未引发异常时的开销
  3. 抛出异常时的开销

【问题讨论】:

    标签: c++ performance exception visual-c++ gcc


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 好点,我想知道有多少测试没有考虑到销毁这些对象所花费的时间,编码版本无一例外,它分布在更多例程中。
        【解决方案4】:

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

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

        卡尔

        【讨论】:

          【解决方案5】:

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

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

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

          编辑:好吧,如果您只需要一个可能有用的通用数字。以为你有一个实际的应用程序来分析你不能只关闭异常的地方。

          【讨论】:

            【解决方案6】:

            draft Technical Report on C++ Performance 的第 5.4 节完全致力于异常的开销。

            【讨论】:

            • 这可以通过在答案中引用相关内容来改进,以防链接失效。
            • 如果“完全投入”是指大量文本和零数据,那么是的。
            【解决方案7】:

            这是我想出的测量代码。你觉得它有什么问题吗?

            目前在 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 中的类似设置。

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

            #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
            }
            

            【讨论】:

            • 您是否尝试过进行测试以捕获任何异常(catch (...))。它可能与仅捕获单个异常类不同...
            【解决方案8】:

            作为一个建议:当抛出异常时,不要太在意开销。异常处理实现通常使不快速抛出和缓慢捕获。没关系,因为这些情况非常特殊。

            卡尔

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-10-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-06-11
              • 2011-04-27
              • 2011-09-11
              相关资源
              最近更新 更多