Эта часть документации [1] посвящена библиотеке реального времени для цифровой обработки сигналов, ЦОС (DSP run-time library). Предоставляемые библиотечными функциями службы включают такие алгоритмы как компандеры, фильтры, БПФ (Быстрое Преобразование Фурье, Fast Fourier Transform, FFT). Эти службы от Analog Devices работают как расширения к стандартному ANSI C. Непонятные термины и сокращения см. в статье Словарик [2].
Для дополнительной информации по используемым алгоритмам DSP и математическим функциям, на которых они основаны, см. книжку авторов W. J. Cody и W. Waite "Software Manual for the Elementary Functions", Englewood Cliffs, New Jersey: Prentice Hall, 1980.
Примечание: в дополнение к вызываемым пользователем функциям, которые описаны в этой статье, библиотека DSP run-time также содержит функции поддержки компилятора, которые выполняют те базовые операции над целыми типами и типами с плавающей точкой, которые компилятор не может генерировать самостоятельно. Эти функции вызываются из кода, генерируемого компилятором, чтобы реализовать преобразование базовых типов, операций с плавающей точкой (Blackfin не имеет аппаратной поддержки операций над числами с плавающей точкой), и т. д. Функции для поддержки компилятора не должны вызываться напрямую из кода пользователя.
В разделе "Руководство по библиотеке DSP Run-Time" содержится общая информация по библиотеке, приводится описание заголовочных подключаемых файлов, предназначенных для текущего релиза компилятора ccblkfn. В разделе "DSP Run-Time Library Reference" [1, 4] содержится полная справочная информация по каждой из библиотечных функций DSP run-time.
[Руководство по библиотеке DSP Run-Time]
Библиотека DSP Run-Time содержит функции, предназначенные для вызова из приложения пользователя процессора Blackfin.
Линковка DSP-библиотеки. Библиотека DSP run-time размещена в каталоге инсталляции VisualDSP++ (%ProgramFiles%\Analog Devices\VisualDSP 5.0\), в поддиректории Blackfin/lib. Предоставляются различные версии этой библиотеки, перечисленные в таблице 4-1.
Таблица 4-1. Файлы DSP-библиотеки (каталог Blackfin/lib).
Файл
Описание
libdsp532.dlb libdsp535.dlb libdsp561.dlb
DSP run-time library (библиотека функций кода реального времени выполнения, предназначенная для цифровой обработки сигналов).
libdsp532y.dlb libdsp535y.dlb libdsp561y.dlb
То же самое, но собранное с учетом исправления ошибок в зависимости от ревизии кристалла (с опцией командной строки -si-revision).
Версии библиотеки, которые содержат "532" в имени dlb-файла, собраны для использования процессорами ADSP-BF531, ADSP-BF532, ADSP-BF533, ADSP-BF534, ADSP-BF536, ADSP-BF537, ADSP-BF538 или ADSP-BF539. Версии библиотеки, которые содержат в имени файла "535", предназначены для процессоров ADSP-BF535. Версии библиотеки, которые содержат в имени файла "561", предназначены для работы с процессорами ADSP-BF561.
Версии библиотеки, имя файлов которых без расширения заканчиваются на "y" (например libdsp532y.dlb), собраны с опцией компилятора -si-revision, и включают все доступные способы обхода ошибок кремния (compiler workarounds) для аппаратных аномалий процессора (hardware anomalies). Подробнее см. описание ключа командной строки -si-revision в [5].
Когда приложение вызывает библиотечную функцию DSP, этот вызов создает ссылку на внешнюю функцию, которую разрешает линкер. Один из способов, которым линкеру указывают место нахождения библиотеки, будет использования файла настроек линкера по умолчанию (default linker description file, < имя_целевого_процессора >.ldf). Если для линковки приложения используется файл .ldf, настроенный пользователем, то добавьте к проекту подходящий библиотечный файл DSP run-time к файлу .ldf, который задан в проекте.
Примечание: вместо того, чтобы модифицировать пользовательский файл .ldf, используйте опцию командной строки -l (см. описание опций линкера в [1]), чтобы указать библиотеку, которую должен искать линкер. Например, опция -ldsp532 добавит к используемым линкером библиотекам файл libdsp532.dlb. Для дополнительной информации по файлам .ldf см. руководство по линкеру и утилитам VisualDSP++ (VisualDSP++ Linker and Utilities Manual).
Исходный код библиотечных функций DSP run-time также предоставляется вместе с VisualDSP++. По умолчанию библиотеки инсталлируются в директорию Blackfin/lib, и исходные коды библиотек копируются в директорию Blackfin/lib/src. Каждая функция находится в отдельном файле. Имя файла функции имеет расширение .asm или .c. Если Вы не хотите модифицировать библиотечные функции, то можете удалить этот каталог вместе с его содержимым, чтобы освободить место на диске.
Исходный код предоставлен для того, чтобы Вы смогли изменить какие-то определенные функции. Чтобы изменить эти файлы, необходимы профессиональные знания ассемблера Blackfin [6] и глубокое понимание рабочего окружения системы, в которой выполняется код (run-time environment). Дополнительную информацию см. в разделе "C/C++ Run-Time Model and Environment" руководства [1]. Перед модификацией исходного кода сделайте копию изменяемого файла с модифицированным именем, и соответственным образом переименуйте саму функцию. Тщательно проверяйте функцию перед её использованием в Вашей системе.
Примечание: Analog Devices предоставляет поддержку run-time библиотеки только в исходной текущей версии.
Атрибуты DSP-библиотеки. Библиотека DSP run-time содержит те же самые атрибуты, что и библиотека C/C++. Для дополнительной информации см. "Library Attributes" в разделе "C/C++ Run-Time Library" руководства [1].
Заголовочные файлы DSP-библиотеки. В них содержатся прототипы для библиотечных функций DSP. Когда соответствующий заголовочных файл подключается директивой #include, препроцессор компилятора использует прототипы в заголовочном файле, чтобы проверить каждый вызов функции в коде пользователя на корректность подставленных аргументов. Таблица 4-2 показывает заголовочные файлы DSP, которые включены в текущий релиз компилятора ccblkfn.
Таблица 4-2. Хедеры библиотеки DSP.
Файл
Описание
complex.h
Базовые арифметические функции для работы с комплексными числами.
cycle_count.h
Базовый набор макросов для анализа кода на предмет потраченных тактов процессора.
cycles.h
Подсчет тактов с накоплением статистики.
filter.h
Фильтры и трансформации (ЦОС).
matrix.h
Функции для работы с матрицами чисел.
stats.h
Статистические функции.
vector.h
Функции для работы с векторами (массивами).
window.h
Генераторы оконных функций (ЦОС).
complex.h. В этом заголовочном файле содержатся определения типов и базовые арифметические операции для переменных типа complex_float, complex_double, complex_long_double, complex_fract16 и complex_fract32. Комплексные функции, определенные в этом хедере, перечислены в таблице 4-3. Функции, которые работают с числами complex_fract16 и complex_fract32, используют арифметическое насыщение [6]. Тип данных complex_fract16 имеет 32-битное выравнивание.
Следующие структуры представляют комплексные числа в прямоугольных координатах:
complex_fract32 polar_fx_fr32 (long _Fract mag, long _Fract phase)
complex_double cexp (double a)
Комплексная экспонента.
complex_long_double cexpd (long double a)
complex_float cexpf (float a)
complex_double norm (complex_double a)
Нормализация.
complex_long_double normd (complex_long_double a)
complex_float normf (complex_float a)
cycle_count.h. Этот заголовочный файл предоставляет недорогой метод оценки скорости выполнения кода на языке C при помощи аппаратного счетчика циклов процессора. Функционал состоит из двух макросов и типа данных, как это описано в разделе "Счетчик тактов процессора".
cycles.h. Этот заголовочный файл определяет набор из 5 макросов и связанный с ними тип данных, который можно использовать для измерения прошедших тактов процессора при выполнении секций кода на языке C. Эти макросы могут записать сколько раз выполнилась определенная часть кода, и вычислить минимальное, среднее и максимальное количество используемых циклов. Возможности, доступные через этот заголовочный файл, описаны в разделе "Счетчик тактов процессора".
filter.h. Здесь содержатся функции для фильтров, используемых в обработке сигналов. Этот файл также включает компандеры A-law и ?-law, используемые приложениях компрессии и декомпрессии сигналов звукового диапазона. Этот заголовок также содержит функции, выполняющие ключевые трансформации сигнала, включая обработки FFT и конволюцию.
Библиотека предоставляет разные формы функции FFT, соответствующие radix-2, radix-4, и двумерным преобразованиям FFT. Количество точек предоставляется как аргумент. Заголовочный файл также определяет комплексную функцию FFT (cfftf_fr16) реализованную на основе оптимизированного алгоритма radix-4. Однако функция cfftf_fr16 задает определенные требования к вычислительным ресурсам, которые могут не подойти для некоторых приложений. Таблица вращения (twiddle table) для функций FFT предоставляется как отдельный аргумент, и она обычно вычисляется один раз на этапе инициализации программы.
Внимание: библиотечная функция cfftf_fr16 задействует регистр M3, который может использоваться эмулятором (аппаратный отладчик JTAG) для переключения контекста. За дополнительной информацией обратитесь к руководству по аппаратному отладчику.
Для инициализации таблицы вращения предоставлены библиотечные функции. Таблица вращения может быть приспособлена к нескольким преобразованиям FFT разных размеров путем выделения таблицы максимального размера, после чего нужно использовать аргумент stride функции FFT, чтобы указать шаг, с которым нужно использовать таблицу. Если аргумент stride установлен в 1, то функция FFT будет использовать всю таблицу целиком; если FFT использует только половину точек самого большого размера, то stride задается как 2.
Имеется функция магнитуды FFT, которая вычисляет нормализованную мощность спектра FFT.
Функции, определенные в заголовочном файле filter.h, перечислены в таблицах 4-4 и 4-5, и также описаны в разделе "DSP Run-Time Library Reference" [1, 4].
void coeff_iirdf1_fr32 (const long double acoeff[], const long double bcoeff[], fract32 coeff[], int nstages)
void coeff_iirdf1_fx32 (const long double acoeff[], const long double bcoeff[], long _Fract coeff[], int nstages)
Таблица 4-5. Функции трасформаций.
Прототип функции
Описание
Быстрое преобразование Фурье
void twidfft_fr16 (complex_fract16 twiddle_table[], int fft_size)
Генерация множителей таблицы вращения для FFT (FFT Twiddle Factors).
void twidfftrad2_fr16 (complex_fract16 twiddle_table[], int fft_size)
Генерация множителей таблицы вращения для Radix-2 FFT.
void twidfftrad2_fr32 (complex_fract32 twiddle_table[], int fft_size)
void twidfftrad4_fr16 (complex_fract16 twiddle_table[], int fft_size)
Генерация множителей таблицы вращения для Radix-4 FFT.
void twidfft2d_fr16 (complex_fract16 twiddle_table[], int fft_size)
Генерация множителей таблицы вращения для 2D FFT.
void twidfft2d_fr32 (complex_fract32 twiddle_table[], int fft_size)
void twidfftf_fr16 (complex_fract16 twiddle_table[], int fft_size)
Генерация множителей таблицы вращения для оптимизированного FFT.
void twidfftf_fr32 (complex_fract32 twiddle_table[], int fft_size)
void fft_magnitude_fr16 (const complex_fract16 input[], fract16 output[], int fft_size, int block_exponent, int mode)
Магнитуда FFT.
void fft_magnitude_fr32 (const complex_fract32 input[], fract32 output[], int fft_size, int block_exponent, int mode)
void cfft_fr16 (const complex_fract16 *input, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
Radix-2 FFT по N точкам, с комплексными входными данными.
void cfft_fr32 (const complex_fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void rfft_fr16 (const fract16 *input, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
Radix-2 FFT по N точкам, с входными данными в виде реальных чисел.
void rfft_fx_fr16 (const _Fract *input, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void rfft_fr32 (const fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void rfft_fx_fr32 (const long _Fract *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void ifft_fr16 (const complex_fract16 *input, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
Radix-2 iFFT по N точкам.
void ifft_fr32 (const complex_fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void cfftrad4_fr16 (const complex_fract16 *input, complex_fract16 *temp, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int block_exponent, int scale_method)
Radix-4 FFT по N точкам с комплексными числами на входе.
void rfftrad4_fr16 (const fract16 *input, complex_fract16 *temp, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int block_exponent, int scale_method)
Radix-4 FFT по N точкам с числами на входе в реальной форме.
void ifftrad4_fr16 (const complex_fract16 *input, complex_fract16 *temp, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int block_exponent, int scale_method)
Radix-4 iFFT по N точкам.
void cfftf_fr16 (const complex_fract16 *input, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size)
Radix-4 FFT по N точкам с быстрым алгоритмом, работающий с комплексными входными числами.
void cfft2d_fr16 (const complex_fract16 *input, complex_fract16 *temp, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int block_exponent, int scale_method)
2D FFT по NxN точкам, работающий с комплексными входными числами.
void cfft2d_fr32 (const complex_fract32 *input, complex_fract32 *temp, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size)
void rfft2d_fr16 (const fract16 *input, complex_fract16 *temp, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int block_exponent, int scale_method)
2D FFT по NxN точкам, работающий с входными данными в виде реальных чисел.
void rfft_fx_fr16 (const _Fract *input, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void rfft_fr32 (const fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void rfft_fx_fr32 (const long _Fract *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size, int *block_exponent, int scale_method)
void ifft2d_fr16 (const complex_fract16 *input, complex_fract16 *temp, complex_fract16 *output, const complex_fract16 *twiddle_table, int twiddle_stride, int fft_size, int block_exponent, int scale_method)
2D iFFT по NxN точкам.
void ifft2d_fr32 (const complex_fract32 *input, complex_fract32 *temp, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size)
void cfftf_fr32 (const complex_fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size)
Mixed-Radix FFT по N точкам, с быстрым алгоритмом, работающий с комплексными входными числами.
void ifftf_fr32 (const complex_fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size)
Mixed-Radix iFFT по N точкам, с быстрым алгоритмом.
void rfftf_fr32 (const complex_fract32 *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size)
Mixed-Radix FFT по N точкам, с быстрым алгоритмом, работающий с реальными входными числами.
void rfftf_fx_fr32 (const long _Fract *input, complex_fract32 *output, const complex_fract32 *twiddle_table, int twiddle_stride, int fft_size)
Свертки (Convolutions)
void convolve_fr16 (const fract16 input_x[], int length_x, const fract16 input_y[], int length_y, fract16 output[])
Простая свертка.
void convolve_fr32 (const fract32 input_x[], int length_x, const fract32 input_y[], int length_y, fract32 output[])
void convolve_fx16 (const _Fract input_x[], int length_x, const _Fract input_y[], int length_y, _Fract output[])
void convolve_fx32 (const long _Fract input_x[], int length_x, const long _Fract input_y[], int length_y, long _Fract output[])
void conv2d_fr16 (const fract16 *input_x, int rows_x, int columns_x, const fract16 *input_y, int rows_y, int columns_y, fract16 *output)
2D свертка.
void conv2d_fx16 (const _Fract *input_x, int rows_x, int columns_x, const _Fract *input_y, int rows_y, int columns_y, _Fract *output)
void conv2d_fr32 (const fract32 *input_x, int rows_x, int columns_x, const fract32 *input_y, int rows_y, int columns_y, fract32 *output)
void conv2d_fx32 (const long _Fract *input_x, int rows_x, int columns_x, const long _Fract *input_y, int rows_y, int columns_y, long _Fract *output)
void conv2d3x3_fr16 (const fract16 *input_x, int rows_x, int columns_x, const fract16 *input_y, fract16 *output)
2D свертка матрицы 3x3.
void conv2d3x3_fx16 (const _Fract *input_x, int rows_x, int columns_x, const _Fract *input_y, _Fract *output)
void conv2d3x3_fr32 (const fract32 *input_x, int rows_x, int columns_x, const fract32 *input_y, fract32 *output)
void conv2d3x3_fx32 (const long _Fract *input_x, int rows_x, int columns_x, const long _Fract *input_y, long _Fract *output)
void a_compress (const short input[], short output[], int length)
A-law компрессор.
void a_expand (const short input[], short output[], int length)
A-law экспандер.
void mu_compress (const short input[], short output[], int length)
μ-law компрессор.
void mu_expand (const char input[], short output[], int length)
μ-law экспандер.
math.h. Здесь определены стандартные математические функции с аргументами типов float и long double, и в некоторых случаях математические функции определены для типов fract16 и fract32, и встроенных C-типов данных _Fract и long _Fract.
Таблица 4-6 суммарно перечисляет функции, определенные в заголовочном файле math.h. Описания этих функций даны в double-версиях функций раздела "C Run-Time Library Reference" руководства [1].
Хедер math.h также предоставляет прототипы для дополнительных математических функций (clip, copysign, max и min), и целочисленную функцию (countones). Описание этих функций см. в разделе "DSP Run-Time Library Reference" [1, 4].
Таблица 4-6. Математические функции.
Прототип функции
Описание
double fabs (double x)
Абсолютное значение комплексного числа.
float fabsf (float x)
long double fabsd (long double x)
double alog (double x)
Антилогарифм.
float alogf (float x)
long double alogd (long double x)
double alog10 (double x)
Антилогарифм по основанию 10.
float alog10f (float x)
long double alog10d (long double x)
double acos (double x)
Арккосинус.
float acosf (float x)
long double acosd (long double x)
fract16 acos_fr16 (fract16 x)
_Fract acos_fx16 (_Fract x)
fract32 acos_fr32 (fract32 x)
long _Fract acos_fx32 (long _Fract x)
double asin (double x)
Арксинус.
float asinf (float x)
long double asind (long double x)
fract16 asin_fr16 (fract16 x)
_Fract asin_fx16 (_Fract x)
fract32 asin_fr32 (fract32 x)
long _Fract asin_fx32 (long _Fract x)
double atan (double x)
Арктангенс.
float atanf (float x)
long double atand (long double x)
fract16 atan_fr16 (fract16 x)
_Fract atan_fx16 (_Fract x)
fract32 atan_fr32 (fract32 x)
long _Fract atan_fx32 (long _Fract x)
double atan2 (double y, double x)
Арктангенс частного.
float atan2f (float y, float x)
long double atan2d (long double y, long double x)
fract16 atan2_fr16 (fract16 y, fract16 x)
fract16 atan2_fr16 (fract16 y, fract16 x)
fract32 atan2_fr32 (fract32 y, fract32 x)
long _Fract atan2_fx32 (long _Fract y, long _Fract x)
double ceil (double x)
Округление.
float ceilf (float x)
long double ceild (long double x)
double cos (double x)
Косинус.
float cosf (float x)
long double cosd (long double x)
fract16 cos_fr16 (fract16 x)
_Fract cos_fx16 (_Fract x)
fract32 cos_fr32 (fract32 x)
long _Fract cos_fx32 (long _Fract x)
double cot (double x)
Котангенс.
float cotf (float x)
long double cotd (long double x)
double cosh (double x)
Гиперболический косинус.
float coshf (float x)
long double coshd (long double x)
double exp (double x)
Экспонента.
float expf (float x)
long double expd (long double x)
double floor (double x)
Наибольшее целое, которое меньше или равно x.
float floorf (float x)
long double floord (long double x)
double fmod (double x, double y)
Остаток в формате числа с плавающей точкой.
float fmodf (float x, float y)
long double fmodd (long double x, long double y)
double frexp (double x, int *n)
Получение мантиссы и экспоненты.
float frexpf (float x, int *n)
long double frexpd (long double x, int *n)
int isnanf (float x)
Проверка: это не число?
int isnan (double x)
int isnand (long double x)
int isinff (float x)
Проверка: это бесконечность?
int isinf (double x)
int isinfd (long double x)
double ldexp(double x, int n)
Умножение на число, равное степени числа 2.
float ldexpf(float x, int n)
long double ldexpd (long double x, int n)
double log (double x)
Натуральный логарифм.
float logf (float x)
long double logd (long double x)
double log10 (double x)
Логарифм по основанию 10.
float log10f (float x)
long double log10d (long double x)
double modf (double x, double *i)
Получение целой и дробной части.
float modff (float x, float *i)
long double modfd (long double x, long double *i)
double pow (double x, double y)
Возведение в степень.
float powf (float x, float y)
long double powd (long double x, long double y)
double rsqrt (double x)
Взаимный квадратный корень.
float rsqrtf (float x)
long double rsqrtd (long double x)
double sin (double x)
Синус.
float sinf (float x)
long double sind (long double x)
fract16 sin_fr16 (fract16 x)
_Fract sin_fx16 (_Fract x)
fract32 sin_fr32 (fract32 x)
long _Fract sin_fx32 (long _Fract x)
double sinh (double x)
Гиперболический синус.
float sinhf (float x)
long double sinhd (long double x)
double sqrt (double x)
Квадратный корень.
float sqrtf (float x)
long double sqrtd (long double x)
fract16 sqrt_fr16 (fract16 x)
fract32 sqrt_fr32 (fract32 x)
_Fract sqrt_fx16 (_Fract x)
long _Fract sqrt_fx32 (long _Fract x)
double tan (double x)
Тангенс.
float tanf (float x)
long double tand (long double x)
fract16 tan_fr16 (fract16 x)
fract32 tan_fr32 (fract32 x)
_Fract tan_fx16 (_Fract x)
long _Fract tan_fx32 (long _Fract x)
double tanh (double x)
Гиперболический тангенс.
float tanhf (float x)
long double tanhd (long double x)
matrix.h. Здесь находятся матричные функции для работы с матрицами реальных и комплексных чисел, для операций матрица-скаляр и матрица-матрица. Описание комплексных чисел см. в описании заголовочного файла complex.h.
Матричные функции перечислены в таблице 4-7. Они работают с типами fract16, fract32, complex_fract16 и complex_fract32, и со встроенными C-типами данных _Fract и long _Fract, с использованием арифметики насыщения [6].
Таблица 4-7. Матричные функции.
Прототип функции
Описание
void matsadd (const double *matrix, double scalar, int rows, int columns, double *out)
Прибавление скаляра к матрице реальных чисел.
void matsaddf (const float *matrix, float scalar, int rows, int columns, float *out)
void matsaddd (const long double *matrix, long double scalar, int rows, int columns, long double *out)
void matsadd_fr16 (const fract16 *matrix, fract16 scalar, int rows, int columns, fract16 *out)
void matsadd_fr32 (const fract32 *matrix, fract32 scalar, int rows, int columns, fract32 *out)
void matsadd_fx16 (const _Fract *matrix, _Fract scalar, int rows, int columns, _Fract *out)
void matsadd_fx32 (const long _Fract *matrix, long _Fract scalar, int rows, int columns, long _Fract *out)
void matssub (const double *matrix, double scalar, int rows, int columns, double *out)
Вычитание скаляра из матрицы реальных чисел.
void matssubf (const float *matrix, float scalar, int rows, int columns, float *out)
void matssubd (const long double *matrix, long double scalar, int rows, int columns, long double *out)
void matssub_fr16 (const fract16 *matrix, fract16 scalar, int rows, int columns, fract16 *out)
void matssub_fr32 (const fract32 *matrix, fract32 scalar, int rows, int columns, fract32 *out)
void matssub_fx16 (const _Fract *matrix, _Fract scalar, int rows, int columns, _Fract *out)
void matssub_fx32 (const long _Fract *matrix, long _Fract scalar, int rows, int columns, long _Fract *out)
void matsmlt (const double *matrix, double scalar, int rows, int columns, double *out)
Умножение матрицы на скаляр.
void matsmltf (const float *matrix, float scalar, int rows, int columns, float *out)
void matsmltd (const long double *matrix, long double scalar, int rows, int columns, long double *out)
void matsmlt_fr16 (const fract16 *matrix, fract16 scalar, int rows, int columns, fract16 *out)
void matsmlt_fr32 (const fract32 *matrix, fract32 scalar, int rows, int columns, fract32 *out)
void matsmlt_fx16 (const _Fract *matrix, _Fract scalar, int rows, int columns, _Fract *out)
void matsmlt_fx32 (const long _Fract *matrix, long _Fract scalar, int rows, int columns, long _Fract *out)
void matmadd (const double *matrix_a, const double *matrix_b, int rows, int columns, double *out)
Сложение матриц реальных чисел.
void matmaddf (const float *matrix_a, const float *matrix_b, int rows, int columns, float *out)
void matmaddd (const long double *matrix_a, const long double *matrix_b, int rows, int columns, long double *out)
void matmadd_fr16 (const fract16 *matrix_a, const fract16 *matrix_b, int rows, int columns, fract16 *out)
void matmadd_fr32 (const fract32 *matrix_a, const fract32 *matrix_b, int rows, int columns, fract32 *out)
void matmadd_fx16 (const _Fract *matrix_a, const _Fract *matrix_b, int rows, int columns, _Fract *out)
void matmadd_fx32 (const long _Fract *matrix_a, const long _Fract *matrix_b, int rows, int columns, long _Fract *out)
void matmsub (const double *matrix_a, const double *matrix_b, int rows, int columns, double *out)
Вычитание матриц реальных чисел.
void matmsubf (const float *matrix_a, const float *matrix_b, int rows, int columns, float *out)
void matmsubd (const long double *matrix_a, const long double *matrix_b, int rows, int columns, long double *out)
void matmsub_fr16 (const fract16 *matrix_a, const fract16 *matrix_b, int rows, int columns, fract16 *out)
void matmsub_fr32 (const fract32 *matrix_a, const fract32 *matrix_b, int rows, int columns, fract32 *out)
void matmsub_fx16 (const _Fract *matrix_a, const _Fract *matrix_b, int rows, int columns, _Fract *out)
void matmsub_fx32 (const long _Fract *matrix_a, const long _Fract *matrix_b, int rows, int columns, long _Fract *out)
void matmmlt (const double *matrix_a, int rows_a, int columns_a, const double *matrix_b, int columns_b, double *out)
Умножение матриц реальных чисел.
void matmmltf (const float *matrix_a, int rows_a, int columns_a, const float *matrix_b, int columns_b, float *out)
void matmmltd (const long double *matrix_a, int rows_a, int columns_a, const long double *matrix_b, int columns_b, long double *out)
void matmmlt_fr16 (const fract16 *matrix_a, int rows_a, int columns_a, const fract16 *matrix_b, int columns_b, fract16 *out)
void matmmlt_fr32 (const fract32 *matrix_a, int rows_a, int columns_a, const fract32 *matrix_b, int columns_b, fract32 *out)
void matmmlt_fx16 (const _Fract *matrix_a, int rows_a, int columns_a, const _Fract *matrix_b, int columns_b, _Fract *out)
void matmmlt_fx32 (const long _Fract *matrix_a, int rows_a, int columns_a, const long _Fract *matrix_b, int columns_b, long _Fract *out)
void cmatsadd (const complex_double *matrix, complex_double scalar, int rows, int columns, complex_double *out)
Прибавление скаляра к матрице комплексных чисел.
void cmatsaddf (const complex_float *matrix, complex_float scalar, int rows, int columns, complex_float *out)
void cmatsaddd (const complex_long_double *matrix, complex_long_double scalar, int rows, int columns, complex_long_double *out)
void cmatsadd_fr16 (const complex_fract16 *matrix, complex_fract16 scalar, int rows, int columns, complex_fract16 *out)
void cmatsadd_fr32 (const complex_fract32 *matrix, complex_fract32 scalar, int rows, int columns, complex_fract32 *out)
void cmatssub (const complex_double *matrix, complex_double scalar, int rows, int columns, complex_double *out)
Вычитание скаляра из матрицы комплексных чисел.
void cmatssubf (const complex_float *matrix, complex_float scalar, int rows, int columns, complex_float *out)
void cmatssubd (const complex_long_double *matrix, complex_long_double scalar, int rows, int columns, complex_long_double *out)
void cmatssub_fr16 (const complex_fract16 *matrix, complex_fract16 scalar, int rows, int columns, complex_fract16 *out)
void cmatssub_fr32 (const complex_fract32 *matrix, complex_fract32 scalar, int rows, int columns, complex_fract32 *out)
void cmatsmlt (const complex_double *matrix, complex_double scalar, int rows, int columns, complex_double *out)
Умножение матрицы комплексных чисел на скаляр.
void cmatsmltf (const complex_float *matrix, complex_float scalar, int rows, int columns, complex_float *out)
void cmatsmltd (const complex_long_double *matrix, complex_long_double scalar, int rows, int columns, complex_long_double *out)
void cmatsmlt_fr16 (const complex_fract16 *matrix, complex_fract16 scalar, int rows, int columns, complex_fract16 *out)
void cmatsmlt_fr32 (const complex_fract32 *matrix, complex_fract32 scalar, int rows, int columns, complex_fract32 *out)
void cmatmadd (const complex_double *matrix_a, const complex_double *matrix_b, int rows, int columns, complex_double *out)
Умножение матриц комплексных чисел.
void cmatmaddf (const complex_float *matrix_a, const complex_float *matrix_b, int rows, int columns, complex_float *out)
void cmatmaddd (const complex_long_double *matrix_a, const complex_long_double *matrix_b, int rows, int columns, complex_long_double *out)
void cmatmadd_fr16 (const complex_fract16 *matrix_a, const complex_fract16 *matrix_b, int rows, int columns, complex_fract16 *out)
void cmatmadd_fr32 (const complex_fract32 *matrix_a, const complex_fract32 *matrix_b, int rows, int columns, complex_fract32 *out)
void cmatmsub (const complex_double *matrix_a, const complex_double *matrix_b, int rows, int columns, complex_double *out)
Вычитание матриц комплексных чисел.
void cmatmsubf (const complex_float *matrix_a, const complex_float *matrix_b, int rows, int columns, complex_float *out)
void cmatmsubd (const complex_long_double *matrix_a, const complex_long_double *matrix_b, int rows, int columns, complex_long_double *out)
void cmatmsub_fr16 (const complex_fract16 *matrix_a, const complex_fract16 *matrix_b, int rows, int columns, complex_fract16 *out)
void cmatmsub_fr32 (const complex_fract32 *matrix_a, const complex_fract32 *matrix_b, int rows, int columns, complex_fract32 *out)
void cmatmmlt (const complex_double *matrix_a, int rows_a, int columns_a, const complex_double *matrix_b, int columns_b, complex_double *out)
Умножение матриц комплексных чисел.
void cmatmmltf (const complex_float *matrix_a, int rows_a, int columns_a, const complex_float *matrix_b, int columns_b, complex_float *out)
void cmatmmltd (const complex_long_double *matrix_a, int rows_a, int columns_a, const complex_long_double *matrix_b, int columns_b, complex_long_double *out)
void cmatmmlt_fr16 (const complex_fract16 *matrix_a, int rows_a, int columns_a, const complex_fract16 *matrix_b, int columns_b, complex_fract16 *out)
void cmatmmlt_fr32 (const complex_fract32 *matrix_a, int rows_a, int columns_a, const complex_fract32 *matrix_b, int columns_b, complex_fract32 *out)
void transpm (const double *matrix, int rows, int columns, double *out)
Транспонирование матрицы.
void transpmf (const float *matrix, int rows, int columns, float *out)
void transpmd (const long double *matrix, int rows, int columns, long double *out)
void transpm_fr16 (const fract16 *matrix, int rows, int columns, fract16 *out)
void transpm_fr32 (const fract32 *matrix, int rows, int columns, fract32 *out)
void transpm_fx16 (const _Fract *matrix, int rows, int columns, _Fract *out)
void transpm_fx32 (const long _Fract *matrix, int rows, int columns, long _Fract *out)
void ctranspm (const complex_double *matrix, int rows, int columns, complex_double *out)
Транспонирование матрицы комплексных чисел.
void ctranspmf (const complex_float *matrix, int rows, int columns, complex_float *out)
void ctranspmd (const complex_long_double *matrix, int rows, int columns, complex_long_double *out)
void ctranspm_fr16 (const complex_fract16 *matrix, int rows, int columns, complex_fract16 *out)
void ctranspm_fr32 (const complex_fract32 *matrix, int rows, int columns, complex_fract32 *out)
В большинстве прототипов функций используются следующие определения:
*matrix_a
указатель на входную матрицу matrix_a[][]
*matrix_b
указатель на входную матрицу matrix_b[][]
scalar
входной скаляр
rows
количество строк
columns
количество столбцов
*out
указатель на выходную матрицу out[][]
В функциях умножения матрица*матрица параметры rows_a и columns_a это размерности матрицы a, и rows_b и columns_b это размерности матрицы b.
Функции, описанные в хедере matrix.h, подразумевают, что входные аргументы массива являются константами; таким образом, их содержимое не изменяется подпрограммой. В частности, это означает, что входные аргументы не перекрываются выходным аргументом.
stats.h. Функции этого заголовочного файла перечислены в таблице 4-8 и подробно описаны в разделе "DSP Run-Time Library Reference" [1, 4].
Таблица 4-8. Статистические функции.
Прототип функции
Описание
void autocohf (const float samples[], int sample_length, int lags, float out[])
Автокогерентность.
void autocoh (const double samples[], int sample_length, int lags, double out[])
void autocohd (const long double samples[], int sample_length, int lags, long double out[])
void autocoh_fr16 (const fract16 samples[], int sample_length, int lags, fract16 out[])
void autocoh_fr32 (const fract32 samples[], int sample_length, int lags, fract32 out[])
void autocoh_fx16 (const _Fract samples[], int sample_length, int lags, _Fract out[])
void autocoh_fx32 (const long _Fract samples[], int sample_length, int lags, long _Fract out[])
void autocorrf (const float samples[], int sample_length, int lags, float out[])
Автокорреляция.
void autocorr (const double samples[], int sample_length, int lags, double out[])
void autocorrd (const long double samples[], int sample_length, int lags, long double out[])
void autocorr_fr16 (const fract16 samples[], int sample_length, int lags, fract16 out[])
void autocorr_fr32 (const fract32 samples[], int sample_length, int lags, fract32 out[])
void autocorr_fx16 (const _Fract samples[], int sample_length, int lags, _Fract out[])
void autocorr_fx32 (const long _Fract samples[], int sample_length, int lags, long _Fract out[])
void crosscohf (const float samples_a[], const float samples_b[], int sample_length, int lags, float out[])
Когерентность (Cross-coherence).
void crosscoh (const double samples_a[], const double samples_b[], int sample_length, int lags, double out[])
void crosscohd (const long double samples_a[], const long double samples_b[], int sample_length, int lags, long double out[])
void crosscoh_fr16 (const fract16 samples_a[], const fract16 samples_b[], int sample_length, int lags, fract16 out[])
void crosscoh_fr32 (const fract32 samples_a[], const fract32 samples_b[], int sample_length, int lags, fract32 out[])
void crosscoh_fx16 (const _Fract samples_a[], const _Fract samples_b[], int sample_length, int lags, _Fract out[])
void crosscoh_fx32 (const long _Fract samples_a[], const long _Fract samples_b[], int sample_length, int lags, long _Fract out[])
void crosscorrf (const float samples_a[], const float samples_b[], int sample_length, int lags, float out[])
Корреляция (Cross-correlation).
void crosscorr (const double samples_a[], const double samples_b[], int sample_length, int lags, double out[])
void crosscorrd (const long double samples_a[], const long double samples_b[], int sample_length, int lags, long double out[])
void crosscorr_fr16 (const fract16 samples_a[], const fract16 samples_b[], int sample_length, int lags, fract16 out[])
void crosscorr_fx16 (const _Fract samples_a[], const _Fract samples_b[], int sample_length, int lags, _Fract out[])
void crosscorr_fr32 (const fract32 samples_a[], const fract32 samples_b[], int sample_length, int lags, fract32 out[])
void crosscorr_fx32 (const long _Fract samples_a[], const long _Fract samples_b[], int sample_length, int lags, long _Fract out[])
void histogramf (const float samples[], int out[], float max_sample, float min_sample, int sample_length, int bin_count)
Гистограмма.
void histogram (const double samples[], int out[], double max_sample, double min_sample, int sample_length, int bin_count)
void histogramd (const long double samples[], int out[], long double max_sample, long double min_sample, int sample_length, int bin_count)
void histogram_fr16 (const fract16 samples[], int out[], fract16 max_sample, fract16 min_sample, int sample_length, int bin_count)
void histogram_fx16 (const _Fract samples[], int out[], _Fract max_sample, _Fract min_sample, int sample_length, int bin_count)
void histogram_fr32 (const fract32 samples[], int out[], fract32 max_sample, fract32 min_sample, int sample_length, int bin_count)
void histogram_fx32 (const long _Fract samples[], int out[], long _Fract max_sample, long _Fract min_sample, int sample_length, int bin_count)
float meanf (const float samples[], int sample_length)
Вычисление среднего значения.
double mean (const double samples[], int sample_length)
long double meand (const long double samples[], int sample_length)
fract16 mean_fr16 (const fract16 samples[], int sample_length)
_Fract mean_fx16 (const _Fract samples[], int sample_length)
fract32 mean_fr32 (const fract32 samples[], int sample_length)
long _Fract mean_fx32 (const long _Fract samples[], int sample_length)
float rmsf (const float samples[], int sample_length)
Вычисление среднеквадратического значения (RMS).
double rms (const double samples[], int sample_length)
long double rmsd (const long double samples[], int sample_length)
fract16 rms_fr16 (const fract16 samples[], int sample_length)
fract32 rms_fr32 (const fract32 samples[], int sample_length)
_Fract rms_fx16 (const _Fract samples[], int sample_length)
long _Fract rms_fx32 (const long _Fract samples[], int sample_length)
float varf (const float samples[], int sample_length)
Различие (Variance).
double var (const double samples[], int sample_length)
long double vard (const long double samples[], int sample_length)
fract16 var_fr16 (const fract16 samples[], int sample_length)
_Fract var_fx16 (const _Fract samples[], int sample_length)
fract32 var_fr32 (const fract32 samples[], int sample_length)
long _Fract var_fx32 (const long _Fract samples[], int sample_length)
int zero_crossf (const float samples[], int sample_length)
Подсчет переходов через ноль (Count Zero Crossing).
int zero_cross (const double samples[], int sample_length)
int zero_crossd (const long double samples[], int sample_length)
int zero_cross_fr16 (const fract16 samples[], int sample_length)
int zero_cross_fx16 (const _Fract samples[], int sample_length)
int zero_cross_fr32 (const fract32 samples[], int sample_length)
int zero_cross_fx32 (const long _Fract samples[], int sample_length)
vector.h. Здесь содержатся функции для работы с реальными и комплексными векторами, где поддерживаются операции как вектор-скаляр, так и вектор-вектор. Описание комплексных типов см. в описании заголовочного файла complex.h.
Функции, определенные в vector.h, перечислены в таблице 4-9. Векторные функции могут работать с типами данных complex_fract16 и complex_fract32, и со встроенными C типами данных _Fract и long _Fract, с использованием арифметики насыщения.
В столбце "Прототип функции" определения vec[], vec_a[] и vec_b[] это входные векторы, scalar это входной скаляр, out[] это выходной вектор, и sample_length это количество элементов. Функции подразумевают, что входные аргументы массивов являются константами; таким образом, они не будут изменены в теле подпрограммы. В частности это означает, что входные аргументы не могут перекрывать выходной аргумент. Обычно самая лучшая производительность достигается для векторных функций в том случае, когда входные и выходные векторы находятся в разных физических банках памяти [6, 7]. Код, структурированный таким образом, позволяет избежать потери вычислительных ресурсов на коллизии банков памяти.
double vecdot (const double vec_a[], const double vec_b[], int length)
Скалярное произведение векторов реальных чисел (Real Vector Dot Product).
long double vecdotd (const long double vec_a[], const long double vec_b[], int length)
float vecdotf (const float vec_a[], const float vec_b[], int length)
fract16 vecdot_fr16 (const fract16 vec_a[], const fract16 vec_b[], int length)
_Fract vecdot_fx16 (const _Fract vec_a[], const _Fract vec_b[], int length)
fract32 vecdot_fr32 (const fract32 vec_a[], const fract32 vec_b[], int length)
long _Fract vecdot_fx32 (const long _Fract vec_a[], const long _Fract vec_b[], int length)
complex_double cvecdot (const complex_double vec_a[], const complex_double vec_b[], int length)
Скалярное произведение векторов комплексных чисел (Complex Vector Dot Product).
complex_long_double cvecdotd (const complex_long_double vec_a[], const complex_long_double vec_b[], int length)
complex_float cvecdotf (const complex_float vec_a[], const complex_float vec_b[], int length)
complex_fract16 cvecdot_fr16 (const complex_fract16 vec_a[], const complex_fract16 vec_b[], int length)
complex_fract32 cvecdot_fr32 (const complex_fract32 vec_a[], const complex_fract32 vec_b[], int length)
window.h. Здесь содержатся функции для генерации окон по разным методикам (так называемые оконные функции). Они перечислены в таблице 4-10, и подробно описаны в разделе "DSP Run-Time Library Reference" [1, 4].
Для всех оконных функций параметр шага (window_stride) используется для определения пространства между значениями окна. Параметр длины окна (window_size) равен количеству элементов в окне. Таким образом, для window_stride=2 и window_length=10 требуется массив длиной 20, где каждая вторая запись остается нетронутой.
Таблица 4-10. Функции генератора окна.
Прототип функции
Описание
void gen_bartlett_fr16 (fract16 bartlett_window[], int window_stride, int window_size)
Окно Бартлетта.
void gen_bartlett_fx16 (_Fract bartlett_window[], int window_stride, int window_size)
void gen_bartlett_fr32 (fract32 bartlett_window[], int window_stride, int window_size)
void gen_bartlett_fx32 (long _Fract bartlett_window[], int window_stride, int window_size)
void gen_blackman_fr16 (fract16 blackman_window[], int window_stride, int window_size)
Окно Блэкмана.
void gen_blackman_fx16 (_Fract blackman_window[], int window_stride, int window_size)
void gen_blackman_fr32 (fract32 blackman_window[], int window_stride, int window_size)
void gen_blackman_fx32 (long _Fract blackman_window[], int window_stride, int window_size)
void gen_gaussian_fr16 (fract16 gaussian_window[], float alpha, int window_stride, int window_size)
Окно Гаусса.
void gen_gaussian_fx16 (_Fract gaussian_window[], float alpha, int window_stride, int window_size)
void gen_gaussian_fr32 (fract32 gaussian_window[], long double alpha, int window_stride, int window_size)
void gen_gaussian_fx32 (long _Fract gaussian_window[], long double alpha, int window_stride, int window_size)
void gen_hamming_fr16 (fract16 hamming_window[], int window_stride, int window_size)
Окно Хемминга.
void gen_hamming_fx16 (_Fract hamming_window[], int window_stride, int window_size)
void gen_hamming_fr32 (fract32 hamming_window[], int window_stride, int window_size)
void gen_hamming_fx32 (long _Fract hamming_window[], int window_stride, int window_size)
void gen_hanning_fr16 (fract16 hanning_window[], int window_stride, int window_size)
Окно Хеннинга (Ханна).
void gen_hanning_fx16 (_Fract hanning_window[], int window_stride, int window_size)
void gen_hanning_fr32 (fract32 hanning_window[], int window_stride, int window_size)
void gen_hanning_fx32 (long _Fract hanning_window[], int window_stride, int window_size)
void gen_harris_fr16 (fract16 harris_window[], int window_stride, int window_size)
Окно Харриса.
void gen_harris_fx16 (_Fract harris_window[], int window_stride, int window_size)
void gen_harris_fr32 (fract32 harris_window[], int window_stride, int window_size)
void gen_harris_fx32 (long _Fract harris_window[], int window_stride, int window_size)
void gen_kaiser_fr16 (fract16 kaiser_window[], float beta, int window_stride, int window_size)
Окно Кайзера.
void gen_kaiser_fx16 (_Fract kaiser_window[], float beta, int window_stride, int window_size)
void gen_kaiser_fr32 (fract32 kaiser_window[], long double beta, int window_stride, int window_size)
void gen_kaiser_fx32 (long _Fract kaiser_window[], long double beta, int window_stride, int window_size)
void gen_rectangular_fr16 (fract16 rectangular_window[], int window_stride, int window_size)
Прямоугольное окно.
void gen_rectangular_fx16 (_Fract rectangular_window[], int window_stride, int window_size)
void gen_rectangular_fr32 (fract32 rectangular_window[], int window_stride, int window_size)
void gen_rectangular_fx32 (long _Fract rectangular_window[], int window_stride, int window_size)
void gen_triangle_fr16 (fract16 triangle_window[], int window_stride, int window_size)
Треугольное окно.
void gen_triangle_fx16 (_Fract triangle_window[], int window_stride, int window_size)
void gen_triangle_fr32 (fract32 triangle_window[], int window_stride, int window_size)
void gen_triangle_fx32 (long _Fract triangle_window[], int window_stride, int window_size)
void gen_vonhann_fr16 (fract16 vonhann_window[], int window_stride, int window_size)
Окно фон Ханна (Хэннинга).
void gen_vonhann_fx16 (_Fract vonhann_window[], int window_stride, int window_size)
void gen_vonhann_fr32 (fract32 vonhann_window[], int window_stride, int window_size)
void gen_vonhann_fx32 (long _Fract vonhann_window[], int window_stride, int window_size)
В технологиях DSP оконная функция (это понятие также называют функция адаптации или функция обострения) это математическая функция, которая равна нулю вне определенного выбранного интервала входных значений. Например, функция равная константе внутри этого интервала и нулю где-либо в другом месте называется функцией прямоугольного окна, что описывает форму её графического представления. Когда другая функция или сигнал/последовательность данных умножается на оконную функцию, то в результате получается ноль вне диапазона оконной функции, и все, что попадает в интервал оконной функции, не будет равно ную. Поэтому получается, что мы смотрим на сигнал как бы через окно, отсюда и пошло название термина.
В обычных приложениях оконные функции чаще используют не отрицательные, плавные, колоколообразные кривые. Также могут использоваться прямоугольные, треугольные и другие функции (из Википедии [3]).
[Счетчик тактов процессора]
Общий базис для вычисления бенчмарков C-кода это измерение количество тактов процессора, которое прошло за время выполнения блока кода. Когда мы знаем это количество тактов, то вычисление реального затраченного времени будет получено умножением количества тактов процессора на длительность одного такта.
Внимание: макросы для подсчета тактов, описанные в этой секции, не являются потокобезопасными (not thread-safe). Если макросы подсчета тактов используются в многопоточной среде выполнения (multi-threaded environment), то они должны запускаться внутри критического региона кода.
Критический регион кода в общем случае это участок кода, в котором запрещены прерывания, т. е. для критического региона кода гарантируется непрерывное выполнение, без отвлечения процессора на другие задачи.
В приложениях, работающих в условиях многозадачных операционных систем (RTOS, VDK) для организации критических регионов кода используется специальное API. Например, в VDK-приложении для этой цели имеются функции PushCriticalRegion и PopCriticalRegion.
Обычные приложения для организации критических регионов могут использовать команды общего запрета и разрешения прерываний (например, для процессоров Blackfin и микроконтроллеров AVR это команды ассемблера cli, sti).
Базовый метод подсчета тактов процессора. Фундаментальный метод измерения скорости выполнения секции кода - записать текущее значение регистра счетчика тактов перед выполняемой секцией кода, и чтение того же регистра снова после того, как измеряемая секция кода выполнилась. Этот процесс реализуется с помощью двух макросов, определенных в заголовочном файле cycle_count.h:
START_CYCLE_COUNT(S) STOP_CYCLE_COUNT(T,S)
Параметр S устанавливается макросом START_CYCLE_COUNT в текущее значение регистра счетчика тактов; это значение потом передается макросу STOP_CYCLE_COUNT, который вычислит разницу между этим параметром и текущим значением регистра счетчика тактов. Чтение регистра счетчика тактов влечет некоторое малое количество затраченных тактов, и макрос гарантирует, что возвращенная разница (параметр T) будет подстроена с учетом этой дополнительной траты процессорного времени. Параметры S и T должны быть разными переменными; они должны быть декларированы с использованием типа данных cycle_t, который в заголовочном файле cycle_count.h определен следующим образом:
typedefvolatileunsignedlonglongcycle_t;
Примечание: использование квалификатора типа volatile в определении типа данных cycle_t означает, что этот тип не может использоваться в качестве типа для возврата результата из функции.
Заголовочный файл cycle_count.h также определяет макрос PRINT_CYCLES(STRING,T), который дает общий пример, как использовать значение типа cycle_t; макрос выводит текст STRING в stdout, после чего выводится количество циклов T.
Описанный здесь инструментарий работает только когда программа скомпилирована с опцией командной строки компилятора –DDO_CYCLE_COUNTS. Если эта опция не указана, то макросы будут заменены пустыми операторами, и не окажут никакого эффекта на поведение программы.
Пример ниже демонстрирует, как использовать базовый функционал определения скорости выполнения секции кода.
Библиотеки реального времени предоставляют альтернативные возможности для измерения скорости выполнения кода C (см. раздел "Подсчет тактов с накоплением статистики" и "Использование time.h для измерения количества тактов").
Базовый функционал подсчета тактов основан на макросах, так что он может быть (при необходимости) изменен вручную для какого-то частного приложения, без необходимости повторной сборки библиотек run-time.
Подсчет тактов с накоплением статистики. В заголовочном файле cycles.h определен набор макросов для измерения скорости скомпилированного исходного кода C. В дополнение к предоставленным базовым макросам для чтения регистра счетчика циклов процессоров Blackfin, макросы заголовка cycles.h могут также накапливать статистику, подходящую для записи производительности секции кода, который запускается снова и снова.
Если опция -DDO_CYCLE_COUNTS указана во время компиляции, то заголовочный файл cycles.h определяет следующие макросы:
CYCLES_INIT(S). Этот макрос инициализирует системный механизм измерения времени и очищает параметр S; приложение должно содержать одну ссылку на этот макрос. CYCLES_START(S). Этот макрос выбирает текущее значение регистра счетчика тактов, и сохраняет его в параметре S. CYCLES_STOP(S). Этот макрос выбирает текущее значение регистра счетчика тактов, и накапливает статистику в параметре S, основываясь на предыдущей ссылке на макрос CYCLES_START. CYCLES_PRINT(S). Этот макрос печатает суммарную накопленную статистику, записанную в параметре S. CYCLES_RESET(S). Этот макрос обнуляет накопленную статистику в параметре S.
Параметр S, который передается в макросы, должен быть декларирован как переменная типа cycle_stats_t. Это специальный структурированный тип данных, который определен в заголовочном файле cycles.h. Этот тип данных может записать количество раз, с которым был выполнен измеряемый блок кода, а также максимальное, минимальное и среднее количество тактов, которое было затрачено на выполнение измеряемого блока кода. Например, если измеряемый кусок кода был выполнен 4 раза, то макрос CYCLES_PRINT сгенерирует вывод в стандартный поток stdout следующего вида:
AVG :95
MIN :92
MAX :100
CALLS :4
Если измеряемый блок кода был выполнен только 1 раз, то будет напечатано сообщение в следующей форме:
CYCLES :95
Если при компиляции не была указана опция -DDO_CYCLE_COUNTS, то вышеописанные макросы будут определены как пустые, и не будет захыватываться информация о времени выполнения. Наличие или отсутствие этой опции позволит переключаться между режимами разработки и релиза проекта, потребуется только перекомпиляция, и какое-либо изменение исходного кода приложения не требуется.
Макросы, определенные в заголовочном файле cycles.h, могут быть изменены для какого-то частного приложения, без необходимости повторной сборки библиотек run-time.
Ниже приведен пример, показывающий функционал макросов заголовка cycles.h.
#include < cycles.h >
#include < stdio.h >
externvoidfoo(void);
externvoidbar(void);
intmain(void)
{
cycle_stats_t stats;
int i;
CYCLES_INIT(stats);
for (i =0; i < LIMIT; i++)
{
CYCLES_START(stats);
foo();
CYCLES_STOP(stats);
}
printf("Такты, потраченные на foo\n");
CYCLES_PRINT(stats);
CYCLES_RESET(stats);
for (i =0; i < LIMIT; i++)
{
CYCLES_START(stats);
bar();
CYCLES_STOP(stats);
}
printf("Такты, потраченные на bar\n");
CYCLES_PRINT(stats);
}
Этот пример выведет что-то наподобие следующего:
Такты, потраченные на foo
AVG : 25454
MIN : 23003
MAX : 26295
CALLS : 16
Такты, потраченные на bar
AVG : 8727
MIN : 7653
MAX : 8912
CALLS : 16
Альтернативные методы измерения скорости выполнения кода C описаны в секциях "Базовый метод подсчета тактов процессора" и "Использование time.h для измерения количества тактов". Также см. "Замечания по использованию измерения количества тактов процессора", где даются полезные советы, связанные с измерениями скорости выполнения кода.
Использование time.h для измерения количества тактов. Заголовочный файл time.h определяет тип данных clock_t, функцию clock и макрос CLOCKS_PER_SEC, которые совместно друг с другом используются для вычисления количества секунд, потраченного в программе.
В стандарте ANSI C функция clock определена как количество зависящих от конкретной реализации элементарных тактовых "тиков", которые прошли с момента запуска программы. В текущей версии компилятора C/C++ функция clock вернет количество циклов процессора, которое было использовано приложением.
Обычный метод использования хедера time.h состоит в следующем: вызвать функцию clock в начале программы, и затем вычитать это значение из значения, которое будет возвращено последующими вызовами этой функции. Вычисленная разница обычно приводится к типу с плавающей точкой, и затем делится на макрос CLOCKS_PER_SEC, чтобы определить количество времени в секундах, которое прошло между двумя вызовами функции clock.
Если этот метод оценки реального времени используется в приложении, то обратите внимание на следующее:
• Значение, присвоенное макросу CLOCKS_PER_SEC должно быть проверено независимо, чтобы гарантировать корректное значение, используемое для каждого конкретного процессора (см. секцию "Determining the Processor Clock Rate"). • Возвращенный из функции clock результат не учитывает накладные расходы на вызов библиотечной функции.
Ниже показан типичный пример, демонстрирующий использование хедера time.h для измерения количества времени, которое приложение тратит на выполнение.
Заголовочные файлы cycles.h и cycle_count.h определяют другие методы для оценки скорости работы приложения, как это описано в секциях "Базовый метод подсчета тактов процессора" и "Подсчет тактов с накоплением статистики" соответственно. Также см. секцию "Замечания по использованию измерения количества тактов процессора", где предоставлены полезные советы.
Determining the Processor Clock Rate. Скорость выполнения приложения может оцениваться с учетом затрат тактов процессора. Однако приложения обычно оцениваются по отношению к реальному затраченному времени (например в секундах).
Определение количества времени, которое приложение потратило на выполнение кода процессором Blackfin, обычно сначала заключается в определении количества потраченных тактов, после этого полученное число делится на частоту тактов процессора (либо умножается на длительность такта процессора). Заголовочный файл time.h определяет макрос CLOCKS_PER_SEC как количество "тиков" процессора в секунду.
На процессорах Blackfin это устанавливается библиотекой run-time в одно из следующих значений в нисходящем порядке приоритета:
• С помощью указания опции -DCLOCKS_PER_SEC=< определение_количества_тактов > командной строки во время компиляции проекта приложения. Из-за того, что тип time_t основывается на целом типе данных long long, рекомендуется назначить символическому имени CLOCKS_PER_SEC значение таким образом, чтобы получился тот же самый тип данных, т. е. с использованием суффикса LL (или ll). Например, -DCLOCKS_PER_SEC=60000000LL. • С помощью Библиотеки Системных Служб (System Services Library, SSL). • С помощью настройки скорости процессора в диалоге опций проекта VisualDSP++, закладка Compile, категория настроек Processor (1). • С помощью заголовочного файла cycles.h.
Если значение макроса CLOCKS_PER_SEC было получено из заголовка cycles.h, имейте в виду, что тактовая частота процессора обычно будет взята как максимально возможная частота процессора, что вовсе не обязательно будет соответствовать скорости работы процессора после его сброса (RESET).
[Замечания по использованию измерения количества тактов процессора]
В этой секции обобщены техники подсчета тактов с целью бенчмаркинга скомпилированного C-кода. Ниже описана каждая из этих альтернатив.
Базовый метод подсчета тактов процессора. Эта возможность подсчета циклов самая недорогая по ресурсам и довольно мало влияет на тестируемый код. Эта технология базируется на макросах, которые могут быть изменены. Эти макросы также могут быть подключены или отключены без какой-либо правки исходного кода, что позволяет легко переключаться между отладочной версией и версией релиза. Одинаковый набор таких макросов доступен на других платформах, предоставляемых компанией Analog Devices.
Подсчет тактов с накоплением статистики. Этот вариант подсчета циклов предоставляет больше возможностей по сравнению с базовой версией, описанной выше. Он более затратен в смысле затрат памяти программ, памяти данных и процессорных тактов. Однако плюсы тоже имеются - можно записывать количество запусков проверяемого кода, и можно вычислить максимум, минимум и среднее значение стоимости итерации выполнения тестируемого кода. Предоставленные макросы учитывают свою вводимую нагрузку чтением регистра счетчиков тактов. По умолчанию эти макросы выключены, но они могут быть включены указанием опции командной строки компилятора -DDO_CYCLE_COUNTS. Эти макросы могут быть также изменены для каких-то конкретных приложений. Этот набор макросов доступен на других платформах, предоставляемых компанией Analog Devices.
Использование time.h для измерения количества тактов. Функционал заголовочного файла time.h представляет простые методы для измерения скорости выполнения приложения, которые являются портируемыми на различные архитектуры и системы. Этот функционал основан на функции clock.
Однако функция clock не учитывает стоимость своего выполнения в том месте, где она вызывается приложением. Дополнительно ссылки на эту функцию могут быть подвергнуты влиянию настроек оптимизации при генерации кода. Это приведет к тому, что точность анализа скорости выполнения кода снизится.
Метод измерения производительности с использованием заголовочного файла time.h лучше всего подходит для анализа всего приложения в целом, а не малых секций кода, которые выполняются за короткий промежуток времени.
При анализе производительности кода требуется учесть некоторые обстоятельства, связанные с добавлением инструментального измеряющего кода в оптимизируемый код C. Если последовательность измеряющих операторов не была тщательно выбрана, то оптимизатор может переместить измеряемый региона код, и/или может даже переместить сам измеряющий инструментальный код, что может привести к порче измерений. Таким образом, считается более надежным измерять счетчик цикла при вызове функции (и возврате из неё), вместо оценки времени выполнения последовательности операторов внутри функции.
Рекомендуется, чтобы используемые напрямую переменные в бенчмарке были простыми скалярными, и находились бы во внутренней памяти (это те переменные, которым присваивается результат ссылки на функцию clock, или переменные, которые используются как аргументы для считающих циклы макросов). В том случае, когда переменным назначается результат вызова функции clock, также рекомендуется задавать эти переменные с ключевым словом volatile [8]. Регистры счетчиков циклов архитектуры Blackfin называются CYCLES и CYCLES2, они являются 32-битными. Регистр CYCLES инкрементируется на каждом такте процессора; когда CYCLES переваливает через максимальное значение в 0, инкрементируется регистр CYCLES2. Работая совместно, эти два регистра представляют 64-битный счетчик, который вряд ли когда-нибудь переполнится во время анализа скорости выполнения приложения.
Внимание: макросы, описанные в этой секции, не являются потокобезопасными, потому что может произойти смена контекста между чтениями регистра CYCLES и регистра CYCLES2. Поэтому если макросы подсчета тактов используются в многопоточном окружении, они должны вызываться из критической секции кода.