Используется фреймворк Accelerate, заметного ускорения нет

У меня есть следующий фрагмент аудиокода, который, по моему мнению, будет хорошим кандидатом для использования vDSP в среде ускорения.

// --- get pointers for buffer lists
float* left = (float*)audio->mBuffers[0].mData;
float* right = numChans == 2 ? (float*)audio->mBuffers[1].mData : NULL;

float dLeftAccum = 0.0;
float dRightAccum = 0.0;

float fMix = 0.25; // -12dB HR per note

// --- the frame processing loop
for(UInt32 frame=0; frame<inNumberFrames; ++frame)
{
    // --- zero out for each trip through loop
    dLeftAccum = 0.0;
    dRightAccum = 0.0;
    float dLeft = 0.0;
    float dRight = 0.0;

    // --- synthesize and accumulate each note's sample
    for(int i=0; i<MAX_VOICES; i++)
    {
        // --- render
        if(m_pVoiceArray[i]) 
            m_pVoiceArray[i]->doVoice(dLeft, dRight);

        // --- accumulate and scale
        dLeftAccum += fMix*(float)dLeft;
        dRightAccum += fMix*(float)dRight;

    }

    // --- accumulate in output buffers
    // --- mono
    left[frame] = (float)dLeftAccum;

    // --- stereo
    if(right) right[frame] = (float)dRightAccum;
}

// needed???
//  mAbsoluteSampleFrame += inNumberFrames;

return noErr;

Поэтому я модифицировал его для использования vDSP, умножив fMix в конце блока кадров.

// --- the frame processing loop
for(UInt32 frame=0; frame<inNumberFrames; ++frame)
{
    // --- zero out for each trip through loop
    dLeftAccum = 0.0;
    dRightAccum = 0.0;
    float dLeft = 0.0;
    float dRight = 0.0;

    // --- synthesize and accumulate each note's sample
    for(int i=0; i<MAX_VOICES; i++)
    {
        // --- render
        if(m_pVoiceArray[i]) 
            m_pVoiceArray[i]->doVoice(dLeft, dRight);

        // --- accumulate and scale
        dLeftAccum += (float)dLeft;
        dRightAccum += (float)dRight;

    }

    // --- accumulate in output buffers
    // --- mono
    left[frame] = (float)dLeftAccum;

    // --- stereo
    if(right) right[frame] = (float)dRightAccum;
}
vDSP_vsmul(left, 1, &fMix, left, 1, inNumberFrames);
vDSP_vsmul(right, 1, &fMix, right, 1, inNumberFrames);
// needed???
//  mAbsoluteSampleFrame += inNumberFrames;

return noErr;

Тем не менее, использование моего процессора остается прежним. Я не вижу здесь ощутимой выгоды от использования vDSP. Я делаю это правильно? Большое спасибо.

Все еще новичок в векторных операциях, полегче со мной :)

Если есть какие-то очевидные оптимизации, которые я должен сделать (вне рамок ускорения), не стесняйтесь указывать мне на них, спасибо!


person lppier    schedule 26.02.2015    source источник
comment
Предположим здесь, что m_pVoiceArray[i]-›doVoice(dLeft, dRight); изменяет dLeft и dRight (потому что они передаются по ссылке, а это C++?) Я бы хотел, чтобы функция doVoice создавала кучу семплов за раз, а не один. Вы, вероятно, тратите большую часть своего времени на просмотр данных и выполнение вызовов функций. То есть измените порядок циклов в цикле обработки кадров. В противном случае я хотел бы познакомить вас с моим другом оператором умножения.   -  person Ian Ollmann    schedule 28.02.2015
comment
Да, они передаются по ссылке, C++.   -  person lppier    schedule 09.03.2015
comment
Вероятно, это не сильно ускорило работу, потому что большая часть вашего времени на семпл тратилась на цикл MAX_VOICES. Вы можете убедиться в этом, посмотрев использование времени на строку исходного кода в Инструментах. Пара умножений, подобных тому, что вы вытащили из цикла, тривиальна по сравнению со стоимостью вызова указателя функции на (образец * голос).   -  person Ian Ollmann    schedule 10.03.2015
comment
Да, я делаю это с тех пор, как... есть некоторые места, где вычисления могут быть выведены из основного цикла обработки, как вы сказали, или вычислены реже.   -  person lppier    schedule 10.03.2015


Ответы (1)


Ваш векторный вызов выполняет 2 умножения на выборку с частотой дискретизации звука. Если ваша частота дискретизации была 192 кГц, то вы говорите только о 384000 умножений в секунду - на самом деле недостаточно для регистрации на современном процессоре. Более того, вы перемещаете существующие мультипликаторы в другое место. Если бы вы взглянули на сгенерированную сборку, я бы предположил, что компилятор довольно прилично оптимизировал ваш исходный код, и любое ускорение в вызове vDSP будет компенсировано тем фактом, что вам требуется второй цикл.

Еще одна важная вещь, которую следует отметить, это то, что все функции vDSP будут работать лучше, когда векторные данные выровнены по 16-байтовой границе. Если вы посмотрите на набор инструкций SSE2 (который, я уверен, активно используется vDSP), вы увидите, что многие инструкции имеют версию для выровненных данных и другую версию для невыровненных данных.

Выровнять данные в gcc можно примерно так:

float inVector[8] = {1, 2, 3, 4, 5, 6, 7, 8} __attribute__ ((aligned(16)));

Или, если вы выделяете в куче, посмотрите, доступно ли aligned_malloc.

person jaket    schedule 26.02.2015