При использовании закрепленной памяти в ArrayFire я получаю низкую производительность.
Я пробовал различные методы создания закрепленной памяти и создания из нее массивов, например. cudaMallocHost. Использование cudaMallocHost с cudaMemcpy довольно быстро (несколько сотен мкс), но тогда создание/инициализация массива arrayfire было очень медленным (~ 2-3 секунды). В итоге я придумал следующий метод и выделение занимает ~ 2-3 сек., но его можно перенести в другое место. Инициализация массива данными хоста проходит удовлетворительно (100-200 мкс), но теперь операции (в данном случае БПФ) мучительно медленны: ~ 400 мс. Я должен добавить, что входной сигнал имеет переменный размер, но для синхронизации я использовал образцы 64K (сложные двойники). Кроме того, я не привожу свою функцию синхронизации для краткости, но это не проблема, я измерял время, используя другие методы, и результаты согласуются.
// Use the Frequency-Smoothing method to calculate the full
// Spectral Correlation Density
// currently the whole function takes ~ 2555 msec. w/ signal 64K samples
// and window_length = 400 (currently not implemented)
void exhaustive_fsm(std::vector<std::complex<double>> signal, uint16_t window_length) {
// Allocate pinned memory (eventually move outside function)
// 2192 ms.
af::af_cdouble* device_ptr = af::pinned<af::af_cdouble>(signal.size());
// Init arrayfire array (eventually move outside function)
// 188 us.
af::array s(signal.size(), device_ptr, afDevice);
// Copy to device
// 289 us.
s.write((af::af_cdouble*) signal.data(), signal.size() * sizeof(std::complex<double>), afHost);
// FFT
// 351 ms. equivalent to:
// af::array fft = af::fft(s, signal.size());
af::array fft = zrp::timeit(&af::fft, s, signal.size());
fft.eval();
// Convolution
// Copy result to host
// free memory (eventually move outside function)
// 0 ms.
af::freePinned((void*) s.device<af::af_cdouble>());
// Return result
}
Как я уже сказал выше, БПФ занимает ~ 400 мс. Эта функция с использованием Armadillo занимает ~ 110 мс. включая свертку, БПФ с использованием FFTW занимает около 5 мс. Также на моей машине, используя пример ArrayFire FFT, я получаю следующие результаты (модифицированные для использования c64)
A = randu(1, N, c64);)
Сравнительный анализ 1-by-N CX fft
1 x 128: time: 29 us.
1 x 256: time: 31 us.
1 x 512: time: 33 us.
1 x 1024: time: 41 us.
1 x 2048: time: 53 us.
1 x 4096: time: 75 us.
1 x 8192: time: 109 us.
1 x 16384: time: 179 us.
1 x 32768: time: 328 us.
1 x 65536: time: 626 us.
1 x 131072: time: 1227 us.
1 x 262144: time: 2423 us.
1 x 524288: time: 4813 us.
1 x 1048576: time: 9590 us.
Так что единственная разница, которую я вижу, это использование закрепленной памяти. Есть идеи, где я ошибаюсь? Спасибо.
ИЗМЕНИТЬ
Я заметил, что при запуске примера AF FFT происходит значительная задержка перед распечаткой 1-го раза (хотя время не включает эту задержку). Поэтому я решил создать класс и перенести все выделения/освобождения в ctor/dtor. Из любопытства я также поместил БПФ в ctor, потому что я также заметил, что если я запускал второй БПФ, это занимало ~ 600 мкс. согласуется с моими тестами. Конечно, запуск «предварительного» БПФ, кажется, «инициализирует» что-то, и последующие БПФ выполняются намного быстрее. Должен быть лучший способ, я должен что-то упустить.