Pull to refresh

Технология MIPS SIMD и процессор Байкал-Т1

Reading time 42 min
Views 17K

Коллеги из Байкал Электроникс предложили поработать с процессором Байкал-Т1 [L1] и написать о своих впечатлениях. Для них это способ рассказать разработчикам о возможностях и особенностях своего процессора. Для меня — шанс поближе познакомиться с системой на современном процессорном ядре и в будущем изобретать поменьше "велосипедов", добавляя, к примеру, новую функциональность в проект MIPSfpga-plus [L2]. Ну и обычное инженерное любопытство, опять же...


Сегодня речь пойдет о векторном расширении архитектуры MIPS SIMD, которое доступно в ядрах MIPS Warrior P-class P5600 [L3], а значит присутствует и в процессоре Байкал-Т1. Статья ориентирована на начинающих разработчиков.



Введение


Практически всегда с разработкой того или иного устройства (прибора/аппаратуры/программно-аппаратного комплекса и т.д.) связано решение задачи по обработке цифровых и аналоговых сигналов. На входе могут быть показания датчиков, сигналы с устройств ввода-вывода, информация из файла на диске и т.д. На выходе: изображение на мониторе, звук из колонок, сигналы управления приводами, показания индикаторов на приборной панели и пр. А "между" вводом и выводом — набор тех или иных математических операций.


Если кратко перечислить способы реализовать эту "математику в железе", то получим следующий список доступных разработчику инструментов, которые могут быть применены как вместе, так и по отдельности:


  • реализация в виде аналоговой схемы.
  • программная реализация на микроконтроллере.
  • реализация на ПЛИС
  • программно-аппаратная реализация в виде системы на кристалле
  • использование цифрового сигнального процессора
  • программная реализация на процессоре общего назначения
  • использование графического контроллера

Этот же список, но более подробно
  • реализация в виде аналоговой схемы
    Несмотря на засилье цифровых устройств, мир и органы чувств человека все равно остаются аналоговым. Хотим мы этого или нет, но даже обрабатывая информацию "исключительно" в цифре, перед входом АЦП нам все равно приходится ставить фильтр. Точно также на аналоговых компонентах могут быть реализованы интеграторы, дифференциаторы, сумматоры и т.д. За десятилетия господства аналоговой электроники инженеры накопили огромный опыт решения тех или иных задач и хороший разработчик (пусть даже цифровой электроники) учитывает это наследие [D1];


  • программная реализация на микроконтроллере
    Обрабатываемых сигналов немного, а математика — не сложная или не требовательная к ресурсам? В этом случае относительно недорогой микроконтроллер с его АЦП, невысокой частотой работы, возможностями энергосбережения — вполне себе вариант. При необходимости "узкие" места можно написать на ассемблере;


  • реализация на ПЛИС
    Если у нас высокие требования к скорости, параллелизму, масштабированию решения, то описываем математику в виде модуля на Verilog или VHDL, выбираем ПЛИС, которая может работать на необходимой для обработки частоте. Если решение окажется очень удачным и появится смысл в его широком тиражировании — добро пожаловать в мир ASIC [L3];


  • программно-аппаратная реализация в виде системы на кристалле
    Система слишком сложная, чтобы описывать ее целиком на Verilog, отдельную логику хочется запрограммировать на высокоуровневом языке, да и вообще — управлять всем из Linux? В этом случае вариантом решения для нас является СнК (System-on-a-Chip, SoC): берем готовое процессорное ядро (Nios II, MIPSfpga и т.д.) и обвешиваем его необходимыми нам периферийными модулями, среди которых будет наш особенный, выполняющий хитрую математику. Некоторые операции можно сделать доступными в виде процессорных команд [L4]. И да, в перспективе это тоже можно реализовать в ASIC;


  • использование цифрового сигнального процессора (ЦСП)
    Здесь мы, фактически, покупаем готовую микросхему с процессорным ядром, своим набором периферии и набором команд, специально ориентированным на высокоскоростную цифровую обработку сигналов. Вокруг нее мы и выстраиваем свое решение [L10, L5];


  • программная реализация на процессоре общего назначения
    Каждый из производителей процессоров предлагает свои архитектурные решения, позволяющие оптимизировать выполнение тех или иных математических операций. И задача разработчика ПО при необходимости использовать предлагаемые производителем возможности для ускорения вычислений. Как раз об этом применительно к процессорам MIPS и пойдет речь ниже;


  • использование графического контроллера для вычислений
    Для того, чтобы настоящий список был более полным, нельзя не упомянуть о возможности вынести наиболее сложные и ресурсоемкие вычисления на видеокарту [L6, L7].

Идеальных инструментов не бывает. Самый лучший инструмент — это тот, который гарантирует решение задачи в приемлемые сроки, для которого в проектной команде есть необходимые компетенции, и который либо есть в наличии, либо может быть приобретен с минимальными затратами. На принятие подобных решений накладываются ограничения бюджета, требования заказчика, а иногда и политические причины.


Надеюсь, что данная статья будет полезна в качестве вводной для тех читателей, кто столкнется с необходимостью оптимизировать выполнение тех или иных вычислений на процессоре Байкал-Т1 или ином другом, построенном на базе ядра (ядер) MIPS, где доступна технология MIPS SIMD.


Ресурсоемкость вычислений


Перед тем, как двигаться дальше, рассмотрим одну из часто встречающихся задач цифровой обработки сигналов (ЦОС) — фильтрацию. В качестве примера возьмем фильтр с конечной импульсной характеристикой (КИХ, FIR, finite impulse response) [L8]. Не углубляясь в теорию ЦОС и математические выкладки отметим основное — уравнение, которое описывает данный вид цифровых фильтров:



где x(n) — входной сигнал, y(n) — выходной сигнал, P — порядок фильтра, bi — коэффициенты фильтра. Это же уравнение можно записать следующим образом:



Природу входного сигнала x(n) в данном случае — проигнорируем. Пусть это будут данные, полученные с АЦП, но с тем же успехом они могут быть считаны из файла. Для нас в рассматриваемом случае это не имеет никакого значения. Так как наша текущая статья "про вычисления", а не "про ЦОС", то, соответственно, не будем погружаться и в Магию фильтров, а просто воспользуемся одним из онлайн сервисов для расчета коэффициентов [L9]:


Устанавливаем желаемые параметры фильтрации (например, один из predefined вариантов: band stop — режекторный фильтр [L11]) и нажимаем кнопку Design Filter:



Результатом расчета является АЧХ фильтра [L12]:


АЧХ фильтра


Набор коэффициентов и исходный код:


SampleFilter.h
#ifndef SAMPLEFILTER_H_
#define SAMPLEFILTER_H_

/*
FIR filter designed with
 http://t-filter.appspot.com

sampling frequency: 2000 Hz

* 0 Hz - 200 Hz
  gain = 1
  desired ripple = 5 dB
  actual ripple = 3.1077303934211127 dB

* 300 Hz - 500 Hz
  gain = 0
  desired attenuation = -40 dB
  actual attenuation = -42.49314043914754 dB

* 600 Hz - 1000 Hz
  gain = 1
  desired ripple = 5 dB
  actual ripple = 3.1077303934211127 dB
*/

#define SAMPLEFILTER_TAP_NUM 25

typedef struct {
  double history[SAMPLEFILTER_TAP_NUM];
  unsigned int last_index;
} SampleFilter;

void SampleFilter_init(SampleFilter* f);
void SampleFilter_put(SampleFilter* f, double input);
double SampleFilter_get(SampleFilter* f);

#endif

SampleFilter.с
#include "SampleFilter.h"

static double filter_taps[SAMPLEFILTER_TAP_NUM] = {
  0.037391727827352596,    -0.03299884552335979,
  0.044230583967321345,    0.0023050970833628304,
  -0.06768087195950104,    -0.046347105409124706,
  -0.011717387509232432,   -0.0707342284185183,
  -0.049766517282999544,   0.16086413543836361,
  0.21561058688743148,     -0.10159456907827959,
  0.6638637561392535,      -0.10159456907827959,
  0.21561058688743148,     0.16086413543836361,
  -0.049766517282999544,   -0.0707342284185183,
  -0.011717387509232432,   -0.046347105409124706,
  -0.06768087195950104,    0.0023050970833628304,
  0.044230583967321345,    -0.03299884552335979,
  0.037391727827352596
};

void SampleFilter_init(SampleFilter* f) {
  int i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i)
    f->history[i] = 0;
  f->last_index = 0;
}

void SampleFilter_put(SampleFilter* f, double input) {
  f->history[f->last_index++] = input;
  if(f->last_index == SAMPLEFILTER_TAP_NUM)
    f->last_index = 0;
}

double SampleFilter_get(SampleFilter* f) {
  double acc = 0;
  int index = f->last_index, i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i) {
    index = index != 0 ? index-1 : SAMPLEFILTER_TAP_NUM-1;
    acc += f->history[index] * filter_taps[i];
  };
  return acc;
}

Посмотрим на параметры фильтрации, функцию SampleFilter_get, вспомним приведенное выше уравнение КИХ-фильтра и отметим наиболее важные для нас моменты:


  • для того, чтобы получить один отсчет y(n), что в нашем случае равносильно одному вызову функции SampleFilter_get нам необходимо в цикле обработать 25 входных отсчетов x(n) (порядок фильтра, см. макрос SAMPLEFILTER_TAP_NUM и "taps" на скриншоте интерфейса);
  • если мы хотим, чтобы эта обработка выполнялась налету (к примеру, по мере поступления x(n) с АЦП), то мы должны успевать выполнять ее с учетом sampling frequency, которая в нашем случае 2000Hz;
  • для каждого из этих 25 отсчетов x(n) мы выполняем ряд математических операций: умножение на соответствующий ему коэффициент, сложение в регистр-аккумулятор. Кроме того, не забываем о сопутствующих операциях по чтению/записи из/в память, на которые также требуется время.

Теперь предположим, что условия задачи в силу неких объективных причин были уточнены:



И в результате мы получаем вот такую АЧХ:


АЧХ фильтра


Что для нас важно:


  • в связи с увеличением sampling frequency до 4000Hz в 2 раза сократилось время, которое мы можем потратить на вычисления, если хотим получать результаты налету;
  • количество итераций (taps, порядок фильтра) при этом увеличилось почти в 3 раза (с 25 до 67). Если не вносить изменения в параметр неравномерности АЧХ (оставить ripple/att. = 5 dB), то количество итераций все равно увеличится в 2 раза;
  • таким образом, незначительное изменение параметров фильтрации привело к увеличению ресурсоемкости вычислений в 6 раз (либо в 4).

Мне бы не хотелось, чтобы читатель обращал внимание на приведенные в примере абсолютные значения параметров фильтра. Основная мысль, которую хотелось бы донести, заключается в том, что в какой-то момент увеличение ресурсоемкости вычислений может выйти за ранее спрогнозированные пределы. И после небольшого изменения алгоритма, его параметров, или входных данных, вдруг, может оказаться что ваше процессорное ядро занимается только тем, что "лопатит" данные, да и то не успевает это делать, не говоря уже про выполнение остальных задач. Либо оно успешно справляется, но создаваемая при этом нагрузка или длительность вычислений уже не соответствуют требованиям к системе. И в этот момент перед вами как никогда встает задача оптимизации.


Скорость вычислений


После того, как мы на простом примере увидели проблему, посмотрим на ее решение. Производители процессоров идут на ряд ухищрений для того, чтобы повысить скорость вычислений: повышают частоту, увеличивают число процессорных ядер, добавляют новые команды, экспериментируют с конфигурацией конвейера, объемом кэша, переходят к использованию все более и более высокоскоростных шин и интерфейсов.


Также никто не забирает у разработчика право реализовать наиболее узкие места на ассемблере, поэкспериментировать с опциями компилятора, сменить алгоритм на менее ресурсоемкий либо ведущий себя более предсказуемо на том же диапазоне параметров.


Cконцентрируемся на двух способах повысить скорость обработки, которые не могут быть использованы без поддержки со стороны архитектуры процессора:


  • объединение нескольких арифметических операций в одну команду;
  • реализация SIMD-подхода.

Объединение арифметических операций


Вернемся к нашему фильтру и внимательно посмотрим на код функции SampleFilter_get:


double SampleFilter_get(SampleFilter* f) {
  double acc = 0;
  int index = f->last_index, i;
  for(i = 0; i < SAMPLEFILTER_TAP_NUM; ++i) {
    index = index != 0 ? index-1 : SAMPLEFILTER_TAP_NUM-1;
    acc += f->history[index] * filter_taps[i];
  };
  return acc;
}

И особенно на строку:


acc += f->history[index] * filter_taps[i];

Здесь мы видим 2 последовательно выполняемые операции: умножение на коэффициент и накопление результатов этой команды в переменной-аккумуляторе. Подобное сочетание умножения и сложения очень часто встречается в алгоритмах ЦОС. Но если эти две операции так часто соседствуют друг с другом, то почему бы их не объединить в одну команду, выполняемую в течении 1 такта? Идея такого объединения пришла в головы инженеров очень давно. Так появилась команда "умножение с накоплением" (совмещённое умножение-сложение, multiply–accumulate operation, MAC), которая ныне присутствует во всех цифровых сигнальных процессорах:



SIMD-подход


Подойдем к решению с другой стороны. А почему бы нам, вместо того, чтобы работать с каждым отсчетом x(n) по отдельности, не объединить несколько отсчетов в один вектор (массив) и применить команду сразу ко всему вектору, а если точнее — то одновременно к каждому элементу вектора? В этом случае за один такт (не считая работу с памятью) можно будет обработать сразу несколько отсчетов:



И чем больше будет максимально допустимый размер вектора, тем выше будет скорость обработки данных. Данный принцип организации вычислений называется SIMD (single instruction, multiple data; одиночный поток команд, множественный поток данных) [L13]. На этом подходе строится работа векторных процессоров [L14] и векторных расширений к скалярным процессорам: SSE и AVX для архитектуры x86, MIPS SIMD [L15] для архитектуры MIPS.


MIPS SIMD


Теперь, когда мы понимаем основные принципы, на которых строятся векторные расширения архитектуры, можно перейти непосредственно к MIPS SIMD. Исчерпывающее описание этого расширения приведено в документации [D2], отметим основные моменты:


  • доступно в двух вариантах: MIPS32 SIMD и MIPS64 SIMD. Так как Байкал-Т1 основан на ядрах архитектуры MIPS 32 r5, то в дальнейшем, упоминая MIPS SIMD, будем иметь в ввиду MIPS32 SIMD. На сайте и в документации Imagination Technologies оно также упоминается как MSA (MIPS SIMD Architecture);
  • работа осуществляется с использованием 32x 128-битных регистров для обработки векторных данных. Каждый из которых может быть представлен как: 16x 8-битных векторов, 8x 16-битных, 4x 32-битных, либо 2x 64-битных:


  • предполагает более 150 инструкций по обработке данных: целочисленных, с плавающей и фиксированной точкой, включая битовые операции, операции сравнения, конвертации:

Целочисленные операции
Mnemonic Instruction Description
ADDV, ADDVI Add
ADD_A, ADDS_A Add and Saturated Add Absolute Values
ADDS_S, ADDS_U Signed and Unsigned Saturated Add
HADD_S, HADD_U Signed and Unsigned Horizontal Add
ASUB_S, ASUB_U Absolute Value of Signed and Unsigned Subtract
AVE_S, AVE_U Signed and Unsigned Average
AVER_S, AVER_U Signed and Unsigned Average with Rounding
DOTP_S, DOTP_U Signed and Unsigned Dot Product
DPADD_S, DPADD_U Signed and Unsigned Dot Product Add
DPSUB_S, DPSUB_U Signed and Unsigned Dot Product Subtract
DIV_S, DIV_U Divide
MADDV Multiply-Add
MAX_A, MIN_A Maximum and Minimum of Absolute Values
MAX_S, MAXI_S, MAX_U, MAXI_U Signed and Unsigned Maximum
MIN_S, MINI_S, MIN_U, MINI_U Signed and Unsigned Maximum
MSUBV Multiply-Subtract
MULV Multiply
MOD_S, MOD_U Signed and Unsigned Remainder (Modulo)
SAT_S, SAT_U Signed and Unsigned Saturate
SUBS_S, SUBS_U Signed and Unsigned Saturated Subtract
HSUB_S, HSUB_U Signed and Unsigned Horizontal Subtract
SUBSUU_S Signed Saturated Unsigned Subtract
SUBSUS_U Unsigned Saturated Signed Subtract from Unsigned
SUBV, SUBVI Subtract

Битовые операции
Mnemonic Instruction Description
AND, ANDI Logical And
BCLR, BCLRI Bit Clear
BINSL, BINSLI, BINSR, BINSRI Bit Insert Left and Right
BMNZ, BMNZI Bit Move If Not Zero
BMZ, BMZI Bit Move If Zero
BNEG, BNEGI Bit Negate
BSEL, BSELI Bit Select
BSET, BSETI Bit Set
NLOC Leading One Bits Count
NLZC Leading Zero Bits Count
NOR, NORI Logical Negated Or
PCNT Population (Bits Set to 1) Count
OR, ORI Logical Or
SLL, SLLI Shift Left
SRA, SRAI Shift Right Arithmetic
SRAR, SRARI Rounding Shift Right Arithmetic
SRL, SRLI Shift Right Logical
SRLR, SRLRI Rounding Shift Right Logical
XOR, XORI Logical Exclusive Or

Арифметические операции с плавающей точкой
Mnemonic Instruction Description
FADD Floating-Point Addition
FDIV Floating-Point Division
FEXP2 Floating-Point Base 2 Exponentiation
FLOG2 Floating-Point Base 2 Logarithm
FMADD, FMSUB Floating-Point Fused Multiply-Add and Multiply-Subtract
FMAX, FMIN Floating-Point Maximum and Minimum
FMAX_A, FMIN_A Floating-Point Maximum and Minimum of Absolute Values
FMUL Floating-Point Multiplication
FRCP Approximate Floating-Point Reciprocal
FRINT Floating-Point Round to Integer
FRSQRT Approximate Floating-Point Reciprocal of Square Root
FSQRT Floating-Point Square Root
FSUB Floating-Point Subtraction

Не арифметические операции с плавающей точкой
Mnemonic Instruction Description
FCLASS Floating-Point Class Mask

Операции сравнения с плавающей точкой
Mnemonic Instruction Description
FCAF Floating-Point Quiet Compare Always False
FCUN Floating-Point Quiet Compare Unordered
FCOR Floating-Point Quiet Compare Ordered
FCEQ Floating-Point Quiet Compare Equal
FCUNE Floating-Point Quiet Compare Unordered or Not Equal
FCUEQ Floating-Point Quiet Compare Unordered or Equal
FCNE Floating-Point Quiet Compare Not Equal
FCLT Floating-Point Quiet Compare Less Than
FCULT Floating-Point Quiet Compare Unordered or Less Than
FCLE Floating-Point Quiet Compare Less Than or Equal
FCULE Floating-Point Quiet Compare Unordered or Less Than or Equal
FSAF Floating-Point Signaling Compare Always False
FSUN Floating-Point Signaling Compare Unordered
FSOR Floating-Point Signaling Compare Ordered
FSEQ Floating-Point Signaling Compare Equal
FSUNE Floating-Point Signaling Compare Unordered or Not Equal
FSUEQ Floating-Point Signaling Compare Unordered or Equal
FSNE Floating-Point Signaling Compare Not Equal
FSLT Floating-Point Signaling Compare Less Than
FSULT Floating-Point Signaling Compare Unordered or Less Than
FSLE Floating-Point Signaling Compare Less Than or Equal
FSULE Floating-Point Signaling Compare Unordered or Less Than or Equal

Операции преобразования с плавающей точкой
Mnemonic Instruction Description
FEXDO Floating-Point Down-Convert Interchange Format
FEXUPL, FEXUPR Left-Half and Right-Half Floating-Point Up-Convert Interchange Format
FFINT_S, FFINT_U Floating-Point Convert from Signed and Unsigned Integer
FFQL, FFQR Left-Half and Right-Half Floating-Point Convert from Fixed-Point
FTINT_S, FTINT_U Floating-Point Round and Convert to Signed and Unsigned Integer
FTRUNC_S, FTRUNC_U Floating-Point Truncate and Convert to Signed and Unsigned Integer
FTQ Floating-Point Round and Convert to Fixed-Point

Операции с фиксированной точкой
Mnemonic Instruction Description
MADD_Q, MADDR_Q Fixed-Point Multiply and Add without and with Rounding
MSUB_Q, MSUBR_Q Fixed-Point Multiply and Subtract without and with Rounding
MUL_Q, MULR_Q Fixed-Point Multiply without and with Rounding

Операции ветвления
Mnemonic Instruction Description
BNZ Branch If Not Zero
BZ Branch If Zero
CEQ, CEQI Compare Equal
CLE_S, CLEI_S, CLE_U, CLEI_U Compare Less-Than-or-Equal Signed and Unsigned
CLT_S, CLTI_S, CLT_U, CLTI_U Compare Less-Than Signed and Unsigned

Операции загрузки и выгрузки векторов
Mnemonic Instruction Description
CFCMSA, CTCMSA Copy from and copy to MSA Control Register
LD Load Vector
LDI Load Immediate
MOVE Vector to Vector Move
SPLAT, SPLATI Replicate Vector Element
FILL Fill Vector from GPR
INSERT, INSVE Insert GPR and Vector element 0 to Vector Element
COPY_S, COPY_U Copy element to GPR Signed and Unsigned
ST Store Vector

Операции перестановки элементов вектора
Mnemonic Instruction Description
ILVEV, ILVOD Interleave Even, Odd
ILVL, ILVR Interleave the Left, Right
PCKEV, PCKOD Pack Even and Odd Elements
SHF Set Shuffle
SLD, SLDI Element Slide
VSHF Vector shuffle

Иные операции
Mnemonic Instruction Description
LSA Left-shift add or load/store address calculation

  • большинство команд доступно в нескольких вариантах, отличающихся друг от друга размером элемента вектора и типом обрабатываемых данных. Так уже знакомая нам операция умножения с накоплением реализована как: FMADD — для чисел с плавающей точкой, MADD_Q — для чисел с фиксированной точкой (с насыщением), MADDR_Q — для чисел с фиксированной точкой (с насыщением и округлением), MADDV — для целых чисел. При этом, к примеру, MADDV доступна в 4х вариантах: MADDV.B — когда элементами для побайтовой обработки (x8), MADDV.H — когда каждый элемент вектора является полусловом (x16), MADDV.W — словом (x32) и MADDV.D — двойным словом (x64)

Формальное описание команды


Поддержка на уровне компилятора


MIPS SIMD поддерживается компилятором gcc, вместе с тем у этой поддержки есть свои особенности:


  • для элементов вектора различной размерности введены отдельные типы данных [L16];
  • мы избавлены от необходимости непосредственной работы с регистрами (работа ведется на уровне переменных соответствующего типа);
  • для всех перечисленных выше операций введены высокоуровневые псевдонимы [L17];
  • согласно документации gcc, компилятор не принимает самостоятельных решений об использовании MIPS SIMD, это же подтверждается неплохо разобранным примером применения MIPS SIMD, опубликованном на сайте Imagination Technologies [D3]. Таким образом, если провести грубую аналогию, то работа с MIPS SIMD ближе к написанию ассемблерных вставок, нежели к высокоуровневому программированию. Что должно учитываться при принятии решения об оптимизации.

Код до оптимизации
#define ROUND_POWER_OF_TWO(value, n) (((value) + (1 << ((n) - 1))) >> (n))
static inline unsigned char clip_pixel(int i32Val)
{
    return ((i32Val) > 255) ? 255u : ((i32Val) < 0) ? 0u : (i32Val);
}
void vert_filter_8taps_16width_c(unsigned char *pSrc, // SOURCE POINTER
int SrcStride,       // SOURCE BUFFER PITCH
unsigned char *pDst, // DEST POINTER
int DstStride,       // DEST BUFFER PITCH
char *pFilter,       // POINTER TO FILTER BANK
int Height)          // HEIGHT OF THE BLOCK
{
    unsigned int Row, Col;
    int FiltSum;
    short Src0, Src1, Src2, Src3, Src4, Src5, Src6, Src7;
    pSrc -= (8 / 2 - 1) * SrcStride; // MOVE INPUT SRC POINTER TO APPROPRIATE POSITION

    // LOOP FOR NUMBER OF COLUMNS-16
    for (Col = 0; Col < 16; ++Col)
    {
        Src0 = pSrc[0 * SrcStride];
        Src1 = pSrc[1 * SrcStride];
        Src2 = pSrc[2 * SrcStride];
        Src3 = pSrc[3 * SrcStride];
        Src4 = pSrc[4 * SrcStride];
        Src5 = pSrc[5 * SrcStride];
        Src6 = pSrc[6 * SrcStride];

        // LOOP FOR NUMBER OF ROWS
        for (Row = 0; Row < Height; Row++)
        {
            Src7 = pSrc[(7 + Row) * SrcStride];
            FiltSum = 0;

            // ACCUMULATED FILTER SUM += PIXEL * FILTER COEFF
            FiltSum += (Src0 * pi8Filter[0]);
            FiltSum += (Src1 * pi8Filter[1]);
            FiltSum += (Src2 * pi8Filter[2]);
            FiltSum += (Src3 * pi8Filter[3]);
            FiltSum += (Src4 * pi8Filter[4]);
            FiltSum += (Src5 * pi8Filter[5]);
            FiltSum += (Src6 * pi8Filter[6]);
            FiltSum += (Src7 * pi8Filter[7]);
            FiltSum = ROUND_POWER_OF_TWO(FiltSum, 7); // ROUNDING
            pDst[Row * DstStride] = clip_pixel(FiltSum);// CLIP RESULT IN 0-255(UNSIGNED CHAR)

            // PREPARING FOR NEXT CONVOLUTION- SLIDING WINDOW
            Src0 = Src1;
            Src1 = Src2;
            Src2 = Src3;
            Src3 = Src4;
            Src4 = Src5;
            Src5 = Src6;
            Src6 = Src7;
        }
        pSrc += 1;
        pDst += 1;
    }
}

Код после оптимизации с использованием MIPS SIMD
/* MSA VECTOR TYPES */
#define WRLEN 128 // VECTOR REGISTER LENGTH 128-BIT
#define NUMWRELEM (WRLEN >> 3)
typedef signed char IMG_VINT8 __attribute__ ((vector_size(NUMWRELEM)));    //VEC SIGNED BYTES
typedef unsigned char IMG_VUINT8 __attribute__ ((vector_size(NUMWRELEM))); //VEC UNSIGNED BYTES
typedef short IMG_VINT16 __attribute__ ((vector_size(NUMWRELEM)));         //VEC SIGNED HALF-WORD
#define LOAD_UNPACK_VEC(pSrc, SrcStride, vi16VecRight, vi16VecLeft) \
{ \
    IMG_VUINT8 vu8Src; \
    IMG_VINT16 vi16Vec0; \
    IMG_VINT8 vi8Tmp0; \
    /* LOAD INPUT VECTOR */ \
    vu8Src = *((IMG_VINT8 *)(pSrc)); \
    /* RANGE WARPING TO MAINTAIN 16 BIT PRECISION */ \
    vi16Vec0 = __builtin_msa_xori_b(vu8Src, 128); \
    /* CALCULATE SIGN EXTENSION */ \
    vi8Tmp0 = __builtin_msa_clti_s_b(vi16Vec0, 0); \
    /* INTERLEAVE RIGHT TO 16 BIT VEC */ \
    vi16VecRight = __builtin_msa_ilvr_b(vi8Tmp0, vi16Vec0); \
    /* INTERLEAVE LEFT TO 16 BIT VEC */ \
    vi16VecLeft = __builtin_msa_ilvl_b(vi8Tmp0, vi16Vec0); \
    pSrc += SrcStride; \
}
void vert_filter_8taps_16width_msa(unsigned char *pSrc, // SOURCE POINTER
int SrcStride,         // SOURCE BUFFER PITCH
unsigned char *pDst,   // DEST POINTER
int DstStride,         // DEST BUFFER PITH
char *pFilter,         // POINTER TO FILTER BANK
int Height)            // HEIGHT OF THE BLOCK
{
    int u32LoopCnt;
    VINT16 vi16Vec0Right, vi16Vec1Right, vi16Vec2Right, vi16Vec3Right;
    VINT16 vi16Vec4Right, vi16Vec5Right, vi16Vec6Right, vi16Vec7Right;
    VINT16 vi16Vec0Left, vi16Vec1Left, vi16Vec2Left, vi16Vec3Left;
    VINT16 vi16Vec4Left, vi16Vec5Left, vi16Vec6Left, vi16Vec7Left;
    VINT16 vi16Temp1Right, vi16Temp1Left;
    VINT16 vi16Filt0, vi16Filt1, vi16Filt2, vi16Filt3;
    VINT16 vi16Filt4, vi16Filt5, vi16Filt6, vi16Filt7;
    pSrc -= (3 * SrcStride);

    // PREPARE FILTER COEFF IN VEC REGISTERS
    vi16Filt0 = __builtin_msa_fill_h(*(pFilter));
    vi16Filt1 = __builtin_msa_fill_h(*(pFilter + 1));
    vi16Filt2 = __builtin_msa_fill_h(*(pFilter + 2));
    vi16Filt3 = __builtin_msa_fill_h(*(pFilter + 3));
    vi16Filt4 = __builtin_msa_fill_h(*(pFilter + 4));
    vi16Filt5 = __builtin_msa_fill_h(*(pFilter + 5));
    vi16Filt6 = __builtin_msa_fill_h(*(pFilter + 6));
    vi16Filt7 = __builtin_msa_fill_h(*(pFilter + 7));

    //LOAD 7 INPUT VECTORS
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec0Right, vi16Vec0Left)
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec1Right, vi16Vec1Left)
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec2Right, vi16Vec2Left)
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec3Right, vi16Vec3Left)
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec4Right, vi16Vec4Left)
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec5Right, vi16Vec5Left)
    LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec6Right, vi16Vec6Left)

    // START CONVOLUTION VERTICALLY
    for (u32LoopCnt = Height; u32LoopCnt--; )
    {
        //LOAD 8TH INPUT VECTOR
        LOAD_UNPACK_VEC(pSrc, SrcStride, vi16Vec7Right, vi16Vec7Left)

        /* FILTER CALC */
        IMG_VINT16 vi16Tmp1, vi16Tmp2;
        IMG_VINT8 vi8Tmp3;

        // 8 TAP VECTORIZED CONVOLUTION FOR RIGHT HALF
        vi16Tmp1 = (vi16Vec0Right * vi16Filt0);
        vi16Tmp1 += (vi16Vec1Right * vi16Filt1);
        vi16Tmp1 += (vi16Vec2Right * vi16Filt2);
        vi16Tmp1 += (vi16Vec3Right * vi16Filt3);
        vi16Tmp2 = (vi16Vec4Right * vi16Filt4);
        vi16Tmp2 += (vi16Vec5Right * vi16Filt5);
        vi16Tmp2 += (vi16Vec6Right * vi16Filt6);
        vi16Tmp2 += (vi16Vec7Right * vi16Filt7);
        vi16Temp1Right = __builtin_msa_adds_s_h(vi16Tmp1, vi16Tmp2);

        // 8 TAP VECTORIZED CONVOLUTION FOR LEFT HALF
        vi16Tmp1 = (vi16Vec0Left * vi16Filt0);
        vi16Tmp1 += (vi16Vec1Left * vi16Filt1);
        vi16Tmp1 += (vi16Vec2Left * vi16Filt2);
        vi16Tmp1 += (vi16Vec3Left * vi16Filt3);
        vi16Tmp2 = (vi16Vec4Left * vi16Filt4);
        vi16Tmp2 += (vi16Vec5Left * vi16Filt5);
        vi16Tmp2 += (vi16Vec6Left * vi16Filt6);
        vi16Tmp2 += (vi16Vec7Left * vi16Filt7);
        vi16Temp1Left = __builtin_msa_adds_s_h(vi16Tmp1, vi16Tmp2);

        // ROUNDING RIGHT SHIFT RANGE CLIPPING AND NARROWING
        vi16Temp1Right = __builtin_msa_srari_h(vi16Temp1Right, 7);
        vi16Temp1Right = __builtin_msa_sat_s_h(vi16Temp1Right, 7);
        vi16Temp1Left = __builtin_msa_srari_h(vi16Temp1Left, 7);
        vi16Temp1Left = __builtin_msa_sat_s_h(vi16Temp1Left, 7);
        vi8Tmp3 = __builtin_msa_pckev_b(vi16Temp1Left, vi16Temp1Right);
        vi8Tmp3 = __builtin_msa_xori_b(vi8Tmp3, 128);

        // STORE OUTPUT VEC
        *((IMG_VINT8 *)(pDst)) = (vi8Tmp3);
        pDst += DstStride;

        // PREPARING FOR NEXT CONVOLUTION- SLIDING WINDOW
        vi16Vec0Right = vi16Vec1Right;
        vi16Vec1Right = vi16Vec2Right;
        vi16Vec2Right = vi16Vec3Right;
        vi16Vec3Right = vi16Vec4Right;
        vi16Vec4Right = vi16Vec5Right;
        vi16Vec5Right = vi16Vec6Right;
        vi16Vec6Right = vi16Vec7Right;
        vi16Vec0Left = vi16Vec1Left;
        vi16Vec1Left = vi16Vec2Left;
        vi16Vec2Left = vi16Vec3Left;
        vi16Vec3Left = vi16Vec4Left;
        vi16Vec4Left = vi16Vec5Left;
        vi16Vec5Left = vi16Vec6Left;
        vi16Vec6Left = vi16Vec7Left;
    }
}

Оценка производительности


Первоначально у меня были мысли написать простейшее приложение (синтетический тест) для оценки прироста производительности при использовании MIPS SIMD. Но несмотря на всю свою привлекательность, этот вариант не является показательным, ввиду его оторванности от реальных задач пользователя. На наше счастье работники Imagination Technologies и MIPS сделали весомый вклад в ffmpeg [L18] — широко используемое open source приложение, предназначенное для конвертации аудио и видео [L19]. Полагаю, что они как никто другой знают, как правильно использовать рассматриваемую технологию, а значит этот код должен быть максимально эффективен.


Таким образом, если мы скомпилируем ffmpeg в двух вариантах: с поддержкой MIPS SIMD и без нее, то можно будет сравнить скорость работы на одинаковых входных данных и по результатам сделать некий вывод об эффективности векторных вычислений.


Сборка ffmpeg


Выполняется на машине x86 под управлением ОС Linux. Используются средства разработки с сайта Imagination Technologies [L20] в режиме кросс-компиляции. Тесты выполняются на последнем стабильном релизе на момент написания статьи — ffmpeg 3.3 [L19].


Конфигурация ffmpeg для варианта с поддержкой MIPS SIMD:


./configure --enable-cross-compile --prefix=../ffmpeg-msa  --cross-prefix=/home/stas/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-03/bin/mips-mti-linux-gnu- --arch=mips --cpu=p5600 --target-os=linux --extra-cflags="-EL -static" --extra-ldflags="-EL -static" --disable-iconv

И с отключенной поддержкой MIPS SIMD:


./configure --enable-cross-compile --prefix=../ffmpeg-soft --cross-prefix=/home/stas/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-03/bin/mips-mti-linux-gnu- --arch=mips --cpu=p5600 --target-os=linux --extra-cflags="-EL -static" --extra-ldflags="-EL -static" --disable-iconv --disable-msa

Описание настроек конфигурации
Параметр Описание
--enable-cross-compile сборка будет осуществляться на машине с архитектурой, отличной отцелевой
--prefix=../ffmpeg-msa каталог, в который будут помещены файлы после команды make install
--cross-prefix=../mips-mti-linux-gnu- путь к toolchain
--arch=mips целевая архитектура — MIPS
--cpu=p5600 целевое процессорное ядро — p5600
--target-os=linux целевая ОС — Linux
--extra-cflags="-EL -static" целевая система — little endian, использовать статическоесвязывание
--extra-ldflags="-EL -static" аналогично
--disable-iconv отключить функциональность, связанную с кодировками текста
--disable-msa не использовать MIPS SIMD

Если вы планируете повторить эти действия, то учтите, что сборка ffmpeg 3.3 с поддержкой MIPS SIMD вываливается с мелкой ошибкой, для устранения которой необходимо в файл libavcodec\mips\hevcpred_msa.c добавить:


#include "libavcodec/hevcdec.h"

Тестирование


Выполняется на процессоре Байкал-Т1:


# uname -a
Linux baikal-BFK-18446744073709551615 4.4.41-bfk #0 SMP Tue Apr 25 15:54:24 MSK 2017 mips GNU/Linux

В качестве входных данных выступают два видеоролика закодированные с использованием x264 [L21] и x265 [L22]. Тестовой задачей является декодирование видео с получением скриншотов через равные промежутки времени:


./ffmpeg-mips/ffmpeg-msa/bin/ffmpeg -i ./The\ Simpsons\ Movie\ -\ Trailer_x264.mp4 -vf fps=1/10 ./out_img/ffmpeg-msa_x264_%d.jpg -report -benchmark

./ffmpeg-mips/ffmpeg-msa/bin/ffmpeg -i ./Tears_400_x265.mp4 -vf fps=1 ./out_img/ffmpeg-msa_x265_%d.jpg -report -benchmark

./ffmpeg-mips/ffmpeg-soft/bin/ffmpeg -i ./The\ Simpsons\ Movie\ -\ Trailer_x264.mp4 -vf fps=1/10 ./out_img/ffmpeg-soft_x264_%d.jpg -report -benchmark

./ffmpeg-mips/ffmpeg-soft/bin/ffmpeg -i ./Tears_400_x265.mp4 -vf fps=1 ./out_img/ffmpeg-soft_x265_%d.jpg -report -benchmark

Описание опций запуска
Параметр Описание
-i ./Tears_400_x265.mp4 файл, который подлежит обработке
-vf fps=1 период (частота) снятия скриншотов (1 сек — для короткого ролика, 10 сек — для длинного)
./out_img/ffmpeg-softx264%d.jpg шаблон имени выходного файла
-report сформировать отчет по результатам работы
-benchmark включить в отчет данные о производительности

Результаты работы ffmpeg


Сценарий Длительность (cек)
декодирование x264 с поддержкой MIPS SIMD 113
декодирование x265 с поддержкой MIPS SIMD 22
декодирование x264 без MIPS SIMD 164
декодирование x265 без MIPS SIMD 52

Таким образом, реальное время декодирования при использовании MIPS SIMD сокращается в 1.5 — 2.4 раза.


Полные логи работы ffmpeg опубликованы на github [L23].


Декодирование x264 с поддержкой MIPS SIMD (отчет, сокращенный вариант)
ffmpeg started on 2010-10-18 at 00:30:26
Report written to "ffmpeg-20101018-003026.log"
Command line:
./ffmpeg-mips/ffmpeg-msa/bin/ffmpeg -i "./The Simpsons Movie - Trailer_x264.mp4" -vf "fps=1/10" "./out_img/ffmpeg-msa_x264_%d.jpg" -report -benchmark
ffmpeg version 3.3 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.9.2 (Codescape GNU Tools 2016.05-03 for MIPS MTI Linux)
  configuration: --enable-cross-compile --prefix=../ffmpeg-msa --cross-prefix=/home/stas/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-03/bin/mips-mti-linux-gnu- --arch=mips --cpu=p5600 --target-os=linux --extra-cflags='-EL -static' --extra-ldflags='-EL -static' --disable-iconv
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
Splitting the commandline.
Reading option '-i' ... matched as input url with argument './The Simpsons Movie - Trailer_x264.mp4'.
Reading option '-vf' ... matched as option 'vf' (set video filters) with argument 'fps=1/10'.
Reading option './out_img/ffmpeg-msa_x264_%d.jpg' ... matched as output url.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option '-benchmark' ... matched as option 'benchmark' (add timings for benchmarking) with argument '1'.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Applying option benchmark (add timings for benchmarking) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url ./The Simpsons Movie - Trailer_x264.mp4.
Successfully parsed a group of options.
Opening an input file: ./The Simpsons Movie - Trailer_x264.mp4.
[file @ 0x1fce0e0] Setting default whitelist 'file,crypto'
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] ISO: File Type Major Brand: isom
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Before avformat_find_stream_info() pos: 73516232 bytes read:65587 seeks:1 nb_streams:2
[h264 @ 0x1fcecb0] nal_unit_type: 7, nal_ref_idc: 3
[h264 @ 0x1fcecb0] nal_unit_type: 8, nal_ref_idc: 3
[h264 @ 0x1fcecb0] nal_unit_type: 6, nal_ref_idc: 0
[h264 @ 0x1fcecb0] nal_unit_type: 5, nal_ref_idc: 3
[h264 @ 0x1fcecb0] user data:"x264 - core 54 svn-620M - H.264/MPEG-4 AVC codec - Copyleft 2005 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x1:0x131 me=umh subme=6 brdo=1 mixed_ref=0 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 chroma_qp_offset=0 threads=1 nr=0 decimate=1 mbaff=0 bframes=1 b_pyramid=0 b_adapt=1 b_bias=0 direct=3 wpredb=0 bime=0 keyint=250 keyint_min=25 scenecut=40 rc=2pass bitrate=4214 ratetol=1.0 rceq='blurCplx^(1-qComp)' qcomp=0.60 qpmin=10 qpmax=51 qpstep=4 cplxblur=20.0 qblur=0.5 ip_ratio=1.40 pb_ratio=1.30"
[h264 @ 0x1fcecb0] Reinit context to 1280x544, pix_fmt: yuv420p
[h264 @ 0x1fcecb0] no picture 
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] All info found
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] After avformat_find_stream_info() pos: 94845 bytes read:141348 seeks:2 frames:13
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './The Simpsons Movie - Trailer_x264.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2007-02-19T05:03:04.000000Z
  Duration: 00:02:17.30, start: 0.000000, bitrate: 4283 kb/s
    Stream #0:0(und), 12, 1/24000: Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x544, 4221 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Metadata:
      creation_time   : 2007-02-19T05:03:04.000000Z
      handler_name    : GPAC ISO Video Handler
    Stream #0:1(und), 1, 1/48000: Audio: aac (HE-AAC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 64 kb/s (default)
    Metadata:
      creation_time   : 2007-02-19T05:03:08.000000Z
      handler_name    : GPAC ISO Audio Handler
Successfully opened the file.
Parsing a group of options: output url ./out_img/ffmpeg-msa_x264_%d.jpg.
Applying option vf (set video filters) with argument fps=1/10.
Successfully parsed a group of options.
Opening an output file: ./out_img/ffmpeg-msa_x264_%d.jpg.
Successfully opened the file.
detected 2 logical cores
[h264 @ 0x20191e0] nal_unit_type: 7, nal_ref_idc: 3
[h264 @ 0x20191e0] nal_unit_type: 8, nal_ref_idc: 3
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> mjpeg (native))
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[h264 @ 0x20191e0] nal_unit_type: 6, nal_ref_idc: 0
[h264 @ 0x20191e0] nal_unit_type: 5, nal_ref_idc: 3
[h264 @ 0x20191e0] user data:"x264 - core 54 svn-620M - H.264/MPEG-4 AVC codec - Copyleft 2005 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x1:0x131 me=umh subme=6 brdo=1 mixed_ref=0 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 chroma_qp_offset=0 threads=1 nr=0 decimate=1 mbaff=0 bframes=1 b_pyramid=0 b_adapt=1 b_bias=0 direct=3 wpredb=0 bime=0 keyint=250 keyint_min=25 scenecut=40 rc=2pass bitrate=4214 ratetol=1.0 rceq='blurCplx^(1-qComp)' qcomp=0.60 qpmin=10 qpmax=51 qpstep=4 cplxblur=20.0 qblur=0.5 ip_ratio=1.40 pb_ratio=1.30"
[h264 @ 0x20191e0] Reinit context to 1280x544, pix_fmt: yuv420p
[h264 @ 0x20191e0] no picture 
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[h264 @ 0x2026050] nal_unit_type: 1, nal_ref_idc: 2
[h264 @ 0x2060f00] nal_unit_type: 1, nal_ref_idc: 0
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[h264 @ 0x20191e0] nal_unit_type: 1, nal_ref_idc: 2
[Parsed_fps_0 @ 0x202bf50] Setting 'fps' to value '1/10'
[Parsed_fps_0 @ 0x202bf50] fps=1/10
[graph 0 input from stream 0:0 @ 0x202c6f0] Setting 'video_size' to value '1280x544'
[graph 0 input from stream 0:0 @ 0x202c6f0] Setting 'pix_fmt' to value '0'
[graph 0 input from stream 0:0 @ 0x202c6f0] Setting 'time_base' to value '1/24000'
[graph 0 input from stream 0:0 @ 0x202c6f0] Setting 'pixel_aspect' to value '0/1'
[graph 0 input from stream 0:0 @ 0x202c6f0] Setting 'sws_param' to value 'flags=2'
[graph 0 input from stream 0:0 @ 0x202c6f0] Setting 'frame_rate' to value '24000/1001'
[graph 0 input from stream 0:0 @ 0x202c6f0] w:1280 h:544 pixfmt:yuv420p tb:1/24000 fr:24000/1001 sar:0/1 sws_param:flags=2
[format @ 0x202c030] compat: called with args=[yuvj420p|yuvj422p|yuvj444p]
[format @ 0x202c030] Setting 'pix_fmts' to value 'yuvj420p|yuvj422p|yuvj444p'
[auto_scaler_0 @ 0x202c660] Setting 'flags' to value 'bicubic'
[auto_scaler_0 @ 0x202c660] w:iw h:ih flags:'bicubic' interl:0
[format @ 0x202c030] auto-inserting filter 'auto_scaler_0' between the filter 'Parsed_fps_0' and the filter 'format'
[AVFilterGraph @ 0x202bb80] query_formats: 4 queried, 2 merged, 1 already done, 0 delayed
[auto_scaler_0 @ 0x202c660] picking yuvj420p out of 3 ref:yuv420p alpha:0
[swscaler @ 0x202cf00] deprecated pixel format used, make sure you did set range correctly
[auto_scaler_0 @ 0x202c660] w:1280 h:544 fmt:yuv420p sar:0/1 -> w:1280 h:544 fmt:yuvj420p sar:0/1 flags:0x4
[mjpeg @ 0x1ff5f90] Forcing thread count to 1 for MJPEG encoding, use -thread_type slice or a constant quantizer if you want to use multiple cpu cores
[mjpeg @ 0x1ff5f90] intra_quant_bias = 96 inter_quant_bias = 0
Output #0, image2, to './out_img/ffmpeg-msa_x264_%d.jpg':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    encoder         : Lavf57.71.100
    Stream #0:0(und), 0, 10/1: Video: mjpeg, yuvj420p(pc), 1280x544, q=2-31, 200 kb/s, 0.10 fps, 0.10 tbn, 0.10 tbc (default)
    Metadata:
      creation_time   : 2007-02-19T05:03:04.000000Z
      handler_name    : GPAC ISO Video Handler
      encoder         : Lavc57.89.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[Parsed_fps_0 @ 0x202bf50] Dropping 1 frame(s).
cur_dts is invalid (this is harmless if it occurs once at the start per stream)

...

[h264 @ 0x2060f00] nal_unit_type: 1, nal_ref_idc: 2
[Parsed_fps_0 @ 0x202bf50] Dropping 1 frame(s).
[Parsed_fps_0 @ 0x202bf50] Dropping 1 frame(s).
[Parsed_fps_0 @ 0x202bf50] Dropping 1 frame(s).
[file @ 0x209dc40] Setting default whitelist 'file,crypto'
[AVIOContext @ 0x2189ab0] Statistics: 0 seeks, 1 writeouts
frame=   15 fps=0.2 q=1.6 size=N/A time=00:02:30.00 bitrate=N/A speed=2.03x    
No more output streams to write to, finishing.
frame=   15 fps=0.2 q=1.6 Lsize=N/A time=00:02:30.00 bitrate=N/A speed=2.03x    
video:1382kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Input file #0 (./The Simpsons Movie - Trailer_x264.mp4):
  Input stream #0:0 (video): 3288 packets read (72364468 bytes); 3288 frames decoded; 
  Input stream #0:1 (audio): 1 packets read (134 bytes); 
  Total: 3289 packets (72364602 bytes) demuxed
Output file #0 (./out_img/ffmpeg-msa_x264_%d.jpg):
  Output stream #0:0 (video): 15 frames encoded; 15 packets muxed (1414925 bytes); 
  Total: 15 packets (1414925 bytes) muxed
bench: utime=113.070s
3288 frames successfully decoded, 0 decoding errors
bench: maxrss=39264kB
[Parsed_fps_0 @ 0x202bf50] 3288 frames in, 15 frames out; 3273 frames dropped, 0 frames duplicated.
[AVIOContext @ 0x1fd6230] Statistics: 73517562 bytes read, 5 seeks

Декодирование x265 с поддержкой MIPS SIMD (отчет, сокращенный вариант)
ffmpeg started on 2010-10-18 at 00:27:58
Report written to "ffmpeg-20101018-002758.log"
Command line:
./ffmpeg-mips/ffmpeg-msa/bin/ffmpeg -i ./Tears_400_x265.mp4 -vf "fps=1" "./out_img/ffmpeg-msa_x265_%d.jpg" -report -benchmark
ffmpeg version 3.3 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.9.2 (Codescape GNU Tools 2016.05-03 for MIPS MTI Linux)
  configuration: --enable-cross-compile --prefix=../ffmpeg-msa --cross-prefix=/home/stas/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-03/bin/mips-mti-linux-gnu- --arch=mips --cpu=p5600 --target-os=linux --extra-cflags='-EL -static' --extra-ldflags='-EL -static' --disable-iconv
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
Splitting the commandline.
Reading option '-i' ... matched as input url with argument './Tears_400_x265.mp4'.
Reading option '-vf' ... matched as option 'vf' (set video filters) with argument 'fps=1'.
Reading option './out_img/ffmpeg-msa_x265_%d.jpg' ... matched as output url.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option '-benchmark' ... matched as option 'benchmark' (add timings for benchmarking) with argument '1'.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Applying option benchmark (add timings for benchmarking) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url ./Tears_400_x265.mp4.
Successfully parsed a group of options.
Opening an input file: ./Tears_400_x265.mp4.
[file @ 0x1fce0e0] Setting default whitelist 'file,crypto'
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] ISO: File Type Major Brand: iso4
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] Before avformat_find_stream_info() pos: 705972 bytes read:32827 seeks:1 nb_streams:1
[hevc @ 0x1fceca0] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fceca0] Decoding VPS
[hevc @ 0x1fceca0] Main profile bitstream
[hevc @ 0x1fceca0] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fceca0] Decoding SPS
[hevc @ 0x1fceca0] Main profile bitstream
[hevc @ 0x1fceca0] Decoding VUI
[hevc @ 0x1fceca0] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fceca0] Decoding PPS
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] All info found
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1fcd980] After avformat_find_stream_info() pos: 20299 bytes read:65595 seeks:2 frames:1
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './Tears_400_x265.mp4':
  Metadata:
    major_brand     : iso4
    minor_version   : 1
    compatible_brands: iso4hvc1
    creation_time   : 2014-08-25T18:10:46.000000Z
  Duration: 00:00:13.96, start: 0.125000, bitrate: 404 kb/s
    Stream #0:0(und), 1, 1/24000: Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv), 1920x800, 402 kb/s, 24 fps, 24 tbr, 24k tbn, 24 tbc (default)
    Metadata:
      creation_time   : 2014-08-25T18:10:46.000000Z
      handler_name    : hevc:fps=24@GPAC0.5.1-DEV-rev4807
Successfully opened the file.
Parsing a group of options: output url ./out_img/ffmpeg-msa_x265_%d.jpg.
Applying option vf (set video filters) with argument fps=1.
Successfully parsed a group of options.
Opening an output file: ./out_img/ffmpeg-msa_x265_%d.jpg.
Successfully opened the file.
detected 2 logical cores
[hevc @ 0x1fe5a00] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] Decoding VPS
[hevc @ 0x1fe5a00] Main profile bitstream
[hevc @ 0x1fe5a00] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] Decoding SPS
[hevc @ 0x1fe5a00] Main profile bitstream
[hevc @ 0x1fe5a00] Decoding VUI
[hevc @ 0x1fe5a00] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] Decoding PPS
Stream mapping:
  Stream #0:0 -> #0:0 (hevc (native) -> mjpeg (native))
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1fe5a00] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] nal_unit_type: 19(IDR_W_RADL), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] Decoding SEI
[hevc @ 0x1fe5a00] Skipped PREFIX SEI 5
[hevc @ 0x1fe5a00] Decoding SEI
[hevc @ 0x1fe5a00] Skipped PREFIX SEI 6
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1ffeba0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x200c4d0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x200c4d0] Output frame with POC 0.
[hevc @ 0x1fe5a00] Decoded frame with POC 0.
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1fe5a00] nal_unit_type: 0(TRAIL_N), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1fe5a00] Output frame with POC 1.
[hevc @ 0x1ffeba0] Decoded frame with POC 5.
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1ffeba0] nal_unit_type: 0(TRAIL_N), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1ffeba0] Output frame with POC 2.
[hevc @ 0x200c4d0] Decoded frame with POC 3.
[Parsed_fps_0 @ 0x201a6c0] Setting 'fps' to value '1'
[Parsed_fps_0 @ 0x201a6c0] fps=1/1
[graph 0 input from stream 0:0 @ 0x201abb0] Setting 'video_size' to value '1920x800'
[graph 0 input from stream 0:0 @ 0x201abb0] Setting 'pix_fmt' to value '0'
[graph 0 input from stream 0:0 @ 0x201abb0] Setting 'time_base' to value '1/24000'
[graph 0 input from stream 0:0 @ 0x201abb0] Setting 'pixel_aspect' to value '0/1'
[graph 0 input from stream 0:0 @ 0x201abb0] Setting 'sws_param' to value 'flags=2'
[graph 0 input from stream 0:0 @ 0x201abb0] Setting 'frame_rate' to value '24/1'
[graph 0 input from stream 0:0 @ 0x201abb0] w:1920 h:800 pixfmt:yuv420p tb:1/24000 fr:24/1 sar:0/1 sws_param:flags=2
[format @ 0x201aad0] compat: called with args=[yuvj420p|yuvj422p|yuvj444p]
[format @ 0x201aad0] Setting 'pix_fmts' to value 'yuvj420p|yuvj422p|yuvj444p'
[auto_scaler_0 @ 0x201a350] Setting 'flags' to value 'bicubic'
[auto_scaler_0 @ 0x201a350] w:iw h:ih flags:'bicubic' interl:0
[format @ 0x201aad0] auto-inserting filter 'auto_scaler_0' between the filter 'Parsed_fps_0' and the filter 'format'
[AVFilterGraph @ 0x201a2f0] query_formats: 4 queried, 2 merged, 1 already done, 0 delayed
[auto_scaler_0 @ 0x201a350] picking yuvj420p out of 3 ref:yuv420p alpha:0
[swscaler @ 0x21d7da0] deprecated pixel format used, make sure you did set range correctly
[auto_scaler_0 @ 0x201a350] w:1920 h:800 fmt:yuv420p sar:0/1 -> w:1920 h:800 fmt:yuvj420p sar:0/1 flags:0x4
[mjpeg @ 0x1fe2ba0] Forcing thread count to 1 for MJPEG encoding, use -thread_type slice or a constant quantizer if you want to use multiple cpu cores
[mjpeg @ 0x1fe2ba0] intra_quant_bias = 96 inter_quant_bias = 0
Output #0, image2, to './out_img/ffmpeg-msa_x265_%d.jpg':
  Metadata:
    major_brand     : iso4
    minor_version   : 1
    compatible_brands: iso4hvc1
    encoder         : Lavf57.71.100
    Stream #0:0(und), 0, 1/1: Video: mjpeg, yuvj420p(pc), 1920x800, q=2-31, 200 kb/s, 1 fps, 1 tbn, 1 tbc (default)
    Metadata:
      creation_time   : 2014-08-25T18:10:46.000000Z
      handler_name    : hevc:fps=24@GPAC0.5.1-DEV-rev4807
      encoder         : Lavc57.89.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
cur_dts is invalid (this is harmless if it occurs once at the start per stream)

...

No more output streams to write to, finishing.
frame=   15 fps=0.7 q=24.8 Lsize=N/A time=00:00:15.00 bitrate=N/A speed=0.668x    
video:1084kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Input file #0 (./Tears_400_x265.mp4):
  Input stream #0:0 (video): 335 packets read (701773 bytes); 335 frames decoded; 
  Total: 335 packets (701773 bytes) demuxed
Output file #0 (./out_img/ffmpeg-msa_x265_%d.jpg):
  Output stream #0:0 (video): 15 frames encoded; 15 packets muxed (1109604 bytes); 
  Total: 15 packets (1109604 bytes) muxed
bench: utime=22.300s
335 frames successfully decoded, 0 decoding errors
bench: maxrss=72432kB
[Parsed_fps_0 @ 0x201a6c0] 335 frames in, 15 frames out; 320 frames dropped, 0 frames duplicated.
[AVIOContext @ 0x1fd6220] Statistics: 734659 bytes read, 2 seeks

Декодирование x264 без MIPS SIMD (отчет, сокращенный вариант)
ffmpeg started on 2010-10-18 at 00:28:31
Report written to "ffmpeg-20101018-002831.log"
Command line:
./ffmpeg-mips/ffmpeg-soft/bin/ffmpeg -i "./The Simpsons Movie - Trailer_x264.mp4" -vf "fps=1/10" "./out_img/ffmpeg-soft_x264_%d.jpg" -report -benchmark
ffmpeg version 3.3 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.9.2 (Codescape GNU Tools 2016.05-03 for MIPS MTI Linux)
  configuration: --enable-cross-compile --prefix=../ffmpeg-soft --cross-prefix=/home/stas/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-03/bin/mips-mti-linux-gnu- --arch=mips --cpu=p5600 --target-os=linux --extra-cflags='-EL -static' --extra-ldflags='-EL -static' --disable-iconv --disable-msa
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
Splitting the commandline.
Reading option '-i' ... matched as input url with argument './The Simpsons Movie - Trailer_x264.mp4'.
Reading option '-vf' ... matched as option 'vf' (set video filters) with argument 'fps=1/10'.
Reading option './out_img/ffmpeg-soft_x264_%d.jpg' ... matched as output url.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option '-benchmark' ... matched as option 'benchmark' (add timings for benchmarking) with argument '1'.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Applying option benchmark (add timings for benchmarking) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url ./The Simpsons Movie - Trailer_x264.mp4.
Successfully parsed a group of options.
Opening an input file: ./The Simpsons Movie - Trailer_x264.mp4.
[file @ 0x1f4a0e0] Setting default whitelist 'file,crypto'
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] ISO: File Type Major Brand: isom
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Before avformat_find_stream_info() pos: 73516232 bytes read:65587 seeks:1 nb_streams:2
[h264 @ 0x1f4acb0] nal_unit_type: 7, nal_ref_idc: 3
[h264 @ 0x1f4acb0] nal_unit_type: 8, nal_ref_idc: 3
[h264 @ 0x1f4acb0] nal_unit_type: 6, nal_ref_idc: 0
[h264 @ 0x1f4acb0] nal_unit_type: 5, nal_ref_idc: 3
[h264 @ 0x1f4acb0] user data:"x264 - core 54 svn-620M - H.264/MPEG-4 AVC codec - Copyleft 2005 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x1:0x131 me=umh subme=6 brdo=1 mixed_ref=0 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 chroma_qp_offset=0 threads=1 nr=0 decimate=1 mbaff=0 bframes=1 b_pyramid=0 b_adapt=1 b_bias=0 direct=3 wpredb=0 bime=0 keyint=250 keyint_min=25 scenecut=40 rc=2pass bitrate=4214 ratetol=1.0 rceq='blurCplx^(1-qComp)' qcomp=0.60 qpmin=10 qpmax=51 qpstep=4 cplxblur=20.0 qblur=0.5 ip_ratio=1.40 pb_ratio=1.30"
[h264 @ 0x1f4acb0] Reinit context to 1280x544, pix_fmt: yuv420p
[h264 @ 0x1f4acb0] no picture 
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] All info found
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] After avformat_find_stream_info() pos: 94845 bytes read:141348 seeks:2 frames:13
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './The Simpsons Movie - Trailer_x264.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2007-02-19T05:03:04.000000Z
  Duration: 00:02:17.30, start: 0.000000, bitrate: 4283 kb/s
    Stream #0:0(und), 12, 1/24000: Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x544, 4221 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Metadata:
      creation_time   : 2007-02-19T05:03:04.000000Z
      handler_name    : GPAC ISO Video Handler
    Stream #0:1(und), 1, 1/48000: Audio: aac (HE-AAC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 64 kb/s (default)
    Metadata:
      creation_time   : 2007-02-19T05:03:08.000000Z
      handler_name    : GPAC ISO Audio Handler
Successfully opened the file.
Parsing a group of options: output url ./out_img/ffmpeg-soft_x264_%d.jpg.
Applying option vf (set video filters) with argument fps=1/10.
Successfully parsed a group of options.
Opening an output file: ./out_img/ffmpeg-soft_x264_%d.jpg.
Successfully opened the file.
detected 2 logical cores
[h264 @ 0x1f951e0] nal_unit_type: 7, nal_ref_idc: 3
[h264 @ 0x1f951e0] nal_unit_type: 8, nal_ref_idc: 3
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> mjpeg (native))
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[h264 @ 0x1f951e0] nal_unit_type: 6, nal_ref_idc: 0
[h264 @ 0x1f951e0] nal_unit_type: 5, nal_ref_idc: 3
[h264 @ 0x1f951e0] user data:"x264 - core 54 svn-620M - H.264/MPEG-4 AVC codec - Copyleft 2005 - http://www.videolan.org/x264.html - options: cabac=1 ref=5 deblock=1:0:0 analyse=0x1:0x131 me=umh subme=6 brdo=1 mixed_ref=0 me_range=16 chroma_me=1 trellis=1 8x8dct=0 cqm=0 deadzone=21,11 chroma_qp_offset=0 threads=1 nr=0 decimate=1 mbaff=0 bframes=1 b_pyramid=0 b_adapt=1 b_bias=0 direct=3 wpredb=0 bime=0 keyint=250 keyint_min=25 scenecut=40 rc=2pass bitrate=4214 ratetol=1.0 rceq='blurCplx^(1-qComp)' qcomp=0.60 qpmin=10 qpmax=51 qpstep=4 cplxblur=20.0 qblur=0.5 ip_ratio=1.40 pb_ratio=1.30"
[h264 @ 0x1f951e0] Reinit context to 1280x544, pix_fmt: yuv420p
[h264 @ 0x1f951e0] no picture 
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[h264 @ 0x1fa2050] nal_unit_type: 1, nal_ref_idc: 2
[h264 @ 0x1fdcf00] nal_unit_type: 1, nal_ref_idc: 0
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[h264 @ 0x1f951e0] nal_unit_type: 1, nal_ref_idc: 2
[Parsed_fps_0 @ 0x1fa7f50] Setting 'fps' to value '1/10'
[Parsed_fps_0 @ 0x1fa7f50] fps=1/10
[graph 0 input from stream 0:0 @ 0x1fa86f0] Setting 'video_size' to value '1280x544'
[graph 0 input from stream 0:0 @ 0x1fa86f0] Setting 'pix_fmt' to value '0'
[graph 0 input from stream 0:0 @ 0x1fa86f0] Setting 'time_base' to value '1/24000'
[graph 0 input from stream 0:0 @ 0x1fa86f0] Setting 'pixel_aspect' to value '0/1'
[graph 0 input from stream 0:0 @ 0x1fa86f0] Setting 'sws_param' to value 'flags=2'
[graph 0 input from stream 0:0 @ 0x1fa86f0] Setting 'frame_rate' to value '24000/1001'
[graph 0 input from stream 0:0 @ 0x1fa86f0] w:1280 h:544 pixfmt:yuv420p tb:1/24000 fr:24000/1001 sar:0/1 sws_param:flags=2
[format @ 0x1fa8030] compat: called with args=[yuvj420p|yuvj422p|yuvj444p]
[format @ 0x1fa8030] Setting 'pix_fmts' to value 'yuvj420p|yuvj422p|yuvj444p'
[auto_scaler_0 @ 0x1fa8660] Setting 'flags' to value 'bicubic'
[auto_scaler_0 @ 0x1fa8660] w:iw h:ih flags:'bicubic' interl:0
[format @ 0x1fa8030] auto-inserting filter 'auto_scaler_0' between the filter 'Parsed_fps_0' and the filter 'format'
[AVFilterGraph @ 0x1fa7b80] query_formats: 4 queried, 2 merged, 1 already done, 0 delayed
[auto_scaler_0 @ 0x1fa8660] picking yuvj420p out of 3 ref:yuv420p alpha:0
[swscaler @ 0x1fa8f00] deprecated pixel format used, make sure you did set range correctly
[auto_scaler_0 @ 0x1fa8660] w:1280 h:544 fmt:yuv420p sar:0/1 -> w:1280 h:544 fmt:yuvj420p sar:0/1 flags:0x4
[mjpeg @ 0x1f71f90] Forcing thread count to 1 for MJPEG encoding, use -thread_type slice or a constant quantizer if you want to use multiple cpu cores
[mjpeg @ 0x1f71f90] intra_quant_bias = 96 inter_quant_bias = 0
Output #0, image2, to './out_img/ffmpeg-soft_x264_%d.jpg':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    encoder         : Lavf57.71.100
    Stream #0:0(und), 0, 10/1: Video: mjpeg, yuvj420p(pc), 1280x544, q=2-31, 200 kb/s, 0.10 fps, 0.10 tbn, 0.10 tbc (default)
    Metadata:
      creation_time   : 2007-02-19T05:03:04.000000Z
      handler_name    : GPAC ISO Video Handler
      encoder         : Lavc57.89.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[Parsed_fps_0 @ 0x1fa7f50] Dropping 1 frame(s).
[h264 @ 0x1fa2050] nal_unit_type: 1, nal_ref_idc: 0

...

[AVIOContext @ 0x2229af0] Statistics: 0 seeks, 1 writeouts
No more output streams to write to, finishing.
frame=   15 fps=0.1 q=1.6 Lsize=N/A time=00:02:30.00 bitrate=N/A speed=1.45x    
video:1382kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Input file #0 (./The Simpsons Movie - Trailer_x264.mp4):
  Input stream #0:0 (video): 3288 packets read (72364468 bytes); 3288 frames decoded; 
  Input stream #0:1 (audio): 1 packets read (134 bytes); 
  Total: 3289 packets (72364602 bytes) demuxed
Output file #0 (./out_img/ffmpeg-soft_x264_%d.jpg):
  Output stream #0:0 (video): 15 frames encoded; 15 packets muxed (1414925 bytes); 
  Total: 15 packets (1414925 bytes) muxed
bench: utime=164.240s
3288 frames successfully decoded, 0 decoding errors
bench: maxrss=39936kB
[Parsed_fps_0 @ 0x1fa7f50] 3288 frames in, 15 frames out; 3273 frames dropped, 0 frames duplicated.
[AVIOContext @ 0x1f52230] Statistics: 73517562 bytes read, 5 seeks

Декодирование x265 без MIPS SIMD (отчет, сокращенный вариант)
ffmpeg started on 2010-10-18 at 00:27:14
Report written to "ffmpeg-20101018-002714.log"
Command line:
./ffmpeg-mips/ffmpeg-soft/bin/ffmpeg -i ./Tears_400_x265.mp4 -vf "fps=1" "./out_img/ffmpeg-soft_x265_%d.jpg" -report -benchmark
ffmpeg version 3.3 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.9.2 (Codescape GNU Tools 2016.05-03 for MIPS MTI Linux)
  configuration: --enable-cross-compile --prefix=../ffmpeg-soft --cross-prefix=/home/stas/mipsfpga/toolchain/mips-mti-linux-gnu/2016.05-03/bin/mips-mti-linux-gnu- --arch=mips --cpu=p5600 --target-os=linux --extra-cflags='-EL -static' --extra-ldflags='-EL -static' --disable-iconv --disable-msa
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
Splitting the commandline.
Reading option '-i' ... matched as input url with argument './Tears_400_x265.mp4'.
Reading option '-vf' ... matched as option 'vf' (set video filters) with argument 'fps=1'.
Reading option './out_img/ffmpeg-soft_x265_%d.jpg' ... matched as output url.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option '-benchmark' ... matched as option 'benchmark' (add timings for benchmarking) with argument '1'.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Applying option benchmark (add timings for benchmarking) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url ./Tears_400_x265.mp4.
Successfully parsed a group of options.
Opening an input file: ./Tears_400_x265.mp4.
[file @ 0x1f4a0e0] Setting default whitelist 'file,crypto'
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] ISO: File Type Major Brand: iso4
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Unknown dref type 0x206c7275 size 12
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] Before avformat_find_stream_info() pos: 705972 bytes read:32827 seeks:1 nb_streams:1
[hevc @ 0x1f4aca0] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f4aca0] Decoding VPS
[hevc @ 0x1f4aca0] Main profile bitstream
[hevc @ 0x1f4aca0] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f4aca0] Decoding SPS
[hevc @ 0x1f4aca0] Main profile bitstream
[hevc @ 0x1f4aca0] Decoding VUI
[hevc @ 0x1f4aca0] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f4aca0] Decoding PPS
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] All info found
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x1f49980] After avformat_find_stream_info() pos: 20299 bytes read:65595 seeks:2 frames:1
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './Tears_400_x265.mp4':
  Metadata:
    major_brand     : iso4
    minor_version   : 1
    compatible_brands: iso4hvc1
    creation_time   : 2014-08-25T18:10:46.000000Z
  Duration: 00:00:13.96, start: 0.125000, bitrate: 404 kb/s
    Stream #0:0(und), 1, 1/24000: Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv), 1920x800, 402 kb/s, 24 fps, 24 tbr, 24k tbn, 24 tbc (default)
    Metadata:
      creation_time   : 2014-08-25T18:10:46.000000Z
      handler_name    : hevc:fps=24@GPAC0.5.1-DEV-rev4807
Successfully opened the file.
Parsing a group of options: output url ./out_img/ffmpeg-soft_x265_%d.jpg.
Applying option vf (set video filters) with argument fps=1.
Successfully parsed a group of options.
Opening an output file: ./out_img/ffmpeg-soft_x265_%d.jpg.
Successfully opened the file.
detected 2 logical cores
[hevc @ 0x1f61a00] nal_unit_type: 32(VPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] Decoding VPS
[hevc @ 0x1f61a00] Main profile bitstream
[hevc @ 0x1f61a00] nal_unit_type: 33(SPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] Decoding SPS
[hevc @ 0x1f61a00] Main profile bitstream
[hevc @ 0x1f61a00] Decoding VUI
[hevc @ 0x1f61a00] nal_unit_type: 34(PPS), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] Decoding PPS
Stream mapping:
  Stream #0:0 -> #0:0 (hevc (native) -> mjpeg (native))
Press [q] to stop, [?] for help
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1f61a00] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] nal_unit_type: 39(SEI_PREFIX), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] nal_unit_type: 19(IDR_W_RADL), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] Decoding SEI
[hevc @ 0x1f61a00] Skipped PREFIX SEI 5
[hevc @ 0x1f61a00] Decoding SEI
[hevc @ 0x1f61a00] Skipped PREFIX SEI 6
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1f7aba0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f884d0] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f884d0] Output frame with POC 0.
[hevc @ 0x1f61a00] Decoded frame with POC 0.
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1f61a00] nal_unit_type: 0(TRAIL_N), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f61a00] Output frame with POC 1.
[hevc @ 0x1f7aba0] Decoded frame with POC 5.
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1f7aba0] nal_unit_type: 0(TRAIL_N), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f7aba0] Output frame with POC 2.
[hevc @ 0x1f884d0] Decoded frame with POC 3.
[Parsed_fps_0 @ 0x1f966c0] Setting 'fps' to value '1'
[Parsed_fps_0 @ 0x1f966c0] fps=1/1
[graph 0 input from stream 0:0 @ 0x1f96bb0] Setting 'video_size' to value '1920x800'
[graph 0 input from stream 0:0 @ 0x1f96bb0] Setting 'pix_fmt' to value '0'
[graph 0 input from stream 0:0 @ 0x1f96bb0] Setting 'time_base' to value '1/24000'
[graph 0 input from stream 0:0 @ 0x1f96bb0] Setting 'pixel_aspect' to value '0/1'
[graph 0 input from stream 0:0 @ 0x1f96bb0] Setting 'sws_param' to value 'flags=2'
[graph 0 input from stream 0:0 @ 0x1f96bb0] Setting 'frame_rate' to value '24/1'
[graph 0 input from stream 0:0 @ 0x1f96bb0] w:1920 h:800 pixfmt:yuv420p tb:1/24000 fr:24/1 sar:0/1 sws_param:flags=2
[format @ 0x1f96ad0] compat: called with args=[yuvj420p|yuvj422p|yuvj444p]
[format @ 0x1f96ad0] Setting 'pix_fmts' to value 'yuvj420p|yuvj422p|yuvj444p'
[hevc @ 0x1f61a00] Decoded frame with POC 1.
[hevc @ 0x1f7aba0] Decoded frame with POC 2.
[auto_scaler_0 @ 0x1f96350] Setting 'flags' to value 'bicubic'
[auto_scaler_0 @ 0x1f96350] w:iw h:ih flags:'bicubic' interl:0
[format @ 0x1f96ad0] auto-inserting filter 'auto_scaler_0' between the filter 'Parsed_fps_0' and the filter 'format'
[AVFilterGraph @ 0x1f962f0] query_formats: 4 queried, 2 merged, 1 already done, 0 delayed
[auto_scaler_0 @ 0x1f96350] picking yuvj420p out of 3 ref:yuv420p alpha:0
[swscaler @ 0x2153da0] deprecated pixel format used, make sure you did set range correctly
[auto_scaler_0 @ 0x1f96350] w:1920 h:800 fmt:yuv420p sar:0/1 -> w:1920 h:800 fmt:yuvj420p sar:0/1 flags:0x4
[mjpeg @ 0x1f5eba0] Forcing thread count to 1 for MJPEG encoding, use -thread_type slice or a constant quantizer if you want to use multiple cpu cores
[mjpeg @ 0x1f5eba0] intra_quant_bias = 96 inter_quant_bias = 0
Output #0, image2, to './out_img/ffmpeg-soft_x265_%d.jpg':
  Metadata:
    major_brand     : iso4
    minor_version   : 1
    compatible_brands: iso4hvc1
    encoder         : Lavf57.71.100
    Stream #0:0(und), 0, 1/1: Video: mjpeg, yuvj420p(pc), 1920x800, q=2-31, 200 kb/s, 1 fps, 1 tbn, 1 tbc (default)
    Metadata:
      creation_time   : 2014-08-25T18:10:46.000000Z
      handler_name    : hevc:fps=24@GPAC0.5.1-DEV-rev4807
      encoder         : Lavc57.89.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1f884d0] nal_unit_type: 0(TRAIL_N), nuh_layer_id: 0, temporal_id: 0
[hevc @ 0x1f884d0] Output frame with POC 3.
[Parsed_fps_0 @ 0x1f966c0] Dropping 1 frame(s).
frame=    0 fps=0.0 q=0.0 size=N/A time=00:00:00.00 bitrate=N/A speed=   0x    
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[Parsed_fps_0 @ 0x1f966c0] Dropping 1 frame(s).
[hevc @ 0x1f61a00] nal_unit_type: 1(TRAIL_R), nuh_layer_id: 0, temporal_id: 0
cur_dts is invalid (this is harmless if it occurs once at the start per stream)
[hevc @ 0x1f61a00] Output frame with POC 4.

... 

No more output streams to write to, finishing.
frame=   15 fps=0.5 q=24.8 Lsize=N/A time=00:00:15.00 bitrate=N/A speed=0.451x    
video:1084kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
Input file #0 (./Tears_400_x265.mp4):
  Input stream #0:0 (video): 335 packets read (701773 bytes); 335 frames decoded; 
  Total: 335 packets (701773 bytes) demuxed
Output file #0 (./out_img/ffmpeg-soft_x265_%d.jpg):
  Output stream #0:0 (video): 15 frames encoded; 15 packets muxed (1109604 bytes); 
  Total: 15 packets (1109604 bytes) muxed
bench: utime=52.330s
335 frames successfully decoded, 0 decoding errors
bench: maxrss=72480kB
[Parsed_fps_0 @ 0x1f966c0] 335 frames in, 15 frames out; 320 frames dropped, 0 frames duplicated.
[AVIOContext @ 0x1f52220] Statistics: 734659 bytes read, 2 seeks

Выводы


  • MIPS SIMD является достаточно мощным инструментом повышения производительности и позволяет в разы сократить реальное время вычислений и соответствующим образом увеличить их скорость;
  • оптимизация — это дорого в части трудозатрат разработчика. Реализация какого-либо алгоритма с использованием MIPS SIMD ближе к написанию ассемблерных вставок, нежели к высокоуровневому программированию. Что требует взвешенного подхода при принятии решений о переработке кода;
  • Байкал-Т1 — это не вымысел маркетологов, он существует, работает, под него вполне спокойно была собрана последняя версия достаточно сложного программного пакета и она на нем без проблем запустилась.

Ссылки


[L1] — Процессор Байкал-Т1;
[L2] — Проект MIPSfpga-plus на github;
[L3] — P-Class P5600 Multiprocessor Core;
[L4] — Добавляем инструкции в микропроцессор MIPS, которые работают в конвейере как его собственные;
[L5] — Texas Instruments. Digital Signal Processors;
[L6] — Альтернативное использование мощностей GPU;
[L7] — OpenCL. Что это такое и зачем он нужен;
[L8] — Wikipedia: Фильтр с конечной импульсной характеристикой;
[L9] — TFilter. Free online FIR filter design tool;
[L10] — Wikipedia: Цифровой сигнальный процессор;
[L11] — Wikipedia: Полосно-заграждающий фильтр;
[L12] — Wikipedia: Амплитудно-частотная характеристика;
[L13] — Wikipedia: SIMD;
[L14] — Wikipedia: Векторный процессор;
[L15] — MIPS SIMD;
[L16] — GCC: MIPS SIMD Architecture (MSA) Support;
[L17] — GCC: MIPS SIMD Architecture Built-in Functions;
[L18] — Проект ffmpeg на github (каталог libavcodec/mips/);
[L19] — FFmpeg multimedia framework;
[L20] — Codescape MIPS SDK;
[L21] — H.264 Demo Clips;
[L22] — x256. Sample HEVC Video Files;
[L23] — Логи работы ffmpeg
[L24] — Материалы семинара Специализированные интегральные схемы наноуровня;


Документация


[D1] — Титце У., Шенк К. — Полупроводниковая схемотехника;
[D2] — MIPS Architecture for Programmers Volume IV-j: The MIPS32 SIMD Architecture Module;
[D3] — MIPS SIMD programming. Optimizing multimedia codecs;


Изображения и таблицы


[P1] — Блок-схема Байкал-Т1. (Источник: L1);
[P2] — TFilter. Пример настройки режекторного фильтра 1 (скриншот);
[P3] — TFilter. АЧХ режекторного фильтра 1;
[P4] — TFilter. Пример настройки режекторного фильтра 2 (скриншот);
[P5] — TFilter. АЧХ режекторного фильтра 2;
[P6] — Сравнение традиционного подхода и SIMD-реализации фильтра (Источник: D3);
[P7] — MSA Vector registers (Источник: D2);
[P8] — MADDV Operation description (Источник: D2);

Tags:
Hubs:
+25
Comments 13
Comments Comments 13

Articles