簡體   English   中英

緩存優化理論

[英]Cache Optimization Theory

我正在考慮進行大容量內存緩存優化,並希望獲得一些反饋。 考慮以下示例:

class example
    {
        float phase1;
        float phaseInc;
        float factor;
    public:
        void process(float* buffer,unsigned int iSamples)//<-high prio audio thread
        {
            for(unsigned int i = 0; i < iSamples; i++)// mostly iSamples is 32
            {
                phase1 += phaseInc;
                float f1 = sinf(phase1);//<-sinf is just an example!            
                buffer[i] = f1*factor;
            }
        }
    };

優化思路:

 void example::process(float* buffer,unsigned int iSamples)
    {
        float stackMemory[3];// should fit in L1 
        memcpy(stackMemory,&phase1,sizeof(float)*3);// get all memory at once
        for(unsigned int i = 0; i < iSamples; i++)
        {
            stackMemory[0] += stackMemory[1];
            float f1 = sinf(stackMemory[0]);
            buffer[i] = f1*stackMemory[2];
        }
        memcpy(&phase1,stackMemory,sizeof(float)*1);// write back only changed mameory 
    }

請注意,實際的示例循環將包含數千個操作。 因此stackMemory可能會變得很大。 我認為它將不超過32kb(是否有更小的L1?)。

這個堆棧內存中使用的變量的順序重要嗎? 我希望不會,因為我想訂購它們,以便減少寫回大小。 還是L1緩存具有與RAM相同的緩存行為?

我有一種感覺,我正在以某種方式進行預取,但是我所讀到的有關預取的內容對於如何有效地使用它是相對模糊的。 5000行以上的代碼不支持嘗試錯誤。

代碼將在Win,Mac和iOS上運行。 有ARM <-> Intel問題嗎?

這種優化可能沒有用,因為在循環的第一次迭代中所有內存都被訪問並轉移到L1了嗎?

感謝您的任何提示和想法。

起初,我認為由於增加了內存訪問和memcpy所需的指令,第二個有可能變慢,而第一個可以直接與已經加載到寄存器中的這三個類成員一起工作。

但是,我嘗試同時使用-O2-O3 GCC 5.2中的代碼,發現無論嘗試什么,我都得到了相同的匯編指令。 考慮到memcpy通常要做的所有額外的概念性工作顯然被壓倒了,這真是太神奇了。

我可以想到的一種情況是,在某些情況下,在某些編譯器上,第二個版本可能在哪里更快?如果訪問this->data_member涉及的別名干擾了優化,並導致了寄存器的冗余加載和存儲。

在這種情況下,它與L1緩存無關,並且與編譯器端的寄存器分配無關。 當您加載相同的內存(成員變量)時,無論連續的數據塊如何,緩存在這里都是不相關的,它與寄存器完全有關。 但是,我找不到一個可能導致編譯器的性能差於另一種情況的情況-我測試的每種情況都產生相同的結果。 在足夠復雜的現實世界中,可能會有所不同。

再說一次,在這種情況下,簡單地這樣做應該更安全:

 void process(float* buffer,unsigned int iSamples)
 {
     const float pi = phaseInc;
     const float p1 = phase1;
     const float fact = factor;
     for(unsigned int i = 0; i < iSamples; i++)
     {
         phase1 += pi;
         float f1 = sinf(p1);
         buffer[i] = f1*fact;
     }
 }

無需使用memcpy跳過memcpy即可將結果存儲到數組中並返回。 即使在我的發現中,即使優化程序設法消除了通常相關的開銷,也給優化程序帶來了額外的壓力。

我知道您的示例已簡化,但是無論您要處理多少個數據成員,都不必將結構簡化為這樣的原始數組(除非這樣的數組實際上是最方便的表示形式)。 從性能的角度來看,如果您僅使用局部變量而不是將數據成員memcpymemcpy的數組,則編譯器將擁有“更輕松”的時間(即使當今的優化器非常出色並且可以處理該問題)。

暫無
暫無

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

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