реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Лишние NOP в ассемблерном коде
Degun
сообщение Oct 23 2007, 11:54
Сообщение #1


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Code Composer Studio v 3.3; Процессор DM642 на evalution board.
Имеется программка, написанная на C++. После анализа её ассемблерного кода выяснилось, что после многих команд (LDW, ADD, CMPLT, AND, LDHU и др.) компилятор вставляет команду NOP, что естественно замедляет функционирование программы. Для чего это? Можно ли отключить вставку операторов NOP в ассемблерный код?
Go to the top of the page
 
+Quote Post
fontp
сообщение Oct 23 2007, 12:04
Сообщение #2


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(Degun @ Oct 23 2007, 15:54) *
Code Composer Studio v 3.3; Процессор DM642 на evalution board.
Имеется программка, написанная на C++. После анализа её ассемблерного кода выяснилось, что после многих команд (LDW, ADD, CMPLT, AND, LDHU и др.) компилятор вставляет команду NOP, что естественно замедляет функционирование программы. Для чего это? Можно ли отключить вставку операторов NOP в ассемблерный код?


Это не ассемблерный код, а выход С-компилятора.

У TI такой подход, что программист (или компилятор) должен следить за длительностью выполнения инструкций (latency). Например, если умножение требует 5 тактов, то нужно пять тактов и ждать, в противном случае Вы выхватываете из конвейера неверный результат (что, однако, никто Вам запретить не может). Вот компилятор и борется с "открытым конвейером"

Есть единственный гарантированый способ избежать вставки NOP в ассемблерный код - написать самому на ассемблере, так чтобы без NOPов ;-) TMS серии 6х - это ведь кубик Рубика
Go to the top of the page
 
+Quote Post
Degun
сообщение Oct 23 2007, 12:15
Сообщение #3


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Цитата(fontp @ Oct 23 2007, 16:04) *
Это не ассемблерный код, а выход С-компилятора.

А разве это не одно и тоже?
Цитата(fontp @ Oct 23 2007, 16:04) *
У TI такой подход, что программист (или компилятор) должен следить за длительностью выполнения инструкций (latency). Например, если умножение требует 5 тактов, то нужно пять тактов и ждать, в противном случае Вы выхватываете из конвейера неверный результат (что, однако, никто Вам запретить не может). Вот компилятор и борется с "открытым конвейером"
Есть единственный гарантированый способ избежать вставки NOP в ассемблерный код - написать самому на ассемблере, так чтобы без NOPов ;-) TMS серии 6х - это ведь кубик Рубика

Не совсем понятно. Если умножению, например, требуется 5 тактов, то соответствующая команда и будет выполняться необходимое кол-во тактов и только после после этого перейдёт к выполнению следующей. Или переход к выполнению следующей команды осуществляется сразу, а результат умножения будет готов только через 5 тактов?
Go to the top of the page
 
+Quote Post
fontp
сообщение Oct 23 2007, 12:28
Сообщение #4


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(Degun @ Oct 23 2007, 16:15) *
А разве это не одно и тоже?

Не совсем понятно. Если умножению, например, требуется 5 тактов, то соответствующая команда и будет выполняться необходимое кол-во тактов и только после после этого перейдёт к выполнению следующей. Или переход к выполнению следующей команды осуществляется сразу, а результат умножения будет готов только через 5 тактов?


Навроде того.
Как захотите так и будет. Вставите 4 NOP дождётесь правильного результата.
Не вставите - никто Вам мешать не станет, процессор не станет ждать.
Но результат будет неверный. Ваше личное дело.
Програмировать открытый конвейер - это как оперировать на открытом мозге

Выход кодогенератора - формально тоже ассемблерный код, но не сильно осмысленый
Осмысленный ассемблерный код пишется программистом
Go to the top of the page
 
+Quote Post
Edmundo
сообщение Oct 24 2007, 12:36
Сообщение #5


Мастер
****

Группа: Свой
Сообщений: 730
Регистрация: 18-02-06
Из: Москва
Пользователь №: 14 474



Цитата(Degun @ Oct 23 2007, 16:15) *
Не совсем понятно. Если умножению, например, требуется 5 тактов, то соответствующая команда и будет выполняться необходимое кол-во тактов и только после после этого перейдёт к выполнению следующей. Или переход к выполнению следующей команды осуществляется сразу, а результат умножения будет готов только через 5 тактов?

Вы читали про ядро, про 8 "вычислителей", про кросс-пути и про параллельное выполнение?
И еще -- если поиграться оптимизацией -- можно получить неплохой код, не обязательно бросаться писать на АСМе. Ну да C vs. ASM -- это из другой оперы biggrin.gif


--------------------
شامل
Go to the top of the page
 
+Quote Post
Degun
сообщение Oct 24 2007, 19:24
Сообщение #6


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



А вообще можете посоветовать:
1. каких правил или приёмов необходимо придерживаться при написании C++ кода для DSP процессора (DM642), чтобы он имел максимальную производительность.
2. что лишнего можно выключить в DSP-BIOS, чтобы уменьшить вычислительную нагрузку на процессор.
Go to the top of the page
 
+Quote Post
Degun
сообщение Oct 26 2007, 12:06
Сообщение #7


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Что можно сделать или оптимизировать в функции ниже в плане генерации оптимального кода для DSP-процессора?
Код
int SplitImage2Areas(unsigned char **Image, int **AreasNumb, int *Areas2Mode, int Width, int Height, int Thres1, int Thres2)
{
    if ((Image==0)||(Width<=0)||(Height<=0)||(AreasNumb==0)) return -1;

    int iPrevAreaNumbL=-1;  //Номер области предыдущей левой точки
    int iPrevModeNumbL=-1;  //Номер моды предыдущей левой точки
    int iPrevAreaNumbU=-1;  //Номер области предыдущей верхней точки
    int iPrevModeNumbU=-1;  //Номер моды предыдущей верхней точки
    int iPrevAreaNumbUL=-1; //Номер области предыдущей верхней левой точки
    int iPrevModeNumbUL=-1; //Номер моды предыдущей верхней левой точки
    int iPrevAreaNumbUR=-1; //Номер области предыдущей верхней правой точки
    int iPrevModeNumbUR=-1; //Номер моды предыдущей верхней правой точки
    int iAreasCount=0;      //Счётчик кол-ва областей
    int i, j, y, x, iNumb[4], iNumbCount, iDelta, iTmp;
    int iCurrPixel, iCurrAreaNumb, iCurrModeNumb;
    //Изображение последовательно просматривается по строкам
    //для отнесения каждого пиксела к определённой области
    for (y=0; y<Height; y++) for (x=0; x<Width; x++)
    {
        //Значение яркости текущего пикселя
        iCurrPixel=Image[y][x];
        //Номер области текущей точки
        iCurrAreaNumb=-1;
        //Номер моды текущей точки
        iCurrModeNumb=(iCurrPixel<Thres1?0:(iCurrPixel>Thres2?1:-1));
        //Определение параметров верхней правой точки
        if ((y>0)&&(x<(Width-1)))
        {
            iPrevAreaNumbUR=AreasNumb[y-1][x+1];
            iPrevModeNumbUR=Areas2Mode[iPrevAreaNumbUR];
        }
        //В зависимости от того является ли точка переходной
        if (iCurrModeNumb>=0)
        {
            //Эта точка не является переходной ни к одной из мод
            //Просмотр всех соседних уже размеченных ранее точек
            //для возможного определения номера области текущей точки
            if ((x>0)&&(iCurrModeNumb==iPrevModeNumbL)) {
                iCurrAreaNumb=iPrevAreaNumbL; //Левая точка
            }
            else if (y>0) { //Верхняя строка
                if (iCurrModeNumb==iPrevModeNumbU) {
                    iCurrAreaNumb=iPrevAreaNumbU; //Верхняя точка
                }
                else if ((x>0)&&(iCurrModeNumb==iPrevModeNumbUL)) {
                    iCurrAreaNumb=iPrevAreaNumbUL; //Верхняя левая точка
                }
                else if ((x<(Width-1))&&(iCurrModeNumb==iPrevModeNumbUR)) {
                    iCurrAreaNumb=iPrevAreaNumbUR; //Верхняя правая точка
                }
            }
        }
        else
        {
            //Текущая точка является переходной к любой области
            //Выбор наиболее близкой области
            iDelta=iTmp=-1;
            if (x>0) { //Левая точка
                iCurrAreaNumb=iPrevAreaNumbL;
                iDelta=abs(Image[y][x-1]-iCurrPixel);
            }
            if (y>0) { //Верхняя строка
                //Верхняя точка
                iTmp=abs(Image[y-1][x]-iCurrPixel);
                if ((iDelta<0)||(iDelta>iTmp)) {
                    iCurrAreaNumb=iPrevAreaNumbU;
                    iDelta=iTmp;
                }
                if (x>0) { //Верхняя левая точка
                    iTmp=abs(Image[y-1][x-1]-iCurrPixel);
                    if (iDelta>iTmp) {
                        iCurrAreaNumb=iPrevAreaNumbUL;
                        iDelta=iTmp;
                    }
                }
                if (x<(Width-1)) { //Верхняя правая точка
                    iTmp=abs(Image[y-1][x+1]-iCurrPixel);
                    if (iDelta>iTmp) {
                        iCurrAreaNumb=iPrevAreaNumbUR;
                        iDelta=iTmp;
                    }
                }
            }
            //Проверка на верхнюю левую точку всего изображения
            if (iCurrAreaNumb>=0)
                iCurrModeNumb=Areas2Mode[iCurrAreaNumb];
            else
                //Нужно добавить новую область с нулевой модой
                iCurrModeNumb=0;
        }
        //Если это новая область
        if (iCurrAreaNumb<0)
        {
            //Добавление нового объекта в коллекцию
            iCurrAreaNumb=iAreasCount++;
            Areas2Mode[iCurrAreaNumb]=iCurrModeNumb;
        }
        //Установка номера области текущей точки
        AreasNumb[y][x] = iCurrAreaNumb;
        //Сканирование окрестных точек для выяснения граничащих областей
        iNumbCount=0;
        if ((x==0)||(iPrevAreaNumbL!=iCurrAreaNumb))
        {
            //Просмотр левой точки
            if ((x>0)&&(iCurrModeNumb==iPrevModeNumbL)&&(iCurrAreaNumb!=iPrevAreaNumbL))
                iNumb[iNumbCount++]=iPrevAreaNumbL;
            //Просмотр верхней левой точки
            if ((y>0)&&(x>0)&&(iCurrModeNumb==iPrevModeNumbUL)&&(iCurrAreaNumb!=iPrevAreaNumbUL))
                iNumb[iNumbCount++]=iPrevAreaNumbUL;
            //Просмотр верхней точки
            if ((y>0)&&(iCurrModeNumb==iPrevModeNumbU)&&(iCurrAreaNumb!=iPrevAreaNumbU))
                iNumb[iNumbCount++]=iPrevAreaNumbU;
        }
        //Сканирование верхней правой точки (в любом случае независимо от iPrevAreaNumb!!!)
        if ((y>0)&&(x<(Width-1))&&(iCurrModeNumb==iPrevModeNumbUR)&&(iCurrAreaNumb!=iPrevAreaNumbUR))
            iNumb[iNumbCount++]=iPrevAreaNumbUR;
        //Добавление найденных граничных областей
        for (i=0; i<iNumbCount; i++)
        {
            iTmp=iNumb[i];
            bool bFind=false;
            for (j=0; j<i; j++) if (iNumb[j]==iTmp) {
                bFind=true;
                break;
            }
            if (!bFind) {
                //Здесь области добавляются к списку соседних областей
            }
        }
        //Запоминание номера области и моды для левой точки
        iPrevAreaNumbL=iCurrAreaNumb;
        iPrevModeNumbL=iCurrModeNumb;
        //Запоминание номера области и моды для верхней левой точки
        iPrevAreaNumbUL=iPrevAreaNumbU;
        iPrevModeNumbUL=iPrevModeNumbU;
        //Запоминание номера области и моды для верхней точки
        iPrevAreaNumbU=iPrevAreaNumbUR;
        iPrevModeNumbU=iPrevModeNumbUR;
    }

    return iAreasCount;
}


Сообщение отредактировал Degun - Oct 26 2007, 12:11
Go to the top of the page
 
+Quote Post
fontp
сообщение Oct 26 2007, 12:40
Сообщение #8


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Неприятный какой алгоритм, сплошные условные операторы, а процессор этого толком и не умеет.

Везде где возможно избавляйтесь от if заменяя их по-возможности на MAX и MIN. Т.е. определяя границы циклов вне циклов по возможности. Да и в циклах минимизируя количество условных операций. Условные операции - смерть конвейера

А вообще-то у TI есть руководство по оптимизации кода на C. Как проектировать конвейеры на С
Там много полезных советов
Go to the top of the page
 
+Quote Post
Degun
сообщение Oct 30 2007, 20:12
Сообщение #9


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Как известно у TI C6000-го семейства 8 конвейеров. А вообще приведённый код функции будет выполняться на одном конвейере или на 8-ми. Т. е. будет ли компилятор загружать автоматически все конвейеры или только один и необходимо предпринимать специальные меры, чтобы загрузить остальные 7?
Go to the top of the page
 
+Quote Post
Edmundo
сообщение Oct 30 2007, 20:32
Сообщение #10


Мастер
****

Группа: Свой
Сообщений: 730
Регистрация: 18-02-06
Из: Москва
Пользователь №: 14 474



Цитата(Degun @ Oct 30 2007, 23:12) *
Как известно у TI C6000-го семейства 8 конвейеров. А вообще приведённый код функции будет выполняться на одном конвейере или на 8-ми. Т. е. будет ли компилятор загружать автоматически все конвейеры или только один и необходимо предпринимать специальные меры, чтобы загрузить остальные 7?

Куча ветвлений в виде if-ов -- не есть истинная обработка сигналов. А посему, не будет работа DSP воистину эффективна. Для этого можно и 8051 или ARM поставить. Не для этого рождены Обработчики Сигналов...


--------------------
شامل
Go to the top of the page
 
+Quote Post
Degun
сообщение Oct 31 2007, 06:29
Сообщение #11


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Цитата(Edmundo @ Oct 30 2007, 23:32) *
Куча ветвлений в виде if-ов -- не есть истинная обработка сигналов. А посему, не будет работа DSP воистину эффективна. Для этого можно и 8051 или ARM поставить. Не для этого рождены Обработчики Сигналов...

Если цифровую обработку сводить только к линейной фильтрации и линейным алгоритмам вообще, то такую обработку вообще с лёгкостью можно и в ПЛИС запихнуть. Но настоящая интеллектуальность алгоритмов начинает проявляться при их нелинейности, что предполагает широкое использование if-ов. Поэтому на DSP-процессоры хотелось бы возложить именно такие более сложные алгоритмы. Да и та функция, которую я привёл не настолько сложна, чтобы сильно загружать процессор: она целочисленна; в ней нет никаких математических вычислений. Я бы даже сказал так: если уж он эту функцию не может выполнять быстро, то вообще что же он тогда может.
Go to the top of the page
 
+Quote Post
fontp
сообщение Oct 31 2007, 08:42
Сообщение #12


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(Degun @ Oct 31 2007, 09:29) *
Если цифровую обработку сводить только к линейной фильтрации и линейным алгоритмам вообще, то такую обработку вообще с лёгкостью можно и в ПЛИС запихнуть. Но настоящая интеллектуальность алгоритмов начинает проявляться при их нелинейности, что предполагает широкое использование if-ов. Поэтому на DSP-процессоры хотелось бы возложить именно такие более сложные алгоритмы. Да и та функция, которую я привёл не настолько сложна, чтобы сильно загружать процессор: она целочисленна; в ней нет никаких математических вычислений. Я бы даже сказал так: если уж он эту функцию не может выполнять быстро, то вообще что же он тогда может.



Ну, он там может всякую фильтрацию, всякие преобразоввания, интерполяцию, экстраполяцию.
Если алгоритм состоит из одних if-ов то вам нужен процессор без конвейера.
Кроме того сигнальный или мультимедийный алгоритм часто можно перепроектировать (не переписать) так, что if-ов не останется, или почти не останется. Например, у DSP для нахождения экстремумов есть специальные ассемблерные инструкции и на них надо выходить или программируя на ассемблере, или с помощью интринсиков. Есть и другие хитроумные специализированые инструкции о которых стандартный С ничего не знает. Но есть интринсики ассемблерные библиотечные функции? котрые их пользуют.

Все современные DSP имеют хороший длинный конвейер и алгоритмы для них должны состоять из коротких циклов с не более одного if внутри, чтобы выполняться эффективно. А в более старых DSP не было этой напасти, зато в них было так мало регистров, что всё приходилось программировать на ассемблере, на С ничего не писалось

Понятно, что это трудно объяснить своему менеджеру, который купил Вам самый дорогой процессор (10 млрд. МИПС :-)) на все случаи жизни. Менеджер - это ведь тот человек, который понятия не имеет, где он находится, но совершенно точно знает, кто виноват :-)

По поводу Вашего предыдущего вопроса - сам он ничего не будет загружать. Компилятор будет делать попытки, но ... оптимизирующий компилятор должен узнать один из известных ему шаблонов, чтобы сгенерировать эффективный код. C FIR фильтром он разберётся лучше программиста, а так не очень...
Что ему программист скажет загрузить (с помощью ассемблера или интринсиков) - то он примерно и загрузит
Go to the top of the page
 
+Quote Post
Degun
сообщение Oct 31 2007, 19:50
Сообщение #13


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Цитата(fontp @ Oct 31 2007, 11:42) *
Ну, он там может всякую фильтрацию, всякие преобразоввания, интерполяцию, экстраполяцию.
Если алгоритм состоит из одних if-ов то вам нужен процессор без конвейера.

Конечно не из одних, но их достаточное кол-во. Типовые задачи цифровой обработки сигналов также присутствуют. Вообще с трудом представляю себе алгоритмы без if-ов. Например, сравнение одной переменной с другой и в зависимости от результата ветвление - это if. А уж без этого трудно представить большинство алгоритмов.
Цитата(fontp @ Oct 31 2007, 11:42) *
Понятно, что это трудно объяснить своему менеджеру, который купил Вам самый дорогой процессор (10 млрд. МИПС :-)) на все случаи жизни.

На самом деле производительность всего 4800 МИПС. Теоретически. Но чтобы их вытянуть у процессора на языке C\C++ нужно приложить массу усилий или перейти на ассемблер. Причём тип процессора был выбран вполне обосновано и претензий к этому у меня нет. Как показывает практика такой производительности процессора не хватает для обработки кадров с разрешением 768*576 с частотой 50 Гц по приведённому выше алгоритму, т. к. эта функция для указанного разрешения выполняется порядка 1 сек!
Цитата(fontp @ Oct 31 2007, 11:42) *
По поводу Вашего предыдущего вопроса - сам он ничего не будет загружать. Компилятор будет делать попытки, но ... оптимизирующий компилятор должен узнать один из известных ему шаблонов, чтобы сгенерировать эффективный код. C FIR фильтром он разберётся лучше программиста, а так не очень...
Что ему программист скажет загрузить (с помощью ассемблера или интринсиков) - то он примерно и загрузит

А есть ли документ где можно посмотреть типовые шаблоны алгоритмов?

Сообщение отредактировал Degun - Oct 31 2007, 19:52
Go to the top of the page
 
+Quote Post
fontp
сообщение Oct 31 2007, 20:20
Сообщение #14


Эксперт
*****

Группа: Свой
Сообщений: 1 467
Регистрация: 25-06-04
Пользователь №: 183



Цитата(Degun @ Oct 31 2007, 22:50) *
А есть ли документ где можно посмотреть типовые шаблоны алгоритмов?


SPRU187 - TMS320C6000 Optimizing Compiler User's Guide
SPRU198- TMS320C6000 Programmer's Guide
SPRU565-TMS320C64x DSP Library Programmer's Reference
SPRU023-TMS320C64x Image/Video Processing Library Programmer’s Reference
и т.д.

они все есть у Вас в 3-м композере
C:\CCStudio_v3.1\docs\pdf\manuals_ccs_full_c6000.html

В первой из книг рассказывается как поменять мозги и программировать в стиле шестьдесятого TMS
конвейеры. Это действительно в каком-то обобщённом смысле больше похоже на проектирование конвейеров ПЛИС , а не обычное последовательное программирование

Другие - описания библиотек. Есть же и исходники если интересно
Приёмчики, которыми пользуется оптимизатор, вряд ли где-то описаны. С опытом почувствуете

Между прочим pentium-мы на чисто логических задачах - тоже страшный тормоз, например на шахматных программах. И причины те же. Это всё процессоры заточеные под потоковые задачи

Короче, нужно или перепроектировать алгоритм (для вычислительных алгоритмов это возможно почти всегда), либо если задача типа перебора на дереве решений с нелинейными метриками - не рассчитывать на
быстродействие 500<мгц>х8<число конвейеров> мипс, а рассчитывать скорее на быстродействие

500мгц/ <глубина конвейера>. В вашем случае 50-100 мипс. Последний факт, понятно, аккуратно умалчивается не только в рекламных листовках, но и в документации на процессор. Харизма не та, чтобы прямо сказать: "Вот такие мы, Тексас (Аналог, Интел), мудАки" :-)
Go to the top of the page
 
+Quote Post
Degun
сообщение Nov 7 2007, 19:59
Сообщение #15


Частый гость
**

Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277



Цитата(fontp @ Oct 31 2007, 23:20) *
Короче, нужно или перепроектировать алгоритм (для вычислительных алгоритмов это возможно почти всегда), либо если задача типа перебора на дереве решений с нелинейными метриками - не рассчитывать на
быстродействие 500<мгц>х8<число конвейеров> мипс, а рассчитывать скорее на быстродействие

500мгц/ <глубина конвейера>. В вашем случае 50-100 мипс. Последний факт, понятно, аккуратно умалчивается не только в рекламных листовках, но и в документации на процессор. Харизма не та, чтобы прямо сказать: "Вот такие мы, Тексас (Аналог, Интел), мудАки" :-)

Что-то я запутался в конвейерах и в глубине конвейера для DM642. В документации по нему сказано, что у него 8 параллельно работающих устройств, выполняющих команды. Т. е. если повезёт, то за один такт может выполниться параллельно до 8-ми команд. Значит 8 - это количество конвейеров или это глубина всего одного конвейера?
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th June 2025 - 21:26
Рейтинг@Mail.ru


Страница сгенерированна за 0.01527 секунд с 7
ELECTRONIX ©2004-2016