2008-09-04 55 views
14

在C++中測量異常處理開銷/性能的最佳方法是什麼?在C++中測量異常處理開銷

請給出獨立代碼示例。

我針對Microsoft Visual C++ 2008和gcc。

我需要從以下情況下得到的結果:當沒有try/catch塊當有try/catch塊,但異常不拋出

  • 開銷時
  • 架空

    1. 開銷拋出異常
  • 回答

    9

    建議:在引發異常時不要打擾太多的開銷。異常處理實現通常不會很快並且很慢。沒關係,因爲這些情況是非常特殊的。

    卡爾

    7

    這是我想出的測量代碼。你看到它有什麼問題嗎?

    在Linux和Windows,到目前爲止,編譯:

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

    或例如Visual C++ Express。在MSVC

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

    或類似的設置:

    要得到基本情況(「異常支持的語言完全刪除」),使用。

    一些初步結果here。由於機器負載的變化,它們可能都很麻煩,但它們確實給出了一些有關異常處理開銷的想法。 (內容提要:沒有或很少在沒有拋出異常,巨大時,他們實際上都扔。)

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

    我會對您的平臺上的結果感興趣... – 2008-09-23 20:47:30

    +1

    您是否試圖做一個測試,你會發現任何異常(catch(...))。它可能不只是捕捉一個異常類... – 2008-09-23 20:48:59

    2

    有以meassure,在代碼中沒有真正的好辦法。你需要使用一個分析器。

    這不會直接向您顯示在異常處理上花了多少時間,但通過一點研究,您將瞭解哪些運行時方法處理異常(例如,對於VC++ .NET,它是__cxx_exc [.. 。])。

    增加他們的時間,你有開銷。在我們的項目中,我們使用了來自Intel的vTunes,它與Visual C++和gcc一起工作。

    編輯:好吧,如果你只需要一個可能工作的通用數字。以爲你有一個真正的應用程序來配置你不能關閉異常的地方。

    2

    有關異常處理性能的另一個注意事項:簡單測試不考慮高速緩存。 try-code和catch-code都很小,一切都適合指令和數據緩存。但是編譯器可能會嘗試將catch代碼從try-code移開,這會減少正常保存在cache中的代碼量,從而提高性能。

    如果您將異常處理與傳統的C樣式返回值檢查進行比較,那麼也應該考慮此緩存效果(在討論中通常會忽略此問題)。

    卡爾

    0

    不會答案取決於什麼清理已發生的拐的結果呢?如果拋出一個引起整個負載的對象超出堆棧的範圍,那麼這會增加開銷。

    換句話說,我不確定是否對第三個問題的答案獨立於代碼的具體情況。

    0

    有關g ++如何處理異常的完整詳細信息,請參閱here。它將其描述爲用於Itanium體系結構,但所用的一般技術是相同的。它不會告訴你在時間上的確切開銷,但是你可以收集粗略的代碼開銷。