簡體   English   中英

C語言中memset函數的復雜性

[英]Complexity of the memset function in C

我和一些朋友討論了一段代碼,我們討論了在C中使用memset函數,如果我們初始化一個大小為N的數組,這個函數的Big-O表示法的順序是什么?

在您可以直接訪問頁表並且以分層方式存儲的系統上,通過將整個虛擬地址映射替換為對單個頁面的寫時復制引用,可以在O(log n)實現memset填充給定的字節值。 但請注意,如果您將來對該對象進行任何修改,則memset的正常O(n)成本將被推遲到頁面錯誤,以在修改頁面時實例化單獨的頁面副本。

您詢問了復雜性,但您可能打算詢問性能。

用符號O(n)表示的復雜性是與算法中的操作數量如何隨着問題大小增長而被迫增長有關的概念。 O(n)表示必須執行與輸入大小成比例的一些步驟。 它沒有說明這個比例是多少。 memset是O(n)。 O(n 2 )表示必須執行與n 2成比例的一些步驟。 memset不是O(n 2 ),因為設置2n個字節的工作量只是n個字節的兩倍,而不是工作量的四倍。

您可能對memset的性能更感興趣,因為memset的庫版本比您可能編寫的C版本執行得更快。

庫版本執行速度更快,因為它使用專門的指令。 最常見的現代處理器具有允許它們在一條指令中將16字節寫入存儲器的指令。 庫實現者用匯編語言或接近它的東西編寫像memset這樣的關鍵函數,因此他們可以訪問所有這些指令。

用C語言編寫時,編譯器很難利用這些指令。 例如,指向您正在設置的內存的指針可能不會與16個字節的倍數對齊。 memset作者將編寫測試指針的代碼,並為每種情況分支到不同的代碼,目標是單獨設置一些字節,然后使用一個對齊的指針,這樣他們就可以使用存儲16字節的快速指令。時間。 這只是庫編寫器在編寫memset等例程時要處理的許多復雜問題之一。

由於這些復雜性,編譯器無法輕松采用memset的C實現並將其轉換為專家編寫的快速代碼。 當編譯器在C代碼中看到一次寫入一個字節的循環時,它通常會生成一次寫入一個字節的匯編語言。 優化器變得越來越聰明,但復雜性限制了它們允許執行的程度以及它們可以執行多少操作而無需生成大量代碼來處理可能很少發生的情況。

復雜度為O(n)。 這是基本的東西。

一些C庫提供了memset()矢量化版本。 除非您的編譯器執行自動矢量化和循環展開,否則for循環將比矢量化memset()慢。 矢量化與否, memset()受存儲器帶寬的限制,最小時間與數組大小除以存儲器帶寬成正比,即當存儲器帶寬恆定時,它是O(n)操作。

在NUMA機器上,可以對非常大的陣列進行線程化,以實現NUMA節點數量級的加速。 有關基准測試,請參閱此答案

暫無
暫無

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

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