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

 
 
> Лишние 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
 
Start new topic
Ответов
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
Edmundo
сообщение Oct 24 2007, 12:36
Сообщение #4


Мастер
****

Группа: Свой
Сообщений: 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
Сообщение #5


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

Группа: Новичок
Сообщений: 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
Сообщение #6


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

Группа: Новичок
Сообщений: 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
qxov
сообщение Nov 16 2007, 10:07
Сообщение #7


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

Группа: Свой
Сообщений: 86
Регистрация: 22-03-07
Из: Санкт-Петербург
Пользователь №: 26 406



Цитата(Degun @ Oct 26 2007, 16:06) *
Что можно сделать или оптимизировать в функции ниже в плане генерации оптимального кода для DSP-процессора?
Код
int SplitImage2Areas(unsigned char **Image, int **AreasNumb, int *Areas2Mode, int Width, int Height, int Thres1, int Thres2)
[поудалял // qxov]


Я хотел бы попытался подсказать, как можно улучшить этот код, но для этого желательно на словах объяснить, что он должен делать - код не прозрачен и практически не читается, к сожалению. Подскажите, если задача не потеряла актуальность.

Цитата(Edmundo @ Oct 24 2007, 16:36) *
Вы читали про ядро, про 8 "вычислителей", про кросс-пути и про параллельное выполнение?
И еще -- если поиграться оптимизацией -- можно получить неплохой код, не обязательно бросаться писать на АСМе. Ну да C vs. ASM -- это из другой оперы biggrin.gif

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

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

У этого семейства 8 юнитов, по 2 каждого типа: .L, .S, .D, .M.
В частности, в SPRU732C Appendix B есть таблица "Mapping Between Instruction and Functional Unit".
Например, в .M юнитах выполняются, в основном, умножения, в .L - логические операции и т.д. То есть, нельзя загрузить все юниты, если не используются соответствующие инструкции. Компилятор очень хорошо оптимизирует код, но только в том случае, если ему предоставить такую возможность - дать знать, сколько раз (обычно) выполняются циклы, вытащить из циклов вызовы функций и т.д. Большое количество разных if - смерть для оптимизатора.
Стоит заметить, что у этих процессоров все инструкции являются условными, что можно грамотно применить при написании кода, получив ускорение даже в несколько раз, по сравнению с написанием "в лоб", при этом не приходится даже серьезно модифицировать алгоритм.
Go to the top of the page
 
+Quote Post
Degun
сообщение Nov 16 2007, 13:08
Сообщение #8


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

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



Цитата(qxov @ Nov 16 2007, 13:07) *
Я хотел бы попытался подсказать, как можно улучшить этот код, но для этого желательно на словах объяснить, что он должен делать - код не прозрачен и практически не читается, к сожалению. Подскажите, если задача не потеряла актуальность.

Задача состоит в следующем: на вход функции поступает полутоновое (серое) 8-ми битовое изображение Image размерами Height и Width. Типичный пример изображения - звёзды на фоне космического пространства. Необходимо разбить изображение на непересекающиеся пронумерованные области в соответствии с двуми порогами: Thr1 - порог фона (нижний порог); Thr2 - порог объектов (верхний порог). Те пикселы, которые находятся между порогами Thr1 и Thr2 (т. е. Thr1 < PixelValue < Thr2) являются переходными и могут быть отнесены к любой ближайшей наиболее близкой (с точки зрения близости значений пикселов) области. На выходе функции в массиве AreasNumbBuf для каждого пиксела сохраняется номер области, к которой принадлежит этот пиксель (это может быть или космическое пространство или звезда или НЛОsmile.gif).
Алгоритм с последней публикации был достаточно сильно изменён, поэтому привожу его заново. Но несмотря на значительную оптимизацию его быстродействие на процессоре DM642 оставляет желать лучшего. Например для изображения размерами 640*480 он выполняется порядка 0.6 сек, что неприемлемо. Планировалось, что он должен выполняться порядка 20 мсек (50 Гц).
Код
#include <stdlib.h>

//Максимальное кол-во областей в изображении
#define MAX_AREAS 1000
#define min(x,y) (x<y?x:y)

//Структура хранения информации об областях
typedef struct TAreaInfo
{
    //Номер кластера
    short iNumber;
    //Номер моды
    short iMode;
    //Счётчик мощности моды
    int iCount;
} TAreaInfo;

//Счётчики количества областей в изображении и в контейнере
static int iAreasCount=0, iAreasInfoCount=0;

//Ограниченный массив структур описателей областей!!!
static TAreaInfo AreasInfo[MAX_AREAS+1];

//Таблица соответствия значений пикселов модам гистограммы
static int ModeNumb4Pix[256];

//Функция создания новой области
static inline int AddNewAreaInfo(const int iModeNumb)
{
//    if (iAreasInfoCount>=MAX_AREAS) return -1;
    iAreasCount++;
    AreasInfo[iAreasInfoCount].iMode=iModeNumb;
    AreasInfo[iAreasInfoCount].iNumber=-1;
    AreasInfo[iAreasInfoCount].iCount=0;
    return iAreasInfoCount++;
}

/*!\brief Разбиение изображения на непересекающиеся области
* \param Image - исходное изображение
* \param Height - высота изображения
* \param Width - ширина изображение
* \param AreasNumbBuf - буфер результата, отражающий номера областей каждого из пикселов
* \param Thr1 - нижний порог
* \param Thr2 - верхний порог
* \result Количество непересекающихся областей в изображении
*/
int SplitImage2Areas(
    register unsigned char ** __restrict Image,
    register int Height, register int Width,
    register int ** __restrict AreasNumbBuf,
    register int Thr1, register int Thr2)
{
    //Изображение последовательно просматривается по строкам
    //для отнесения каждого пиксела к определённой области
    //Вычисление площади, занимаемой каждой областью и модой
    register int iPrevAreaNumbL=-1;  //Номер области предыдущей левой точки
    register int iPrevModeNumbL=-1;  //Номер моды предыдущей левой точки
    register int iPrevAreaNumbU=-1;  //Номер области предыдущей верхней точки
    register int iPrevModeNumbU=-1;  //Номер моды предыдущей верхней точки
    register int iPrevAreaNumbUL=-1; //Номер области предыдущей верхней левой точки
    register int iPrevModeNumbUL=-1; //Номер моды предыдущей верхней левой точки
    register int iPrevAreaNumbUR=-1; //Номер области предыдущей верхней правой точки
    register int iPrevModeNumbUR=-1; //Номер моды предыдущей верхней правой точки
    //Временные переменные
    register int i, y, x, iSrcIndex, iDstIndex, iDelta, iTmp;
    register int iCurrPixel, iCurrAreaNumb, iCurrModeNumb;
    register TAreaInfo * __restrict pSrcObj, * __restrict pDstObj, * __restrict pTmpObj;

    //Проверка корректности входных параметров
    if ((Image==0)||(Width<=0)||(Height<=0)||(ModeNumb4Pix==0)||(AreasNumbBuf==0)) return -1;
    //Формирование таблицы мод пикселей
    for (i=0; i<256; i++)
    {
        if (i<Thr1)
            ModeNumb4Pix[i]=0;
        else if (i>=Thr2)
            ModeNumb4Pix[i]=1;
        else
            ModeNumb4Pix[i]=-1;
    }
    //Обнуление счётчиков кол-ва областей
    iAreasCount=iAreasInfoCount=0;
    //Обработка верхней левой точки изображения
    iCurrPixel=Image[0][0];
    iCurrModeNumb=ModeNumb4Pix[iCurrPixel];
    if (iCurrModeNumb<0)
    {
        //Сканирование зигзагом окрестных точек для
        //выявления ближайшей с установленной модой
        iDelta=min(Width,Height);
        for (i=1; i<iDelta; i++)
        {
            iSrcIndex=-1;
            for (y=i, x=0; y>=0; y--, x++)
            {
                iDstIndex=Image[y][x];
                iTmp=ModeNumb4Pix[iDstIndex];
                if (iTmp<0) continue;
                iDstIndex=abs(iDstIndex-iCurrPixel);
                if ((iSrcIndex<0)||(iSrcIndex>iDstIndex))
                {
                    iSrcIndex=iDstIndex;
                    iCurrModeNumb=iTmp;
                }
            }
            //Нашли подходящую точку - выход из поиска
            if (iCurrModeNumb>=0) break;
        }
        //Если точек нет, то нулевая мода
        if (iCurrModeNumb<0) iCurrModeNumb=0;
    }
    iCurrAreaNumb=AddNewAreaInfo(iCurrModeNumb);
    AreasNumbBuf[0][0]=iCurrAreaNumb;
    //Обработка первой верхней строки изображения,
    //начиная со второго пиксела строки
    for (x=1; x<Width; x++)
    {
        //Запоминание номера области и моды для левой точки
        iPrevAreaNumbL=iCurrAreaNumb;
        iPrevModeNumbL=iCurrModeNumb;
        //Номер моды текущей точки
        iCurrModeNumb=ModeNumb4Pix[Image[0][x]];
        //В зависимости от наличия моды
        if (iCurrModeNumb<0) {
            iCurrModeNumb=iPrevModeNumbL;
            iCurrAreaNumb=iPrevAreaNumbL;
        }
        else if (iCurrModeNumb==iPrevModeNumbL) {
            iCurrAreaNumb=iPrevAreaNumbL;
        }
        else {
            //Добавление новой области
            iCurrAreaNumb=AddNewAreaInfo(iCurrModeNumb);
        }
        //Установка номера области текущей точки
        AreasNumbBuf[0][x] = iCurrAreaNumb;
        //Инкремент счётчика площади, занимаемой областью
        AreasInfo[iCurrAreaNumb].iCount++;
    }
    //Декремент ширины изображения для увеличения скорости обработки
    Width--;
    //Цикл по всем точкам изображения
    for (y=1; y<Height; y++)
    {
        //Установка начального значения для верхней левой точки
        iPrevAreaNumbUL=AreasNumbBuf[y-1][0];
        iPrevModeNumbUL=AreasInfo[iPrevAreaNumbUL].iMode;
        //Установка начального значения для верхней точки
        iPrevAreaNumbU=AreasNumbBuf[y-1][1];
        iPrevModeNumbU=AreasInfo[iPrevAreaNumbU].iMode;
        //Значение яркости первого пикселя строки
        iCurrPixel=Image[y][0];
        //Значение моды первого пикселя строки
        iPrevModeNumbL=ModeNumb4Pix[iCurrPixel];
        //В зависимости от признака переходности пиксела
        if (iPrevModeNumbL<0) {
            if (abs(iCurrPixel-Image[y-1][0])<abs(iCurrPixel-Image[y-1][1]))
            {
                iPrevModeNumbL=iPrevModeNumbUL;
                iPrevAreaNumbL=iPrevAreaNumbUL;
            }
            else
            {
                iPrevModeNumbL=iPrevModeNumbU;
                iPrevAreaNumbL=iPrevAreaNumbU;
            }
        }
        else if (iPrevModeNumbL==iPrevModeNumbUL)
            iPrevAreaNumbL=iPrevAreaNumbUL; //Верхняя левая точка
        else if (iPrevModeNumbL==iPrevModeNumbU)
            iPrevAreaNumbL=iPrevAreaNumbU;  //Верхняя точка
        else {
            //Добавление новой области
            iPrevAreaNumbL=AddNewAreaInfo(iPrevModeNumbL);
        }
        //Установка номера области первого пиксела строки
        AreasNumbBuf[y][0] = iPrevAreaNumbL;
        //Инкремент счётчика площади, занимаемой областью
        AreasInfo[iPrevAreaNumbL].iCount++;
        //Обработка очередной строки изображения
        for (x=1; x<Width; x++)
        {
            //Определение параметров верхней правой точки
            iPrevAreaNumbUR=AreasNumbBuf[y-1][x+1];
            iPrevModeNumbUR=AreasInfo[iPrevAreaNumbUR].iMode;
            //Значение яркости текущего пикселя
            iCurrPixel=Image[y][x];
            //Номер моды текущей точки
            iCurrModeNumb=ModeNumb4Pix[iCurrPixel];
            //В зависимости от того является ли точка переходной
            if (iCurrModeNumb<0)
            {
                //Текущая точка является переходной к любой области
                //Перебор всех точек окрестности и выбор наиболее близкой области
                //Левая точка
                iDelta=abs(Image[y][x-1]-iCurrPixel);
                iCurrAreaNumb=iPrevAreaNumbL;
                iCurrModeNumb=iPrevModeNumbL;
                //Верхняя точка
                iTmp=abs(Image[y-1][x]-iCurrPixel);
                if (iDelta>iTmp) {
                    iDelta=iTmp;
                    iCurrAreaNumb=iPrevAreaNumbU;
                    iCurrModeNumb=iPrevModeNumbU;
                }
                //Верхняя левая точка
                iTmp=abs(Image[y-1][x-1]-iCurrPixel);
                if (iDelta>iTmp) {
                    iDelta=iTmp;
                    iCurrAreaNumb=iPrevAreaNumbUL;
                    iCurrModeNumb=iPrevModeNumbUL;
                }
                //Верхняя правая точка
                iTmp=abs(Image[y-1][x+1]-iCurrPixel);
                if (iDelta>iTmp) {
                    iDelta=iTmp;
                    iCurrAreaNumb=iPrevAreaNumbUR;
                    iCurrModeNumb=iPrevModeNumbUR;
                }
            }
            //Эта точка не является переходной ни к одной из мод
            //Просмотр всех соседних уже размеченных ранее точек
            //для возможного определения номера области текущей точки
            else if (iCurrModeNumb==iPrevModeNumbL)
                    iCurrAreaNumb=iPrevAreaNumbL;  //Левая точка
            else if (iCurrModeNumb==iPrevModeNumbUL)
                    iCurrAreaNumb=iPrevAreaNumbUL; //Верхняя левая точка
            else if (iCurrModeNumb==iPrevModeNumbU)
                    iCurrAreaNumb=iPrevAreaNumbU;  //Верхняя точка
            else if (iCurrModeNumb==iPrevModeNumbUR)
                    iCurrAreaNumb=iPrevAreaNumbUR; //Верхняя правая точка
            else {
                //Добавление новой области
                iCurrAreaNumb=AddNewAreaInfo(iCurrModeNumb);
            }
            //Установка номера области текущей точки
            AreasNumbBuf[y][x] = iCurrAreaNumb;
            //Объект области в дереве
            pSrcObj=&AreasInfo[iCurrAreaNumb];
            //Инкремент счётчика площади, занимаемой областью
            pSrcObj->iCount++;
            //Сканирование верхней правой точки для добавления её в список соседних областей
            if ((iCurrModeNumb==iPrevModeNumbUR)&&(iCurrAreaNumb!=iPrevAreaNumbUR))
            {
                //Объект области предыдущей ссылки
                pDstObj=&AreasInfo[iPrevAreaNumbUR];
                //Всего четыре возможных варианта
                if (pSrcObj->iNumber<0)
                {
                    if (pDstObj->iNumber>=0)
                    {
                        //Только добавляется ссылка на ссылочную область
                        pSrcObj->iNumber=pDstObj->iNumber;
                        //Декремент кол-ва областей
                        iAreasCount--;
                    }
                    else
                    {
                        //Обе области являются доменными
                        iTmp=min(iCurrAreaNumb,iPrevAreaNumbUR);
                        pSrcObj->iNumber=iTmp;
                        pDstObj->iNumber=iTmp;
                        //Декремент кол-ва областей
                        iAreasCount--;
                    }
                }
                else //if (pSrcObj->iNumber>=0)
                {
                    if (pDstObj->iNumber<0)
                    {
                        //Только добавляется ссылка на ссылочную область
                        pDstObj->iNumber=pSrcObj->iNumber;
                        //Декремент кол-ва областей
                        iAreasCount--;
                    }
                    else
                    {
                        iSrcIndex=pSrcObj->iNumber;
                        iDstIndex=pDstObj->iNumber;
                        if (iSrcIndex!=iDstIndex)
                        {
                            //Это самый трудоёмкий случай.
                            //Но, к счастью, самый редкий!
                            //Необходимо объединить две области
                            for (i=0; i<iAreasInfoCount; i++)
                            {
                                pTmpObj=&AreasInfo[i];
                                if (pTmpObj->iNumber==iSrcIndex)
                                    pTmpObj->iNumber=iDstIndex;
                            }
                            //Декремент кол-ва областей
                            iAreasCount--;
                        }
                    }
                }
            }
            //Запоминание номера области и моды для левой точки
            iPrevAreaNumbL=iCurrAreaNumb;
            iPrevModeNumbL=iCurrModeNumb;
            //Запоминание номера области и моды для верхней левой точки
            iPrevAreaNumbUL=iPrevAreaNumbU;
            iPrevModeNumbUL=iPrevModeNumbU;
            //Запоминание номера области и моды для верхней точки
            iPrevAreaNumbU=iPrevAreaNumbUR;
            iPrevModeNumbU=iPrevModeNumbUR;
        }
        //Значение яркости последнего пикселя строки
        iCurrPixel=Image[y][Width];
        //Значение моды последнего пикселя строки
        iCurrModeNumb=ModeNumb4Pix[iCurrPixel];
        //В зависимости от наличия моды
        if (iCurrModeNumb<0) {
            //Левая точка
            iDelta=abs(Image[y][x-1]-iCurrPixel);
            iCurrAreaNumb=iPrevAreaNumbL;
            iCurrModeNumb=iPrevModeNumbL;
            //Верхняя левая точка
            iTmp=abs(Image[y-1][x-1]-iCurrPixel);
            if (iDelta>iTmp) {
                iDelta=iTmp;
                iCurrAreaNumb=iPrevAreaNumbUL;
                iCurrModeNumb=iPrevModeNumbUL;
            }
            //Верхняя точка
            iTmp=abs(Image[y-1][x]-iCurrPixel);
            if (iDelta>iTmp) {
                iDelta=iTmp;
                iCurrAreaNumb=iPrevAreaNumbU;
                iCurrModeNumb=iPrevModeNumbU;
            }
        }
        else if (iCurrModeNumb==iPrevModeNumbL)
            iCurrAreaNumb=iPrevAreaNumbL;  //Левая точка
        else if (iCurrModeNumb==iPrevModeNumbUL)
            iCurrAreaNumb=iPrevAreaNumbUL; //Верхняя левая точка
        else if (iCurrModeNumb==iPrevModeNumbU)
            iCurrAreaNumb=iPrevAreaNumbU;  //Верхняя правая точка
        else {
            //Добавление новой области
            iCurrAreaNumb=AddNewAreaInfo(iCurrModeNumb);
        }
        //Установка номера области последнего пикселя строки
        AreasNumbBuf[y][Width] = iCurrAreaNumb;
        //Инкремент счётчика площади, занимаемой областью
        AreasInfo[iCurrAreaNumb].iCount++;
    }
    //Восстановление исходной ширины изображения
    Width++;

    //Упорядочивание переадресации областей (именно здесь)!!!!!
    for (i=0; i<iAreasInfoCount; i++)
    {
        pTmpObj=&AreasInfo[i];
        iTmp=pTmpObj->iNumber;
        if (iTmp<0)
        {
            //Это независимый кластер
            pTmpObj->iNumber=i;
        }
        else if (iTmp!=i)
        {
            //Это не кластерная область
            AreasInfo[iTmp].iCount+=pTmpObj->iCount;
            //Обнуление счётчика - выключение области
            pTmpObj->iCount=0;
        }
    }

    //Могут оставаться независимые области с индексами больше iAreasCount
    for (iDstIndex=0, iSrcIndex=iAreasCount; iSrcIndex<iAreasInfoCount; iSrcIndex++)
    {
        //Если эта область уже переадресована - все нормально
        pSrcObj=&AreasInfo[iSrcIndex];
        if ((pSrcObj==NULL)||(pSrcObj->iCount==0)) continue;
        //Поиск индекса для переадресации
        for (; iDstIndex<iAreasCount; iDstIndex++)
        {
            pDstObj=&AreasInfo[iDstIndex];
            if ((pDstObj!=NULL)&&(pDstObj->iCount==0)) break;
        }
        //Сохранение указателя на моду
        pDstObj->iMode=pSrcObj->iMode;
        //Коррекция счётчиков мощности областей
        pDstObj->iCount=pSrcObj->iCount;
        pSrcObj->iCount=0;
        //Установка ссылки данной области на переадресованную
        pSrcObj->iNumber=iDstIndex;
        //Замена всех ссылок на эту область!!!!!!!!
        for (i=0; i<iAreasInfoCount; i++)
        {
            pTmpObj=&AreasInfo[i];
            if (pTmpObj->iNumber==iSrcIndex) pTmpObj->iNumber=iDstIndex;
        }
    }

    //Переписывание индексов областей на новые переназначенные
    for (y=0; y<Height; y++) for (x=0; x<Width; x++)
    {
        iTmp=AreasNumbBuf[y][x];
        iTmp=AreasInfo[iTmp].iNumber;
        AreasNumbBuf[y][x]=iTmp;
    }

    return iAreasCount;
}
Go to the top of the page
 
+Quote Post
qxov
сообщение Nov 18 2007, 13:15
Сообщение #9


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

Группа: Свой
Сообщений: 86
Регистрация: 22-03-07
Из: Санкт-Петербург
Пользователь №: 26 406



Цитата(Degun @ Nov 16 2007, 16:08) *
Алгоритм с последней публикации был достаточно сильно изменён, поэтому привожу его заново. Но несмотря на значительную оптимизацию его быстродействие на процессоре DM642 оставляет желать лучшего. Например для изображения размерами 640*480 он выполняется порядка 0.6 сек, что неприемлемо. Планировалось, что он должен выполняться порядка 20 мсек (50 Гц).

А вот возникает еще вопрос: 640*480*2 байт памяти для 640x480, как минимум, используется, что равно 600Кб. Если верить ti, то самое бодрое, что есть - TMS320DM642-720 c 256 KB внутренней памяти. Это получается, что во внешней памяти данные хранятся или я не понимаю всего?
Далее, 720e6/640/480/50 = 46.875. То есть, для 640x480x50 раз/сек есть, в лучшем случае, 46 тактов. Реально - еще меньше. Однозначно, работать нужно из внутренней памяти, причем не просто из внутренней памяти, а еще и так, чтобы данные укладывались в кэш первого уровня, иначе, грубо говоря, время выполнения увеличится чуть ли не в два раза.
Таким образом необходимо:
1. Создать во внутреней памяти буфера для хранения трех строк:
1.1. Текущая строка
1.2. Предыдущая строка.
1.3. Следующая строка.
2. Настроить канал ДМА, чтобы во время обработки буферов (1.2.) и (1.1.) копировались данные из внешней памяти в (1.3.).
3. Дожидаемся окончания работы ДМА, свопим буфера и запускаем снова канал ДМА, а сами тем временем обрабатываем предыдущие строки.

И, думаю, если копнуть глубже, то окажется, что времени не 1/50 секунды есть, а 1/25, не так ли? Реально частота кадров какая?

Здесь надо менять очень серьезно все. А уже потом - оптимизировать код, там тоже есть, где разгуляться.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- Degun   Лишние NOP в ассемблерном коде   Oct 23 2007, 11:54
|- - fontp   Цитата(Degun @ Oct 23 2007, 16:15) А разв...   Oct 23 2007, 12:28
|- - fontp   Неприятный какой алгоритм, сплошные условные опера...   Oct 26 2007, 12:40
||- - Degun   Как известно у TI C6000-го семейства 8 конвейеров....   Oct 30 2007, 20:12
||- - Edmundo   Цитата(Degun @ Oct 30 2007, 23:12) Как из...   Oct 30 2007, 20:32
||- - Degun   Цитата(Edmundo @ Oct 30 2007, 23:32) Куча...   Oct 31 2007, 06:29
||- - fontp   Цитата(Degun @ Oct 31 2007, 09:29) Если ц...   Oct 31 2007, 08:42
||- - Degun   Цитата(fontp @ Oct 31 2007, 11:42) Ну, он...   Oct 31 2007, 19:50
||- - fontp   Цитата(Degun @ Oct 31 2007, 22:50) А есть...   Oct 31 2007, 20:20
||- - Degun   Цитата(fontp @ Oct 31 2007, 23:20) Короче...   Nov 7 2007, 19:59
||- - fontp   Цитата(Degun @ Nov 7 2007, 22:59) Что-то ...   Nov 8 2007, 07:33
||- - vadkudr   Цитата(Degun @ Nov 8 2007, 04:59) Что-то ...   Nov 20 2007, 13:33
||- - SIA   Цитата(Degun @ Nov 7 2007, 22:59) Что-то ...   Mar 17 2008, 17:09
|- - qxov   Цитата(Degun @ Nov 16 2007, 16:08) Задача...   Nov 16 2007, 21:53
||- - Degun   Цитата(qxov @ Nov 17 2007, 00:53) Вот пло...   Nov 17 2007, 10:54
|- - qxov   Как успехи? Вот, набросал на коленке кусочек. Може...   Nov 19 2007, 20:42
|- - Degun   Цитата(qxov @ Nov 17 2007, 00:53) Вот так...   Nov 20 2007, 17:38
- - mdmitry   Возможно оффтор! В MATLAB ImageProcessing Tool...   Nov 18 2007, 11:09
- - Degun   Уважаемый qxov я сделал вашу функцию calcModes с п...   Nov 22 2007, 14:13
|- - qxov   Цитата(Degun @ Nov 22 2007, 17:13) Уважае...   Nov 22 2007, 14:49
- - qxov   А можно ли считать, что за пределами кадра есть ра...   Nov 22 2007, 20:00
|- - Degun   Цитата(qxov @ Nov 22 2007, 23:00) А можно...   Nov 23 2007, 11:58
|- - qxov   Цитата(Degun @ Nov 23 2007, 14:58) Да впо...   Nov 23 2007, 12:50
|- - Degun   Цитата(qxov @ Nov 23 2007, 15:50) Точно 7...   Nov 25 2007, 17:44
|- - qxov   Цитата(Degun @ Nov 25 2007, 20:44) Точно ...   Nov 26 2007, 07:41
|- - Degun   Цитата(qxov @ Nov 26 2007, 10:41) Я в DSP...   Nov 26 2007, 12:19
- - qxov   Не знаю, на сколько этот вариант подходит: если m...   Nov 26 2007, 19:07
|- - Degun   Цитата(qxov @ Nov 26 2007, 22:07) Не знаю...   Nov 27 2007, 12:26
|- - qxov   Цитата(Degun @ Nov 27 2007, 15:26) Вообще...   Nov 28 2007, 06:07
|- - Degun   Цитата(qxov @ Nov 28 2007, 09:07) Начинат...   Dec 6 2007, 17:40
|- - qxov   Цитата(Degun @ Dec 6 2007, 20:40) Такие с...   Dec 7 2007, 06:20
|- - Degun   Вот такой у меня получился код для DSP. Но для изо...   Feb 1 2008, 12:43
- - Николай Z   Цитата(Degun @ Oct 23 2007, 14:54) Code C...   Dec 6 2007, 23:23
- - qxov   Очень тяжелый вложенный цикл. Нужно рассмотреть во...   Feb 13 2008, 10:16
|- - Degun   Цитата(qxov @ Feb 13 2008, 13:16) Очень т...   Feb 19 2008, 12:55
- - Degun   Следующий вариант выполняется на 1 мсек быстрее, ч...   Mar 17 2008, 13:29


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

 


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


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