关于性能:测量C ++中的异常处理开销

关于性能:测量C ++中的异常处理开销

Measuring exception handling overhead in C++

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

请提供独立的代码示例。

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

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

  • 没有try / catch块时开销
  • 有try / catch块但未引发异常时的开销
  • 引发异常时的开销

  • 有关C ++性能的技术报告草稿中的5.4节完全涉及异常的开销。


    作为建议:抛出异常时,不要为开销过多地打扰。异常处理实现通常不会使快速抛出和捕获缓慢。没关系,因为这些案例很特殊。

    卡尔


    这是我想出的测量代码。您看到任何问题吗?

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

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

    或例如Visual C ++ Express。

    要获取基本情况("从语言中完全删除了例外支持"),请使用:

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

    或MSVC中的类似设置。

    这里有一些初步结果。由于机器负载的变化,它们可能都是骗人的,但是它们确实提供了有关相对异常处理开销的一些信息。 (执行摘要:没有抛出异常时什么都不是,实际上抛出异常时很大。)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    #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
    "
    );
    #else
        printf("case1\tcase2\tcase3
    "
    );
    #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("
    "
    );
        }

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

    凯文·弗雷(Kevin Frei)在他的演讲" Windows上C ++异常处理的代价"中谈到了异常处理的性能代价。 (在"摘要和结论"下,有一个列表项表示" [异常处理性能成本并非总是可衡量的"。)


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

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

    卡尔


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

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

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

    编辑:好吧,如果您只需要一个可能有效的通用编号。以为您有一个实际的应用程序可以分析您无法关闭异常的情况。


    这里显示了有关g ++如何处理异常的完整详细信息。它描述它是用于Itanium体系结构,但是所使用的通用技术是相同的。它不会告诉您确切的时间开销,但是您可以了解大致的代码开销。


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

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


    推荐阅读

      提高3A四核羿龙II游戏配置的性能

      提高3A四核羿龙II游戏配置的性能,,以节能环保为主题的IT产业,目前3A低端平台处理器、主板芯片组、独立开发卡性能突出,特别是在与AMD的处理

      优化PostgreSQL中的批量更新性能

      优化PostgreSQL中的批量更新性能,数据,表格,在Ubuntu 12.04上使用PG 9.1. 我们目前需要24小时才能运行大量UPDATE数据库上的语句,其形式

      诺基亚威图性能好到哪里

      诺基亚威图性能好到哪里,诺基亚,手机,诺基亚威图性能好到哪里这是一部以前列出的手机。即使当时配置不高,该品牌的手机也不依赖于该功能吸

      魅蓝note6性能参数有哪些

      魅蓝note6性能参数有哪些,摄像头,蓝牙,魅蓝note6性能参数有哪些魅力蓝色Note6最好拍照。电池寿命更长。蓝色Note6使用高通 snapdragon 625

      测量快捷键|角度测量快捷键

      测量快捷键|角度测量快捷键,,角度测量快捷键答:solidworks中测量的快捷键是第三个快捷键:实体测量工具,在装配环境中经常会使用到,因为我们可

      国产电脑cpu测试|国产CPU性能

      国产电脑cpu测试|国产CPU性能,,国产CPU性能天玑9000答: 天玑9000更厉害。因为天玑9000是 最新发布的cpu,也是现在的天花板。而麒麟9000是 2

      主流电脑cpu性能分析|cpu性能对比表

      主流电脑cpu性能分析|cpu性能对比表,,1. cpu性能对比表一、参数对比1、r7 5800H:制程工艺为7nm,主频3.2GHz,睿频4.4GHz,线程数是8核16线程,45W

      新老酷睿i3性能对比试验i34130和i33220

      新老酷睿i3性能对比试验i34130和i33220,,新的英特尔酷睿i3-4130 Haswell处理器架构已经推出了很长一段时间,虽然市场的时间还不长,已经成为