为什么在缓冲区较小时在循环缓冲区中写入大量数据需要较少的时间

时间:2017-07-19 17:56:11

标签: c circular-buffer

我正在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

0 个答案:

没有答案