У меня есть следующий код Java. Я пытаюсь оптимизировать функцию
while(pStart < audio.length) {
int pEnd = Math.round(pStart + winSize*Fs);
int windowEnd = Math.min(pEnd, audio.length);
double[] window = new double[fftSize*2];
for(int i = pStart; i < windowEnd; i++) {
window[(i-pStart)*2] = audio[i];
}
fft.complexForward(window);
double fftVal;
for(int i = 0; i < fftSize/2; i++) {
fftVal = Math.sqrt((window[i*2] * window[i*2]) + (window[i*2+1] * window[i*2+1] ));
powerAll[i][index] = 20 * Math.log10(
Math.abs(fftVal) / (windowEnd - pStart));
}
index++;
pStart = pStart + windowSlide;
}
Сроки по файлам трассировки:
Всего 2500 мс fft ~ 500 мс self ~ 900 мс секунд для цикла ~ 900 мс
Итак, я сосредоточен на том, чтобы оптимизировать второй цикл while. Я не могу изменить функцию fft.
По тому же вопросу я не уверен, почему трассировщик сообщает "я", чтобы он составлял 900 мс.
Исходный код можно упростить, применяя математические свойства функции журнала.
Рассмотрим следующую функцию, извлеченную из исходного кода:
double original( double[] window, int i, int windowEnd, int pStart ) {
double fftVal = Math.sqrt(
( window[ i * 2 ] * window[ i * 2 ] )
+ ( window[ i * 2 + 1 ] * window[ i * 2 + 1 ] )
);
return 20 * Math.log10(
Math.abs( fftVal ) / ( windowEnd - pStart ) );
}
В принципе, в псевдокоде есть следующая функция:
x = sqrt(w[2i]^2 + w[2i+1]^2)
return 20 * log( abs(x) / ( windowEnd - pStart ) )
Упрощенный вариант с объяснениями каждого шага:
double variant( double[] window, int i, int windowEnd, int pStart ) {
// w[2i]^2 + w[2i+1]^2
double temp1 = window[ i * 2 ] * window[ i * 2 ]
+ window[ i * 2 + 1 ] * window[ i * 2 + 1 ];
// apply log(sqrt(X)) == log(X^0.5) == 0.5 log(X)
double temp2 = 0.5 * Math.log10( temp1 );
// calculate the value of Math.log10( windowEnd - pStart )
// (and cache it outside of the function)
double tempConst3 = Math.log10( windowEnd - pStart );
// apply log(X/Y) == log(X) - log(Y)
double temp4 = temp2 - tempConst3;
return 20 * temp4;
}
Ваш код является легкой целью для распараллеливания. Вы можете:
ForkJoin
который обрабатывает многие аспекты для вас;parallelStream
потока.Мой выбор, безусловно, будет номером 3, если не более того для удовольствия.
Я потратил некоторое время, чтобы измерить ваш код в моей настройке, используя jmh. Это занимает 14 наносекунд за вход в window
массив. Учитывая объем выполненных расчетов, я думаю, что это уже отличный результат и не может быть улучшен с какой-либо значительной разницей.
Простые оптимизации, которые вы можете сделать, - это сохранить значение window[i*2]
и window[i*2+1]
в переменной и использовать их в методе sqrt()
что уменьшит количество обращений к массиву.
Кроме этого, если бы вы могли сказать, что вы пытаетесь сделать, мы могли бы помочь вам лучше.