2011-08-23 24 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