簡體   English   中英

在帶有 C++ 的嵌入式環境中使用 inheritance 的“價格”是多少?

[英]What's the “price” of using inheritance in an embedded environment with C++?

我正在使用 C++ 開始一個新的嵌入式項目,我想知道使用面向接口的設計是否太貴了。 像這樣的東西:

typedef int data;

class data_provider {

public:
    virtual data get_data() = 0;
};

class specific_data_provider : public data_provider {
public:
    data get_data() {
    return 7;
    }
};

class my_device {
public:
    data_provider * dp;
    data d;

    my_device (data_provider * adp) {
    dp = adp;
    d = 0;
    }

    void update() {
    d = dp->get_data();
    }
};

int
main() {
    specific_data_provider sdp;
    my_device dev(&sdp);

    dev.update();

    printf("d = %d\n", dev.d);

    return 0;
}

Inheritance 基本上是免費的。 但是,多態性和動態分派( virtual )會產生一些后果:每個帶有 virtual 方法的 class 實例都包含一個指向vtable的指針,該指針用於 select 調用正確的方法。 這為每個虛擬方法調用添加了兩個 memory 訪問。

在大多數情況下,它不會成為問題,但它可能會成為某些實時應用程序的瓶頸。

Inheritance 本身是免費的。 例如,在下面,從性能/內存的角度來看, BC是相同的:

struct A { int x; };
struct B : A { int y; };
struct C { int x, y; };

Inheritance 僅在您擁有虛擬功能時才會產生費用。

struct A { virtual ~A(); };
struct B : A { ... };

在這里,幾乎在所有實現中,由於虛擬 function, AB都將大一個指針大小。

虛函數還有其他缺點(與非虛函數相比)

  1. 虛函數要求您在調用時查找 vtable。 如果該 vtable 不在緩存中,那么您將獲得 L2 未命中,這在嵌入式平台上可能會非常昂貴(例如,在當前一代游戲控制台上超過 600 個周期)。
  2. 即使你命中了 L2 緩存,如果你分支到許多不同的實現,那么你可能會在大多數調用上得到一個分支錯誤預測,從而導致管道刷新,這又會花費很多周期。
  3. 由於虛函數基本上不可能內聯(在極少數情況下除外),您還會錯過許多優化機會。 如果您調用的 function 很小,那么與內聯的非虛擬 function 相比,這可能會增加嚴重的性能損失。
  4. 虛擬調用會導致代碼膨脹。 每個虛擬 function 調用都會添加幾個字節的指令來查找 vtable,並為 vtable 本身添加許多字節。

如果您使用多個 inheritance,那么情況會變得更糟。

通常人們會告訴你“在你的分析器告訴你之前不要擔心性能”,但如果性能對你來說很重要,這是一個糟糕的建議。 如果您不擔心性能,那么最終會出現到處都是虛函數,並且當您運行分析器時,沒有一個熱點需要優化——整個代碼庫都需要優化。

如果對您很重要,我的建議是針對性能進行設計。 盡可能設計為避免對虛擬功能的需求。 圍繞緩存設計數據:更喜歡 arrays 到基於節點的數據結構,如std::liststd::map 即使您有一個包含幾千個元素的容器,並且經常在中間插入,對於某些架構上的數組,我仍然會使用 go。 您為插入而丟失復制數據的數千個周期很可能會被您在每次遍歷時實現的緩存局部性所抵消(還記得單個L2 緩存未命中的成本嗎?您可以在遍歷鏈表時期待很多)

真的取決於你的硬件。 Inheritance 本身可能不會花費您任何費用。 對於每個 class 中的 vTable,虛擬方法會花費您一些 memory。 打開異常處理可能會在 memory 和性能方面花費更多。 我已經在 NetBurner 平台上廣泛使用了 C++ 的所有功能,其中的芯片像 MOD5272 有幾兆的 Flash 和 8 兆的 RAM。 還有一些事情可能取決於實現,在我使用的 GCC 工具鏈上,當使用 cout 而不是 printf 時,你會受到大量 memory 的打擊(它似乎鏈接到一堆庫中)。 您可能對我寫的關於類型安全代碼成本的博文感興趣。 您必須在您的環境中運行類似的測試才能真正回答您的問題。

通常的建議是使代碼清晰和正確,然后只有在實踐中證明是一個問題(太慢或太多內存)時才考慮優化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM