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

    Коллеги из Байкал Электроникс предложили поработать с процессором Байкал-Т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);

    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 13
    • +1
      ну а теперь главный вопрос, где купить?
    • 0
      Купить можно в конторе. Все контакты на сайте Байкал Электроникс.
      • 0
        обрана последняя версия достаточно сложного программного пакета и она на нем без проблем запустилась
        И работала с тормозами?
        • 0
          Какой смысл вы вкладываете во фразу «работала с тормозами»? ffmpeg — это консольное приложение, поэтому у него нет «времени отклика на действия с элементами GUI», высокое значения которого принято называть «тормозами»
          • 0
            было бы интересней если бы были даны цены:
            1) процессора байкал + материнской платы под него,
            2) проц + мамка для амд
            2) проц + мамка для intel
            и всё это сравнить за сколько секунд*цена декодирует — байкал, амд и интел.

            Байкал-Т1 — это не вымысел маркетологов, он существует
            БТРы на колесах тоже существуют, только по городу на них ездят редко.

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

              Я не ставил перед собой задачу проводить какой-то анализ в стиле "MIPS vs неMIPS" или "Байкал vs Intel vs AMD vs ARM".
              Если у вас есть серьезное желание провести подобные сравнительные тесты на производительность, и вы готовы собрать соответствующий стенд в стиле iXBT — обратитесь к производителю: https://habrahabr.ru/post/328566/#comment_10220052 — думаю, что вам помогут получить удаленный доступ к Байкалу. У меня с этим проблем не возникло.
              Что касается цены, то ее предоставлении по запросу является политикой производителя. При всем сожалении — не мне ее менять.


              БТРы на колесах тоже существуют

              Не понимаю сути данного выпада.
              Для информации: в городских условиях у вас гораздо больше шансов встретить колесный бронетранспортер (БТР-80, -82), чем гусеничный (МТ-ЛБ) или любую иную бронетехнику. В силу того, что колесная техника в мирное время может (в отличии от гусеничной) передвигаться по дорогам общего пользования. Именно поэтому колесные БТР стоят на вооружении внутренних войск, или, как сейчас их называют — Росгвардии.
              Пожалуйста, учите матчасть или формулируйте свои мысли более четко.


              В таблице скорее всего ошибка

              Покажите, пожалуйста, где. Выкопировки из логов, так же как ссылка на полные логи — приведены в составе статьи.

              • 0
                декодирование x264 с поддержкой MIPS SIMD 113 сек
                декодирование x264 без MIPS SIMD 164 сек

                SIMD в байкале замедляет?

                БТРы на колесах тоже существуют, только по городу на них ездят редко.
                Не понимаю сути данного выпада.
                99% населения ездит на другом транспорте, а не на БТР.
                Так же и с непонятным байкалом, кому он нужен, если остальные ездят на x86, arm и тд.
                • 0
                  хотя я наверно ошибся, не думал что x265 настолько быстрее чем x264
                  • 0

                    Там разные файлы на входе, закодированные разными кодеками. Один короткий (x265), другой — длинный (x264). Отсюда разница.

                  • 0
                    SIMD в байкале замедляет?

                    прочитайте, пожалуйста, внимательно: 113 сек (с поддержкой SIMD) < 164 сек (без SIMD).


                    Так же и с непонятным байкалом, кому он нужен, если остальные ездят на x86, arm и тд.

                    Время рассудит. А между делом никому не нужный процессор собираются выпустить партией до 100 тыс. штук: http://www.baikalelectronics.ru/about/press-center/news/FRP_project/

          • +1
            Пишу в свободное время библиотеку связанную обработкой изображений. Сейчас она поддерживает SIMD расширения различных CPU (x86, ppc, arm). Было бы интересно поработать и с MIPS (добавить поддержку MSA). Можно ли как-то получить удаленный доступ к байкалу?
            • 0
              Да, конечно. Напишите мне на почту, Andrey.Malafeev собака baikalelectronics.ru, я организую.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.