Во-первых, при настройке функции частотного анализа с использованием инфраструктуры Accelerate абсолютное системное время постоянно составляло 225 мс на итерацию. Затем прошлой ночью я изменил порядок объявления двух массивов, и внезапно он снизился до 202 мс. Увеличение на 10% за счет простого изменения порядка объявления кажется безумием. Может кто-нибудь объяснить мне, почему компилятор (который настроен на оптимизацию) еще не находит это решение?
Дополнительная информация: Перед циклом есть некоторая настройка массивов, используемых в цикле, состоящая из преобразования их из целых чисел в массивы с плавающей запятой (для Accelerate) и последующего взятия sin и cos массива времени (длиной 16 строк). Все массивы с плавающей запятой (8 массивов x 1000 элементов) объявляются первыми в функции (после проверки правильности параметров). Они всегда объявляются одного и того же размера (константой), потому что в противном случае производительность страдала из-за незначительного сокращения занимаемой площади. Я пробовал сделать их глобальными, но я думаю, что компилятор уже понял это, так как производительность не изменилась. Цикл состоит из 25 строк.
---Дополнения---
Да, "-Os" - это флаг. (в любом случае по умолчанию в Xcode: самый быстрый, самый маленький)
(ниже по памяти - не пытайтесь скомпилировать его, потому что я не вставил такие вещи, как шаг (который равен 1) и т. д. Однако все вызовы Accelerate есть)
передаваемые параметры: inttimearray, intamparray, length, scale1, scale2, amp
float trigarray1[maxsize];
float trigarray2[maxsize];
float trigarray3[maxsize];
float trigarray4[maxsize];
float trigarray5[maxsize];
float temparray[maxsize];
float amparray[maxsize]; //these two make the most change
float timearray[maxsize]; //these two make the most change
vDSP_vfltu32(inttimearray,timearray,length); //convert to float array
vDSP_vflt16(intamparray,amparray,length); //convert to float array
vDSP_vsmul(timearray,scale1,temparray,length); //scale time and store in temp
vvcosf(temparray,trigarray3,length); //cos of temparray
vvsinf(temparray,trigarray4,length); //sin of temparray
vDSP_vneg(trigarray4,trigarray5,length); //negative of trigarray4
vDSP_vsmul(timearray,scale2,temparray,length); //scale time and store in temp
vvcosf(temparray,trigarray1,length); //cos of temparray
vvsinf(temprray,trigarray2,length); //sin of temparray
float ysum;
vDSP_sve(amparray,ysum,length); //sum of amparray
float csum, ssum, ccsum, sssum, cssum, ycsum, yssum;
for (i = 0; i<max; i++) {
vDSP_sve(trigarray1,csum,length); //sum of trigarray1
vDSP_sve(trigarray2,ssum,length); //sum of trigarray2
vDSP_svesq(trigarray1,ccsum,length); //sum of trigarray1^2
vDSP_svesq(trigarray2,sssum,length); //sum of trigarray2^2
vDSP_vmul(trigarray1,trigarray2,temparray,length); //temp = trig1*trig2
vDSP_sve(temparray,cssum,length); //sum of temp array
// 2 more sets of the above 2 lines, for the 2 remaining sums
amp[i] = (arithmetic of sums);
//trig identity to increase the sin/cos by a delta frequency
//vmma is a*b+c*d=result
vDSP_vmma (trigarray1,trigarray3,trigarray2,trigarray4,temparray,length);
vDSP_vmma (trigarray2,trigarray3,trigarray1,trigarray5,trigarray2,length);
memcpy(trigarray1,temparray,length*sizeof(float));
}
---Текущее решение---
Я сделал некоторые изменения следующим образом:
Все массивы объявлены выровненными и обнулены (я объясню далее), а maxsize теперь кратен 16.
__attribute__ ((align (16))) float timearray[maxsize] = {0};
Я обнулил все массивы, потому что теперь, когда длина меньше maxsize, я округляю длину до ближайшего числа, кратного 16, чтобы все зацикленные функции работали с шириной, кратной 16, не влияя на размер суммы.
Преимущества:
- Небольшой прирост производительности
- Скорость почти постоянна независимо от порядка объявления массивов (что теперь делается прямо перед тем, как они понадобятся, а не все в большом блоке)
- Скорость также почти постоянна для любой длины 16 (т. е. от 241 до 256 или от 225 до 240...), тогда как раньше, если длина менялась от 256 до 255, функция теряла производительность на 3+%.
В будущем (возможно, с этим кодом, поскольку требования к анализу все еще меняются), я понимаю, что мне нужно будет больше учитывать использование стека и выравнивание/фрагменты векторов. К сожалению, для этого кода я не могу сделать эти массивы статическими или глобальными, так как эта функция может вызываться более чем одним объектом одновременно.