2011-08-23 29 views
1

我正在使用環緩衝來保存流音頻應用程序的樣本。我從Ken Greenebaum的Audio Anecdotes 2書中複製了ringbuffer實現。如何提高環緩衝區代碼的性能?

在我的代碼上運行英特爾的Vtune分析器後,它告訴我大部分時間都用於函數getSamplesAvailable()getSpaceAvailable()

任何人都可以提出建議,我怎麼可能會優化這些功能呢?

RingBuffer::getSamplesAvailable(void) 
{ 
    int count = (mTail - mHead + mSize) % mSize; 
    return(count); 
} 

unsigned int RingBuffer::getSpaceAvailable(void) 
{ 
    int free = (mHead - mTail + mSize - 1)%mSize; 
    int underMark = mHighWaterMark - getSamplesAvailable(); 
    int spaceAvailable = min(underMark, free); 
    return(spaceAvailable); 
} 

int RingBuffer::push(int value) 
{ 
    int status = 1; 
    if(getSpaceAvailable()) { 
     // next two operations do NOT have to be atomic! 
     // do NOT have to worry about collision with _tail 
     mBuffer[mTail] = value; // store value 
     mTail = ++mTail % mSize; // increment tail 
    } else { 
    status = 0; 
    } 
    return(status); 
} 

int RingBuffer::pop(int *value) 
{ 
    int status = 1; 
    if(getSamplesAvailable()) { 
     *value = mBuffer[mHead]; 
     mHead = ++mHead % mSize; // increment head 
    } else { 
     status = 0; 
    } 
    return(status); 
} 
+0

谷歌爲「虛擬環緩衝區」。我不知道你是否可以在你的操作系統上實現它,但當你需要一個真正的快速緩衝區時,它是一個非常好的選擇。 – PlasmaHH

回答

2

我認爲問題不是他們的複雜性,他們只是基本的整數運算,但他們是如何調用的次數。

是否有這樣做「批量」的(插入或一次獲取各種值)的緩衝器更新的可能?這樣你可以節省一些計算。

3

如果你能夠讓mSize二的冪,可以更換

(mTail - mHead + mSize) % mSize 

通過

(mTail - mHead) & (mSize-1) 

(mHead - mTail + mSize - 1) % mSize 

通過

(mHead - mTail - 1) & (mSize - 1) 
+0

你不需要改變代碼,因爲編譯器會自動優化到相同的(如果這是安全的);儘可能使用無符號整數 – sehe

+1

@sehe:編譯器不會做這樣的事情。 'mSize'不是一個常量,編譯器在生成代碼時無法知道它是二的冪。 –

0

亨利克爾提出的使用二的冪是第一件要做的事。還有可能改變你編寫mTail和mHead索引的方式。不要將它們保留在[0,mSize [範圍內,你可以讓它們以uint32_t的形式自由運行。

當訪問一個元素,你需要做一個模MSIZE將每個接入放緩。

mBuffer[mTail % mSize] = value; 

但它會simpify例如樣品數(即使你的索引包裹在uint32_t的最大值):

int count = mTail - mHead; 

它也將讓您充分使用環形緩衝區,而不是丟失一個元素來區分緩衝區已滿或空的情況。

0

如果速度是你最重要的事情,你可以用一個事實,即它是)非便攜式(僅適用於Windows住,雖然Linux具有相同的基本功能以及使應該在那裏工作,以及)和b )只能在發佈版本(當然更多的是用VC++如何分配在調試模式記憶 - 可能有一些編譯標誌此),您可以使用以下方法:?

DWORD size = 64 * 1024; // HAS to be a multiple of 64k due to how win allocates memory 
HANDLE mapped_memory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, NULL); 
int *p1 = (int*)MapViewOfFile(mapped_memory, FILE_MAP_WRITE, 0, 0, size); 
int *p2 = (int*)MapViewOfFile(mapped_memory, FILE_MAP_WRITE, 0, 0, size); 
// p1 and p2 should be adjacent in memory, if not try again.. no idea if there's some 
// better method under windows 

基本上,你現在有兩個相鄰的存儲虛擬內存中的塊指向相同的物理內存。也就是說,如果您通過pdw1寫入,您將看到pdw2中的更改,反之亦然。

的好處是,你現在可以更有效地讀取和寫入緩衝區,並也較大數額比在同一時間只有一個字。你只需要正確地減少指針 - 不應太難實現。

編輯:現在看到 - 甚至有一個POSIX實現on wiki