簡體   English   中英

Memset struct 變量分別與 memset 整個結構,哪個更快?

[英]Memset struct variables separately vs memset entire struct, which is faster?

假設我有這樣的結構:

struct tmp {
    unsigned char arr1[10];
    unsigned char arr2[10];
    int  i1;
    int  i2;
    unsigned char arr3[10];
    unsigned char arr4[10];
};

其中哪一個會更快?

(1) Memset 整個結構為 0,然后將成員填充為:

struct tmp t1;
memset(&t1, 0, sizeof(struct tmp));

t1.i1 = 10;
t1.i2 = 20;
memcpy(t1.arr1, "ab", sizeof("ab"));
// arr2, arr3 and arr4 will be filled later.

或者

(2) Memset 分離變量:

struct tmp t1;
t1.i1 = 10;
t1.i2 = 20;
memcpy(t1.arr1, "ab", sizeof("ab"));

memset(t1.arr2, 0, sizeof(t1.arr2); // will be filled later
memset(t2.arr3, 0, sizeof(t1.arr3); // will be filled later
memset(t2.arr4, 0, sizeof(t1.arr4); // will be filled later

就性能而言,對 memset 的多次調用(在結構的單獨成員上)比對 memset 的單個調用(在整個結構上)更快/更慢。

在沒有考慮特定系統的情況下討論這個問題並沒有真正的意義,除非你真的有一個性能瓶頸,否則思考這些事情也沒有什么成果。 我還是可以試試的。

對於“通用計算機”,您必須考慮:

  • 對齊訪問
    在一個 go 中訪問一大塊數據通常會更好。 在潛在錯位的情況下,無論數據有多大,處理該問題的開銷代碼大致相同。 理論上假設這段代碼中的所有訪問都發生了錯位,那么 1 次 memset 調用優於 3 次。

    此外,我們可以假設結構的第一項是對齊的,但我們不能假設結構內的任何單個成員都是如此。 linker 將在對齊的地址分配結構,然后可能在其中的任何位置添加填充以補償未對齊。

    聲明您的結構時沒有考慮 alignment,所以這將是一個問題 - 編譯器將插入大量填充。

    (另一方面,整個結構上的 memset 也會覆蓋填充字節,這是一點點開銷代碼。)

  • 數據緩存使用
    從上到下訪問相鄰 memory 的區域比從代碼中的多個位置訪問它的片段更“緩存友好”。 隨后訪問連續的 memory 意味着計算機可以將大量數據加載到緩存中,而不是從 RAM 中獲取數據,這樣比較慢。

  • 指令緩存使用和分支預測
    在這種情況下不是很相關,因為代碼基本上只是在做原始副本並且沒有分支。

  • 生成的機器指令數量
    這始終是代碼速度的一個很好的粗略指示。 顯然,有些指令比其他指令慢很多,但較少的指令通常意味着更快的代碼。 用 gcc x86_64 -O3 拆解你的兩個功能然后我得到這個:

     func1: movabs rax, 85899345930 pxor xmm0, xmm0 movups XMMWORD PTR [rdi+16], xmm0 mov QWORD PTR [rdi+20], rax mov eax, 25185 movups XMMWORD PTR [rdi], xmm0 movups XMMWORD PTR [rdi+32], xmm0 mov WORD PTR [rdi], ax ret func2: movabs rax, 85899345930 xor edx, edx xor ecx, ecx xor esi, esi mov QWORD PTR [rdi+20], rax mov eax, 25185 mov WORD PTR [rdi], ax mov BYTE PTR [rdi+2], 0 mov QWORD PTR [rdi+10], 0 mov WORD PTR [rdi+18], dx mov QWORD PTR [rdi+28], 0 mov WORD PTR [rdi+36], cx mov QWORD PTR [rdi+38], 0 mov WORD PTR [rdi+46], si ret

    這很好地表明了前一個代碼更高效,並且它也應該對數據緩存更友好,所以如果 (1) 沒有明顯更快,我會感到驚訝。

另請注意,如果您使用 static 存儲持續時間聲明此結構,您會將零輸出“外包”給程序設置.bss的 CRT 部分,並在 main() 甚至被調用之前執行。 那么這些 memset 都不需要了。 代價是啟動速度稍慢,但整體程序速度更快。

暫無
暫無

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

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