我正在C中研究用于音频目的的循环缓冲区
我需要在一个memcpy中写入的字节数是2048字节 - 帧大小为512个浮点样本。
我测试了32000次写操作,即65536000字节(32000 * 512 * 4)
如果我的循环缓冲区长度为0x1000000(16777216),则需要12000微秒(*)
如果我的循环缓冲区长度为0x100000(1048576),则需要4000微秒(*)
看起来好像循环缓冲区更长时间会花费更多时间 ...虽然写入的总字节数是相同的。什么可以解释这种差异?
我尝试在代码中或在对结果的解释中发现错误,但找不到任何解释。
也许我在某个地方犯了一个愚蠢的错误,但我找不到它。
我写了一个小例子来说明我的问题: 更新版本
//
// main.c
// TestMemoryWrite
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h> // DST_NONE, gettimeofday
#define kLengthOfOneSetOfFloatToWrite 512
#define kNumberOfSetToWrite 32000
#if 0
#define kMainBufferLengthInBytes 0x1000000 // 12000 useconds
#else
#define kMainBufferLengthInBytes 0x100000 // 3500 useconds
#endif
#define kMainBufferLengthInFloat ( kMainBufferLengthInBytes / sizeof(float) )
float gMainBufferFloat[ kMainBufferLengthInFloat ] = {0}; // 16 777 816 bytes
float gSubArrayToWrite[kLengthOfOneSetOfFloatToWrite] = {0};
// gPtrWrite is our void* pointer in gMainBufferFloat
// Each time we write it will be "advanced" for 512 float equivalent
// When gBufferEnd is reached, gPtrWrite is reinitialized at gBufferStart
void * gPtrWrite = (void*)gMainBufferFloat;
void * gBufferStart = (void*)gMainBufferFloat;
void * gBufferEnd = (void*)gMainBufferFloat + kMainBufferLengthInBytes;
// function providing gPtrWrite value
void *ARWritePtr(void)
{
// Return current Pointer in gMainBufferFloat
void * ptrWrite = gPtrWrite;
// Advance our pointer or reset to the start
// aSetOfBytesToWrite: 2048
uint32_t aSetOfBytesToWrite = kLengthOfOneSetOfFloatToWrite * sizeof(float);
gPtrWrite += aSetOfBytesToWrite;
// Shall we reach the end next time
if ( gPtrWrite >= gBufferEnd ) {
// Then reset to start
gPtrWrite = gBufferStart;
}
return ptrWrite;
}
int main(int argc, const char * argv[]) {
// Initialize items to compute elapsed time
struct timeval tv1, tv2;
struct timezone tz1 = {0, DST_NONE};
unsigned long tv_sec, tv_usec;
// Create data for the test
// Initialize random functions
srand((int)time(NULL));
for (int i = 0; i<kLengthOfOneSetOfFloatToWrite; i++) {
gSubArrayToWrite[i] = (float)rand()/1000000.0;
}
// initialize timing
gettimeofday( &tv1, &tz1);
// lengthToWriteInBytes: 512 * 4
// -> 2048
uint32_t lengthToWriteInBytes = kLengthOfOneSetOfFloatToWrite * sizeof(float);
// totalBytesToWrite: 32000 * 512 * 4
// -> 65536000
uint32_t totalBytesToWrite = kNumberOfSetToWrite * kLengthOfOneSetOfFloatToWrite * sizeof(float);
printf("kNumberOfSetToWrite:%u\n", kNumberOfSetToWrite);
printf("of kLengthOfOneSetOfFloatToWrite:%u\n", kLengthOfOneSetOfFloatToWrite);
printf("total bytes:%u \n", totalBytesToWrite);
printf("expected overrides:%u\n", (uint32_t)totalBytesToWrite / kMainBufferLengthInBytes);
float *framefloat = NULL;
float *framefloatPrevious = NULL;
// 32000 loops
uint32_t countOfResets = 0;
for (int i=0; i < kNumberOfSetToWrite ; i++) {
// get current pointer to write in our buffer
framefloat = (float*)ARWritePtr();
// if our pointer is smaller than before, we had a reset
if (framefloat < framefloatPrevious && framefloatPrevious ) {
countOfResets++;
}
// copy our 2048 bytes: memcpy(dst, src, length)
memcpy((void*)framefloat, (void*)gSubArrayToWrite, lengthToWriteInBytes);
framefloatPrevious = framefloat;
}
gettimeofday( &tv2, &tz1);
tv_sec=tv2.tv_sec - tv1.tv_sec;
tv_usec=tv2.tv_usec - tv1.tv_usec;
printf("\n- %lu Seconds %lu Micro Seconds \n", tv_sec, tv_usec);
printf("average Micro Seconds / count framesToWrite:%f\n", (double)tv_usec / (double)kNumberOfSetToWrite);
printf("total bytes written:%u count of resets:%u\n\n", totalBytesToWrite, countOfResets );
return 0;
}
有人会有解释吗?
(*)使用MacBook Pro 16GB 2,7 GHz Intel Core i7