|
Лишние NOP в ассемблерном коде |
|
|
|
Nov 25 2007, 17:44
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Цитата(qxov @ Nov 23 2007, 15:50)  Точно 7.9 мсек? Просто 7.9 мсек на 500МГц - 3950000 циклов, что многовато для обработки 640*480=307200 пикселов изображения - более 128 циклов на пиксел, а расчетное - около 0.25 с хвостиком должно выходить. Ну пусть в два раза ошиблись, но не на столько же... Оптимизация-то включена?  Точно 7.9 мсек. Может быть где-то в настройках DSP-BIOS стоит опция размещать статические буфера не в IRAM, а в во внешней SDRAM. Возможно именно из-за этого такое большое время выполнения.
|
|
|
|
|
Nov 26 2007, 07:41
|

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

|
Цитата(Degun @ Nov 25 2007, 20:44)  Точно 7.9 мсек. Может быть где-то в настройках DSP-BIOS стоит опция размещать статические буфера не в IRAM, а в во внешней SDRAM. Возможно именно из-за этого такое большое время выполнения. Я в DSP-BIOS не верю  Не могу ничего сказать по этому поводу - не приходилось сколько-нибудь значимых с ним дел иметь.
|
|
|
|
|
Nov 26 2007, 12:19
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Цитата(qxov @ Nov 26 2007, 10:41)  Я в DSP-BIOS не верю  Не могу ничего сказать по этому поводу - не приходилось сколько-нибудь значимых с ним дел иметь. Точно в DSP-BIOS было дело. Изменил настройки и тот вариант с DMA, который я приводил выше, стал выполняться за 0.967 мсек
|
|
|
|
|
Nov 27 2007, 12:26
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Цитата(qxov @ Nov 26 2007, 22:07)  Не знаю, на сколько этот вариант подходит:
если min(abs(дельта яркости окрестных точек))>(thresoldHi-thresoldLo), то новая область; иначе - точка относится к области, соответствующей одной из min(abs(дельта яркости окрестных точек)) Вообще-то интересный вариант. Не понятно только как начинать разметку изображения, когда ещё никаких областей нет? А чем вообще обусловлен вопрос - этот вариант проще?
|
|
|
|
|
Nov 28 2007, 06:07
|

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

|
Цитата(Degun @ Nov 27 2007, 15:26)  Вообще-то интересный вариант. Не понятно только как начинать разметку изображения, когда ещё никаких областей нет? А чем вообще обусловлен вопрос - этот вариант проще? Начинать просто - первому пикселу задаем какой-то номер области и от этого пляшем. Вариант значительно проще - в том алгоритме, который используется сейчас, это так или иначе все равно делается, но помимо этих расчетов еще куча других присутствует. Если данная схема позволит полчить удовлетворительные результаты, то, наверное, лучше копать в этом направлении. Разумеется, потом все равно придется как-то перенумеровывать области точек. Хотя, если предположить, что исходная картинка такова, что при сканировании ее по строкам и задания областей не может возникнуть случая, подобного Код ..11..22.. ...11.2... ....11.... либо допускается, что области, содержащие точки, скорее относящиеся к одинаковым модам, соприкасаются, не объединяясь при этом в одну, то алгоритм можно упростить до безумия
|
|
|
|
|
Dec 6 2007, 17:40
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Цитата(qxov @ Nov 28 2007, 09:07)  Начинать просто - первому пикселу задаем какой-то номер области и от этого пляшем. Вариант значительно проще - в том алгоритме, который используется сейчас, это так или иначе все равно делается, но помимо этих расчетов еще куча других присутствует. Если данная схема позволит полчить удовлетворительные результаты, то, наверное, лучше копать в этом направлении. Разумеется, потом все равно придется как-то перенумеровывать области точек. Хотя, если предположить, что исходная картинка такова, что при сканировании ее по строкам и задания областей не может возникнуть случая, подобного Код ..11..22.. ...11.2... ....11.... Такие случаи, к сожалению, встречаются и довольно часто. Так, что без перенумеровывания, по-видимому, не обойтись. Цитата(qxov @ Nov 28 2007, 09:07)  либо допускается, что области, содержащие точки, скорее относящиеся к одинаковым модам, соприкасаются, не объединяясь при этом в одну, то алгоритм можно упростить до безумия  Так тоже не честно. В этом суть алгоритма разметки на области.
|
|
|
|
|
Dec 6 2007, 23:23
|
Местный
  
Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930

|
Цитата(Degun @ Oct 23 2007, 14:54)  Code Composer Studio v 3.3; Процессор DM642 на evalution board. Имеется программка, написанная на C++. После анализа её ассемблерного кода выяснилось, что после многих команд (LDW, ADD, CMPLT, AND, LDHU и др.) компилятор вставляет команду NOP, что естественно замедляет функционирование программы. Для чего это? Можно ли отключить вставку операторов NOP в ассемблерный код? Прочтите доку на процессор и Вам станет понятно назначение NOP-ов, которые Вам в код всовывает компилятор... Я не знаю Вашего процессора, но это достаточно стандартный прием во многих микроконтроллерах, которые работают по принципу конвейера... Делается - чаще всего для того, чтобы дать возможность процессору закончить записб результата на регистры управления или в регистры/ячейки внешней памяти... Т.к. иначе - возможно использование "старого" значения в следующей команде... Вышесказанное - это лишь возможные причины - настоящие - в документации на Ваш микроконтроллер... Попытки убрать такие NOP-ы могут привести к сбоям, а могут и остаться безнаказанными - все зависит от операндов следующих за NOP-ами команд... В любом случае - прежде чем убирать такие NOP-ы - надо как следует подумать... Если компилятор "умный" - то он сам анализирует - надо вставлять NOP-ы или нет... Если глупый - он вставляет их "не думая" в критических местах так - как это решил нужным сделать разработчик компилятора и возможно - часть их лишние... Общая рекомендация - лучше их не убирать... Не так уж много времени они обчно забирают
Сообщение отредактировал Николай Z - Dec 6 2007, 23:26
|
|
|
|
|
Dec 7 2007, 06:20
|

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

|
Цитата(Degun @ Dec 6 2007, 20:40)  Такие случаи, к сожалению, встречаются и довольно часто. Так, что без перенумеровывания, по-видимому, не обойтись.
Так тоже не честно. В этом суть алгоритма разметки на области. Я уже потом подумал, что, наверное, схема с разметкой по превышению порога изменения яркости будет работать плохо - нужна высокая контрастность соседних точек, иначе все одной областью заполнится тупо.
|
|
|
|
|
Feb 1 2008, 12:43
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Вот такой у меня получился код для DSP. Но для изображения размером 640*480 пикселей он выполняется за 85 мсек, что много. Что здесь можно ещё оптимизировать? Код #include <stdlib.h> #include <string.h> #include <csl_dat.h>
//Максимальное кол-во областей в изображении #define MAX_AREAS 1000 //Максимальная ширина изображения #define IMG_WIDTH_MAX 640 //Максимальная высота изображения #define IMG_HEIGHT_MAX 480 //Макросы минимума и максимума #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b))
//Счётчики количества областей в изображении и в контейнере static int iAreasCount=0, iAreasInfoCount=0;
//Ограниченные массивы структур описателей областей!!! static short AreasMode[MAX_AREAS+1]; static short AreasNumber[MAX_AREAS+1];
//Функция создания новой области static inline int AddNewAreaInfo(const int iModeNumb) { // if (iAreasInfoCount>=MAX_AREAS) return -1; iAreasCount++; AreasMode[iAreasInfoCount]=iModeNumb; AreasNumber[iAreasInfoCount]=-1; return iAreasInfoCount++; }
// Буферы для кэширования строк изображения static unsigned char ImageBuf[3][IMG_WIDTH_MAX]; static int AreasBuf[2][IMG_WIDTH_MAX];
int test_SplitImage2Areas( register unsigned char ** restrict Image, register int Height, register int Width, register short * restrict ModeNumb4Pix, register int ** restrict Areas) { //Изображение последовательно просматривается по строкам //для отнесения каждого пиксела к определённой области //Вычисление площади, занимаемой каждой областью и модой 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 Uint32 id_LoadTransfer, id_SaveTransfer; register int iImageBufIndex, iAreasBufIndex; register unsigned char * restrict pImageCurrBuf; register unsigned char * restrict pImagePrevBuf; register int * restrict pAreasCurrBuf; register int * restrict pAreasPrevBuf;
//Проверка корректности входных параметров if ((Image==0)||(ModeNumb4Pix==0)||(Areas==0)) return -1; if ((Width<=0)||(Height<=0)||(Width>IMG_WIDTH_MAX)||(Height>IMG_HEIGHT_MAX)) return -1;
//Загрузка первой строки изображения id_LoadTransfer=DAT_copy(Image[0], ImageBuf[0], Width);
//Обнуление счётчиков кол-ва областей 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); AreasBuf[0][0]=iCurrAreaNumb; //Указатель на текущую обрабатываемую строку изображения pImageCurrBuf=ImageBuf[0]; //Указатель на текущую результирующую строку номеров областей pAreasCurrBuf=AreasBuf[0]; //Ожидание окончания загрузки первой строки изображения while(DAT_busy(id_LoadTransfer)); //Запуск загрузки второй строки изображения id_LoadTransfer=DAT_copy(Image[1], ImageBuf[1], Width); //Обработка первой верхней строки изображения, //начиная со второго пиксела строки for (x=1; x<Width; x++) { //Запоминание номера области и моды для левой точки iPrevAreaNumbL=iCurrAreaNumb; iPrevModeNumbL=iCurrModeNumb; //Номер моды текущей точки iCurrModeNumb=ModeNumb4Pix[pImageCurrBuf[x]]; //В зависимости от наличия моды if (iCurrModeNumb<0) { iCurrModeNumb=iPrevModeNumbL; iCurrAreaNumb=iPrevAreaNumbL; } else if (iCurrModeNumb==iPrevModeNumbL) { iCurrAreaNumb=iPrevAreaNumbL; } else { //Добавление новой области iCurrAreaNumb=AddNewAreaInfo(iCurrModeNumb); } //Установка номера области текущей точки pAreasCurrBuf[x]=iCurrAreaNumb; } //Сохранение первой строки результата id_SaveTransfer=DAT_copy(AreasBuf[0], Areas[0], Width); //установка кольцевого указателя на буфер текущей строки iImageBufIndex=iAreasBufIndex=1; //Декремент ширины изображения для увеличения скорости обработки Width--; //Цикл по всем точкам изображения for (y=1; y<Height; y++) { //Сохранение указателя на предыдущую строку изображения pImagePrevBuf=pImageCurrBuf; //Сохранение указателя на предыдущую строку результата pAreasPrevBuf=pAreasCurrBuf; //Указатель на текущую строку изображения pImageCurrBuf=ImageBuf[iImageBufIndex]; //Указатель на текущую строку результата pAreasCurrBuf=AreasBuf[iAreasBufIndex]; //Продвижение индекса на следующую строку iImageBufIndex++; iImageBufIndex%=3; iAreasBufIndex++; iAreasBufIndex%=2; //Ожидание окончания загрузки текущей строки изображения while(DAT_busy(id_LoadTransfer)); //Запуск загрузки следующей строки изображения id_LoadTransfer = DAT_copy(Image[y+1], ImageBuf[iImageBufIndex], Width); //Установка начального значения для верхней левой точки iPrevAreaNumbUL=pAreasPrevBuf[0]; iPrevModeNumbUL=AreasMode[iPrevAreaNumbUL]; //Установка начального значения для верхней точки iPrevAreaNumbU=pAreasPrevBuf[1]; iPrevModeNumbU=AreasMode[iPrevAreaNumbU]; //Значение яркости первого пикселя строки iCurrPixel=pImageCurrBuf[0]; //Значение моды первого пикселя строки iPrevModeNumbL=ModeNumb4Pix[iCurrPixel]; //В зависимости от признака переходности пиксела if (iPrevModeNumbL<0) { if (abs(iCurrPixel-pImagePrevBuf[0])<abs(iCurrPixel-pImagePrevBuf[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); } //Установка номера области первого пиксела строки pAreasCurrBuf[0] = iPrevAreaNumbL; //Обработка очередной строки изображения for (x=1; x<Width; x++) { //Определение параметров верхней правой точки iPrevAreaNumbUR=pAreasPrevBuf[x+1]; iPrevModeNumbUR=AreasMode[iPrevAreaNumbUR]; //Значение яркости текущего пикселя iCurrPixel=pImageCurrBuf[x]; //Номер моды текущей точки iCurrModeNumb=ModeNumb4Pix[iCurrPixel]; //В зависимости от того является ли точка переходной if (iCurrModeNumb<0) { //Текущая точка является переходной к любой области //Перебор всех точек окрестности и выбор наиболее близкой области //Левая точка iDelta=abs(pImageCurrBuf[x-1]-iCurrPixel); iCurrAreaNumb=iPrevAreaNumbL; iCurrModeNumb=iPrevModeNumbL; //Верхняя точка iTmp=abs(pImagePrevBuf[x]-iCurrPixel); if (iDelta>iTmp) { iDelta=iTmp; iCurrAreaNumb=iPrevAreaNumbU; iCurrModeNumb=iPrevModeNumbU; } //Верхняя левая точка iTmp=abs(pImagePrevBuf[x-1]-iCurrPixel); if (iDelta>iTmp) { iDelta=iTmp; iCurrAreaNumb=iPrevAreaNumbUL; iCurrModeNumb=iPrevModeNumbUL; } //Верхняя правая точка iTmp=abs(pImagePrevBuf[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); } //Установка номера области текущей точки pAreasCurrBuf[x] = iCurrAreaNumb; //Сканирование верхней правой точки для добавления её в список соседних областей if ((iCurrModeNumb==iPrevModeNumbUR)&&(iCurrAreaNumb!=iPrevAreaNumbUR)) { //Всего четыре возможных варианта if (AreasNumber[iCurrAreaNumb]<0) { if (AreasNumber[iPrevAreaNumbUR]>=0) { //Только добавляется ссылка на ссылочную область AreasNumber[iCurrAreaNumb]=AreasNumber[iPrevAreaNumbUR]; //Декремент кол-ва областей iAreasCount--; } else { //Обе области являются доменными iTmp=min(iCurrAreaNumb,iPrevAreaNumbUR); AreasNumber[iCurrAreaNumb]=iTmp; AreasNumber[iPrevAreaNumbUR]=iTmp; //Декремент кол-ва областей iAreasCount--; } } else //if (AreasNumber[iCurrAreaNumb]>=0) { if (AreasNumber[iPrevAreaNumbUR]<0) { //Только добавляется ссылка на ссылочную область AreasNumber[iPrevAreaNumbUR]=AreasNumber[iCurrAreaNumb]; //Декремент кол-ва областей iAreasCount--; } else { iSrcIndex=AreasNumber[iCurrAreaNumb]; iDstIndex=AreasNumber[iPrevAreaNumbUR]; if (iSrcIndex!=iDstIndex) { //Это самый трудоёмкий случай. //Но, к счастью, самый редкий! //Необходимо объединить две области if (iSrcIndex<iDstIndex) { //Обмен значениями iTmp=iSrcIndex; iSrcIndex=iDstIndex; iDstIndex=iTmp; } for (i=0; i<iAreasInfoCount; i++) { if (AreasNumber[i]==iSrcIndex) AreasNumber[i]=iDstIndex; } //Декремент кол-ва областей iAreasCount--; } } } } //Запоминание номера области и моды для левой точки iPrevAreaNumbL=iCurrAreaNumb; iPrevModeNumbL=iCurrModeNumb; //Запоминание номера области и моды для верхней левой точки iPrevAreaNumbUL=iPrevAreaNumbU; iPrevModeNumbUL=iPrevModeNumbU; //Запоминание номера области и моды для верхней точки iPrevAreaNumbU=iPrevAreaNumbUR; iPrevModeNumbU=iPrevModeNumbUR; } //Значение яркости последнего пикселя строки iCurrPixel=pImageCurrBuf[Width]; //Значение моды последнего пикселя строки iCurrModeNumb=ModeNumb4Pix[iCurrPixel]; //В зависимости от наличия моды if (iCurrModeNumb<0) { //Левая точка iDelta=abs(pImageCurrBuf[x-1]-iCurrPixel); iCurrAreaNumb=iPrevAreaNumbL; iCurrModeNumb=iPrevModeNumbL; //Верхняя левая точка iTmp=abs(pImagePrevBuf[x-1]-iCurrPixel); if (iDelta>iTmp) { iDelta=iTmp; iCurrAreaNumb=iPrevAreaNumbUL; iCurrModeNumb=iPrevModeNumbUL; } //Верхняя точка iTmp=abs(pImagePrevBuf[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); } //Установка номера области последнего пикселя строки pAreasCurrBuf[Width]=iCurrAreaNumb; //Ожидание окончания сохранения результата while(DAT_busy(id_SaveTransfer)); //Сохранение строки результата id_SaveTransfer=DAT_copy(pAreasCurrBuf, Areas[y], Width); } //Восстановление исходной ширины изображения Width++;
//Упорядочивание переадресации областей (именно здесь)!!!!! for (i=0; i<iAreasInfoCount; i++) { //Номер кластера для текущей области iTmp=AreasNumber[i]; //Пропуск кластерных областей if (iTmp<0) //Установка номера области AreasNumber[i]=i; else //Выключение области AreasMode[i]=-1; }
//Могут оставаться независимые области с индексами больше iAreasCount for (iDstIndex=0, iSrcIndex=iAreasCount; iSrcIndex<iAreasInfoCount; iSrcIndex++) { //Если эта область уже переадресована - все нормально if (AreasMode[iSrcIndex]<0) continue; //Поиск индекса для переадресации for (/*задаётся вовне*/; iDstIndex<iAreasCount; iDstIndex++) if (AreasMode[iDstIndex]<0) break; //Сохранение указателя на моду AreasMode[iDstIndex]=AreasMode[iSrcIndex]; //Выключение переадресуемой области AreasMode[iSrcIndex]=-1; //Установка ссылки данной области на переадресованную AreasNumber[iSrcIndex]=iDstIndex; //Замена всех ссылок на эту область!!!!!!!! for (i=0; i<iAreasInfoCount; i++) if (AreasNumber[i]==iSrcIndex) AreasNumber[i]=iDstIndex; }
//Загрузка первой строки номеров областей id_LoadTransfer=DAT_copy(Areas[0], AreasBuf[0], Width); //Установка кольцевого указателя iAreasBufIndex=0; //Начальная инициализация идентификатора канала сохранения id_SaveTransfer=DAT_XFRID_WAITNONE; //Обработка всех строк for (y=0; y<Height; y++) { //Указатель на текущую строку результата pAreasCurrBuf=AreasBuf[iAreasBufIndex]; //Продвижение индекса на следующую строку iAreasBufIndex^=1; //Ожидание окончания загрузки текущей строки изображения while(DAT_busy(id_LoadTransfer)); //Запуск загрузки следующей строки изображения id_LoadTransfer=DAT_copy(Areas[y+1], AreasBuf[iAreasBufIndex], Width); //Переписывание индексов удалённых областей на переназначенные for (x=0; x<Width; x++) pAreasCurrBuf[x]=AreasNumber[pAreasCurrBuf[x]]; //Ожидание окончания сохранения результата while(DAT_busy(id_SaveTransfer)); //Сохранение строки результата id_SaveTransfer=DAT_copy(pAreasCurrBuf, Areas[y], Width); } //Ожидание окончания сохранения результата while(DAT_busy(id_SaveTransfer));
return iAreasCount; }
Сообщение отредактировал Degun - Feb 1 2008, 12:45
|
|
|
|
|
Feb 19 2008, 12:55
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Цитата(qxov @ Feb 13 2008, 13:16)  Очень тяжелый вложенный цикл. Нужно рассмотреть возможность упрощения. Возможно, имеет смысл разбить его на несколько значительно более простых. Значительно упростил вложенный цикл за счёт чуть большего расхода памяти. В результате для изображения с разрешением 640*480 процедура стала выполняться за 55 мсек. Но всё равно как-то много. Чтобы ещё такого оптимизировать? Код #include <stdlib.h> #include <limits.h> #include <csl_dat.h>
//Максимальное кол-во областей в изображении #define MAX_AREAS 2000
//Ограниченный массив структур описателей областей!!! #pragma DATA_ALIGN(8); static short AreasMode[MAX_AREAS+1]; #pragma DATA_ALIGN(8); static short AreasNumber[MAX_AREAS+1]; #pragma DATA_ALIGN(8); static short AreasPixel[MAX_AREAS+1];
//Буферы для кэширования строк изображения #pragma DATA_ALIGN(8); static unsigned char ImageBuf[2][IMG_WIDTH_MAX]; #pragma DATA_ALIGN(8); static unsigned short AreasBuf[2][IMG_WIDTH_MAX];
int dsp_SplitImage2AreasFast( unsigned char ** restrict Image, int Height, int Width, unsigned char * restrict ModeNumb4Pix, unsigned short ** restrict Areas) { //Изображение последовательно просматривается по строкам //для отнесения каждого пиксела к определённой области //Вычисление площади, занимаемой каждой областью и модой register int iAreasCounter; //Счётчик количества областей в изображении register int iAreasInfoCounter;//Счётчик количества областей в контейнере register int iPrevAreaNumbL; //Номер области предыдущей левой точки register int iPrevModeNumbL; //Номер моды предыдущей левой точки //Временные переменные register int i, y, x, iSrcIndex, iDstIndex, iTmp; register int iCurrAreaNumb, iCurrModeNumb, iAreasInfoCountSav; register Uint32 id_LoadTransfer, id_SaveTransfer; register unsigned char * restrict pImageNextBuf; register unsigned char * restrict pImageCurrBuf; register unsigned short * restrict pAreasCurrBuf; register unsigned short * restrict pAreasPrevBuf;
//Проверка корректности входных параметров if ((Image==0)||(ModeNumb4Pix==0)||(Areas==0)||(Width<=0)||(Height<=0)|| (Width>IMG_WIDTH_MAX)||(Height>IMG_HEIGHT_MAX)) return -1;
//Установка указателя на следующую строку изображения pImageNextBuf=ImageBuf[0]; //Загрузка первой строки изображения id_LoadTransfer=DAT_copy(Image[0], pImageNextBuf, Width); //Начальная инициализация идентификатора канала сохранения id_SaveTransfer=DAT_XFRID_WAITNONE;
//Обнуление счётчиков кол-ва областей iAreasCounter=iAreasInfoCounter=0; //Установка кол-ва областей максимально возможное для первой строки iAreasInfoCountSav=INT_MAX; //Обнуление указателя на текущую строку pAreasCurrBuf=NULL; //Цикл по всем точкам изображения for (y=0; y<Height; y++) { //Сохранение указателя на текущую строку изображения pImageCurrBuf=pImageNextBuf; //Сохранение указателя на предыдущую строку результата pAreasPrevBuf=pAreasCurrBuf; //Указатель на следующую строку изображения pImageNextBuf=ImageBuf[(y+1)&1]; //Указатель на текущую строку результата pAreasCurrBuf=AreasBuf[y&1]; //Начальные значения номера области и моды для левой точки iPrevModeNumbL=iPrevAreaNumbL=-1; //Ожидание окончания загрузки текущей строки изображения DAT_wait(id_LoadTransfer); //Запуск загрузки следующей строки изображения id_LoadTransfer = DAT_copy(Image[y+1], pImageNextBuf, Width); //Обработка очередной строки изображения for (x=0; x<Width; x++) { //Номер моды текущей точки iCurrModeNumb=ModeNumb4Pix[pImageCurrBuf[x]]; //В зависимости от того принадлежит ли точка той же моде, //что и её левая точка, установка номера области if (iCurrModeNumb==iPrevModeNumbL) iCurrAreaNumb=iPrevAreaNumbL; else { //Добавление новой области // if (iAreasInfoCount>=MAX_AREAS) return -1; iCurrAreaNumb=iAreasInfoCounter; AreasMode[iAreasInfoCounter]=iCurrModeNumb; AreasNumber[iAreasInfoCounter]=iAreasInfoCounter; AreasPixel[iAreasInfoCounter]=x; //Инкремент счётчиков областей iAreasCounter++; iAreasInfoCounter++; //Запоминание номера области и моды для левой точки iPrevAreaNumbL=iCurrAreaNumb; iPrevModeNumbL=iCurrModeNumb; } //Установка номера области текущей точки pAreasCurrBuf[x]=iCurrAreaNumb; } //Обработка всех областей в текущей строке для выявления их связей //с областями на предыдущей строке for (; iAreasInfoCountSav<iAreasInfoCounter; iAreasInfoCountSav++) { iSrcIndex=iAreasInfoCountSav; iCurrModeNumb=AreasMode[iAreasInfoCountSav]; iTmp=AreasPixel[iAreasInfoCountSav]; if (iTmp>0) iTmp--; if (iAreasInfoCountSav==(iAreasInfoCounter-1)) iCurrAreaNumb=Width-1; else iCurrAreaNumb=AreasPixel[iAreasInfoCountSav+1]; iCurrAreaNumb=pAreasPrevBuf[iCurrAreaNumb]; //Цикл по всем граничащим на предыдущей строке областям for (i=pAreasPrevBuf[iTmp]; i<=iCurrAreaNumb; i++) { if (AreasMode[i]!=iCurrModeNumb) continue; //На предыдущей строке найдена область с совпадающей модой, //которая соседствует с исходной iDstIndex=i; while(AreasNumber[iDstIndex]!=iDstIndex) iDstIndex=AreasNumber[iDstIndex]; if (iSrcIndex!=iDstIndex) { //Объединение двух кластеров областей if (iSrcIndex<iDstIndex) { //Сохранение номера AreasNumber[iDstIndex]=iSrcIndex; } else { //Сохранение номера AreasNumber[iSrcIndex]=iDstIndex; //Для дальнейшего объединения берётся меньший индекс iSrcIndex=iDstIndex; } //Декремент кол-ва областей iAreasCounter--; } } } //Сохранение кол-ва областей iAreasInfoCountSav=iAreasInfoCounter; //Ожидание окончания сохранения результата DAT_wait(id_SaveTransfer); //Сохранение строки результата id_SaveTransfer=DAT_copy(pAreasCurrBuf, Areas[y], sizeof(short)*Width); }
//Обновление ссылок на области for (iSrcIndex=0; iSrcIndex<iAreasInfoCounter; iSrcIndex++) { //Поиск индекса назначения iDstIndex=iSrcIndex; while(AreasNumber[iDstIndex]!=iDstIndex) iDstIndex=AreasNumber[iDstIndex]; //Обновление номера области AreasNumber[iSrcIndex]=iDstIndex; }
//Могут оставаться независимые области с индексами больше iAreasCount for (iDstIndex=-1, iSrcIndex=iAreasCounter; iSrcIndex<iAreasInfoCounter; iSrcIndex++) { //Если эта область уже переадресована - все нормально if (AreasNumber[iSrcIndex]!=iSrcIndex) continue; //Поиск индекса для переадресации for (iDstIndex++; iDstIndex<iAreasCounter; iDstIndex++) if (AreasNumber[iDstIndex]!=iDstIndex) break; //Сохранение указателя на моду AreasMode[iDstIndex]=AreasMode[iSrcIndex]; //Установка ссылки данной области на переадресованную AreasNumber[iSrcIndex]=iDstIndex; //Замена всех ссылок на эту область!!!!!!!! for (i=iSrcIndex; i<iAreasInfoCounter; i++) if (AreasNumber[i]==iSrcIndex) AreasNumber[i]=iDstIndex; }
//Установка указателя на текущую загружаемую строку pAreasCurrBuf=AreasBuf[0]; //Загрузка первой строки номеров областей id_LoadTransfer=DAT_copy(Areas[0], pAreasCurrBuf, sizeof(short)*Width); //Начальная инициализация идентификатора канала сохранения id_SaveTransfer=DAT_XFRID_WAITNONE; //Обработка всех строк for (y=0; y<Height; y++) { //Сохранение указателя на предыдущую строку результата pAreasPrevBuf=pAreasCurrBuf; //Указатель на следующую строку результата pAreasCurrBuf=AreasBuf[(y+1)&1]; //Ожидание окончания загрузки текущей строки изображения DAT_wait(id_LoadTransfer); //Запуск загрузки следующей строки изображения id_LoadTransfer=DAT_copy(Areas[y+1], pAreasCurrBuf, sizeof(short)*Width); //Переписывание индексов удалённых областей на переназначенные for (x=0; x<Width; x++) pAreasPrevBuf[x]=AreasNumber[pAreasPrevBuf[x]]; //Ожидание окончания сохранения результата DAT_wait(id_SaveTransfer); //Сохранение строки результата id_SaveTransfer=DAT_copy(pAreasPrevBuf, Areas[y], sizeof(short)*Width); } //Ожидание окончания сохранения результата DAT_wait(id_SaveTransfer);
return iAreasCounter; }
Сообщение отредактировал Degun - Feb 19 2008, 13:04
|
|
|
|
|
Mar 17 2008, 13:29
|
Частый гость
 
Группа: Новичок
Сообщений: 84
Регистрация: 4-09-07
Из: Москва
Пользователь №: 30 277

|
Следующий вариант выполняется на 1 мсек быстрее, чем предыдущий. Возможно это ещё не предел оптимизации, но больше у меня идей нет. Если кто знает, то подскажите. Код /*!\brief Разбиение изображения на непересекающиеся области * \brief в соответствии с таблицей мод * \param Image - исходное изображение * \param Height - высота изображения * \param Width - ширина изображение * \param ModeNumb4Pix - таблица соответствия значений пикселов модам гистограммы * \param Areas - буфер результата, отражающий номера областей каждого из пикселов * \result Количество непересекающихся областей в изображении */ #include <stdlib.h> #include <csl_dat.h>
//Максимальное кол-во областей в изображении #define MAX_AREAS 2000
//Ограниченный массив структур описателей областей!!! #pragma DATA_ALIGN(8); static short AreasMode[MAX_AREAS+1]; #pragma DATA_ALIGN(8); static short AreasNumber[MAX_AREAS+1]; #pragma DATA_ALIGN(8); static short AreasPixel[MAX_AREAS+1];
//Буферы для кэширования строк изображения #pragma DATA_ALIGN(8); static unsigned char ImageBuf[2][IMG_WIDTH_MAX]; #pragma DATA_ALIGN(8); static unsigned short AreasBuf[2][IMG_WIDTH_MAX];
int dsp_SplitImage2AreasFast( unsigned char ** restrict Image, int Height, int Width, unsigned char * restrict ModeNumb4Pix, unsigned short ** restrict Areas) { //Изображение последовательно просматривается по строкам //для отнесения каждого пиксела к определённой области //Вычисление площади, занимаемой каждой областью и модой register int iAreasCounter; //Счётчик количества областей в изображении register int iAreasInfoCounter;//Счётчик количества областей в контейнере //Временные переменные register int i, y, x, iSrcIndex, iDstIndex, iTmp; register int iCurrAreaNumb, iCurrModeNumb; register Uint32 id_LoadTransfer, id_SaveTransfer; register unsigned char * restrict pImageNextBuf; register unsigned char * restrict pImageCurrBuf; register unsigned short * restrict pAreasCurrBuf; register unsigned short * restrict pAreasPrevBuf;
//Проверка корректности входных параметров if ((Image==0)||(ModeNumb4Pix==0)||(Areas==0)|| (Width<=0)||(Height<=0)||(Width>IMG_WIDTH_MAX)) return -1;
//Установка указателя на следующую строку изображения pImageNextBuf=ImageBuf[0]; //Загрузка первой строки изображения id_LoadTransfer=DAT_copy(Image[0], pImageNextBuf, Width); //Начальная инициализация идентификатора канала сохранения id_SaveTransfer=DAT_XFRID_WAITNONE;
//Обнуление счётчиков кол-ва областей iAreasCounter=iAreasInfoCounter=0; //Установка кол-ва областей максимально возможное для исключения //применения к первой строке ветви выявления связей с предыдущими строками iTmp=IMG_WIDTH_MAX; //Обнуление указателя на текущую строку pAreasCurrBuf=NULL; //Цикл по всем точкам изображения for (y=0; y<Height; y++) { //Сохранение указателя на текущую строку изображения pImageCurrBuf=pImageNextBuf; //Сохранение указателя на предыдущую строку результата pAreasPrevBuf=pAreasCurrBuf; //Указатель на следующую строку изображения pImageNextBuf=ImageBuf[(y+1)&1]; //Указатель на текущую строку результата pAreasCurrBuf=AreasBuf[y&1]; //Начальные значения номера моды iCurrModeNumb=-1; //Ожидание окончания загрузки текущей строки изображения DAT_wait(id_LoadTransfer); //Запуск загрузки следующей строки изображения id_LoadTransfer = DAT_copy(Image[y+1], pImageNextBuf, Width); //Обработка очередной строки изображения for (x=0; x<Width; x++) { //Номер моды текущей точки i=ModeNumb4Pix[pImageCurrBuf[x]]; //В зависимости от того принадлежит ли точка той же моде, //что и её левая точка, установка номера области if (iCurrModeNumb!=i) { //Добавление новой области // if (iAreasInfoCount>=MAX_AREAS) return -1; iCurrModeNumb=i; iCurrAreaNumb=iAreasInfoCounter; AreasMode[iAreasInfoCounter]=iCurrModeNumb; AreasNumber[iAreasInfoCounter]=iAreasInfoCounter; AreasPixel[iAreasInfoCounter]=x; //Инкремент счётчиков областей iAreasCounter++; iAreasInfoCounter++; } //Установка номера области текущей точки pAreasCurrBuf[x]=iCurrAreaNumb; } //Обработка всех областей в текущей строке для выявления их связей for (; iTmp<iAreasInfoCounter; iTmp++) { iSrcIndex=iTmp; iCurrModeNumb=AreasMode[iTmp]; i=AreasPixel[iTmp]; if (i>0) i--; if (iTmp==(iAreasInfoCounter-1)) iCurrAreaNumb=Width-1; else iCurrAreaNumb=AreasPixel[iTmp+1]; iCurrAreaNumb=pAreasPrevBuf[iCurrAreaNumb]; //Цикл по всем граничащим на предыдущей строке областям for (i=pAreasPrevBuf[i]; i<=iCurrAreaNumb; i++) { if (AreasMode[i]!=iCurrModeNumb) continue; //На предыдущей строке найдена область с совпадающей модой, //которая соседствует с исходной iDstIndex=i; while(AreasNumber[iDstIndex]!=iDstIndex) iDstIndex=AreasNumber[iDstIndex]; if (iSrcIndex!=iDstIndex) { //Объединение двух кластеров областей if (iSrcIndex<iDstIndex) { //Сохранение номера AreasNumber[iDstIndex]=iSrcIndex; } else { //Сохранение номера AreasNumber[iSrcIndex]=iDstIndex; //Для дальнейшего объединения берётся меньший индекс iSrcIndex=iDstIndex; } //Декремент кол-ва областей iAreasCounter--; } } } //Сохранение кол-ва областей iTmp=iAreasInfoCounter; //Ожидание окончания сохранения результата DAT_wait(id_SaveTransfer); //Сохранение строки результата id_SaveTransfer=DAT_copy(pAreasCurrBuf, Areas[y], sizeof(short)*Width); }
//Обновление ссылок на области for (iSrcIndex=0; iSrcIndex<iAreasInfoCounter; iSrcIndex++) { //Поиск индекса назначения iDstIndex=iSrcIndex; while(AreasNumber[iDstIndex]!=iDstIndex) iDstIndex=AreasNumber[iDstIndex]; //Обновление номера области AreasNumber[iSrcIndex]=iDstIndex; }
//Могут оставаться независимые области с индексами больше iAreasCount for (iDstIndex=-1, iSrcIndex=iAreasCounter; iSrcIndex<iAreasInfoCounter; iSrcIndex++) { //Если эта область уже переадресована - все нормально if (AreasNumber[iSrcIndex]!=iSrcIndex) continue; //Поиск индекса для переадресации for (iDstIndex++; iDstIndex<iAreasCounter; iDstIndex++) if (AreasNumber[iDstIndex]!=iDstIndex) break; //Сохранение указателя на моду AreasMode[iDstIndex]=AreasMode[iSrcIndex]; //Установка ссылки данной области на переадресованную AreasNumber[iSrcIndex]=iDstIndex; //Замена всех ссылок на эту область!!!!!!!! for (i=iSrcIndex; i<iAreasInfoCounter; i++) if (AreasNumber[i]==iSrcIndex) AreasNumber[i]=iDstIndex; }
//Установка указателя на текущую загружаемую строку pAreasCurrBuf=AreasBuf[0]; //Загрузка первой строки номеров областей id_LoadTransfer=DAT_copy(Areas[0], pAreasCurrBuf, sizeof(short)*Width); //Начальная инициализация идентификатора канала сохранения id_SaveTransfer=DAT_XFRID_WAITNONE; //Обработка всех строк for (y=0; y<Height; y++) { //Сохранение указателя на предыдущую строку результата pAreasPrevBuf=pAreasCurrBuf; //Указатель на следующую строку результата pAreasCurrBuf=AreasBuf[(y+1)&1]; //Ожидание окончания загрузки текущей строки изображения DAT_wait(id_LoadTransfer); //Запуск загрузки следующей строки изображения id_LoadTransfer=DAT_copy(Areas[y+1], pAreasCurrBuf, sizeof(short)*Width); //Переписывание индексов удалённых областей на переназначенные for (x=0; x<Width; x++) pAreasPrevBuf[x]=AreasNumber[pAreasPrevBuf[x]]; //Ожидание окончания сохранения результата DAT_wait(id_SaveTransfer); //Сохранение строки результата id_SaveTransfer=DAT_copy(pAreasPrevBuf, Areas[y], sizeof(short)*Width); } //Ожидание окончания сохранения результата DAT_wait(id_SaveTransfer);
return iAreasCounter; }
|
|
|
|
|
Mar 17 2008, 17:09
|
Местный
  
Группа: Свой
Сообщений: 462
Регистрация: 26-06-07
Пользователь №: 28 723

|
Цитата(Degun @ Nov 7 2007, 22:59)  Что-то я запутался в конвейерах и в глубине конвейера для DM642. В документации по нему сказано, что у него 8 параллельно работающих устройств, выполняющих команды. Т. е. если повезёт, то за один такт может выполниться параллельно до 8-ми команд. Значит 8 - это количество конвейеров или это глубина всего одного конвейера? Глубина конвейера и их число - независимые величины. Кстати, глубина конвейера часто зависит от выполняемой операции. Есть очень хорошая книжка, где все это расписано - П.М. Коуги, "Архитектура конвейерных ЭВМ". Грубо говоря, длина конвейера - это сколько тактов от выдачи команды до получения результата данной команды (в то же время в процессе исполнения могут находиться другие команды, если для них есть данные, если их нет - то компилятор и ставит NOP-ы). Число конвейеров - это то, сколько независимых друг от друга наборов данных могут обрабатываться параллельно. Естественно, все это хорошо работает только на задачах типа фильтрации, где нет зависимостей по данным (результат предыдущей операции для непосредственно следующей за ней не нужен). Производительность таких систем радикально зависит от алгоритма, и для алгоритмов с большим числом ветвления (типа управляющих) нужен совершенно другой проц, с одним-двумя максимально короткими конвейерами и максимальной тактовой частотой, точнее, с максимальным отношением тактовой частоты к эффективной длине конвейера. Эффективная длина конвейера - это и есть число тактов после запуска операции до возможности использования результата в следующих командах или число потерянных тактов при переходе. К примеру, эффективная длина конвейера процессоров MIPS на целочисленных операциях нормальной разрядности не превышает 2 (обычно 1), на плавающих - 5 (редко 7). А тактовые частоты достаточно высоки, поэтому неудивительно, что на задачах типа описанной Вами он работает гораздо эффективнее DSP. Это имеет большой коммерческий смысл - благодаря этому свойству была создана и "раскручена" компания, предложившая очень экономичные эффективные решения в области security video, причем именно на MIPS, благодаря его высокой эффективности на реальном коде. p.s. IMHO, любую задачу надо начинать с анализа алгоритмов, их написания и отладки на том же PC, и только после этого выбирать вычислительную платформу, а не просто смотреть на рекламные цифры. Иначе можно сильно погореть.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|