Поиск:

Ответ в темуСоздание новой темы Создание опроса
> нужно ускорить одну функцию, надо асм или нет 
:(
    Опции темы
comcon1
Дата 28.2.2007, 01:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



В общем, занялся профилированием своей проге. Отловил функцию, запускающуюся порядка
миллиардов раз и жрущую процентов 40-30 времени. Больше всех. Я ее чуть подкорячил. 
Время выполнение ее упало, а других - выросло!! Как такое может быть.

Смотрю плоские профили - все функции выполнялись в разных вариантах одинаковое число раз. Но только, суммарное время ВЫРОСЛО! Как такое может быть??

Компилю этим:
============
gcc-3.4.4 
cygwin

Прога у меня кросс. Но в линухе еще не пробовал. Она компилится и без цигвина, но в ДевЦпп у меня профилер глючит почему-то.

Вот было:
Код

int Water::returnProton(bool exists) {
    int result = 0;
    for (int j=0; j<4; j++)
        result += ((exists && (hydro[j]==1)) || (!exists && (hydro[j]==-1))) ? 1 : 0;
    return result;
}

Стало:
Код

inline short Water::returnProton(bool exists) {
    register short ex = -1+2*exists;
    return (hydro[0] == ex) + (hydro[1] == ex) + (hydro[2] == ex) + (hydro[3] == ex);
}


А в плоском профиле было:
Код

 38.00     30.58    30.58 440359184     0.00     0.00  Water::returnProton(bool) 
 11.77     40.05     9.47        1     9.47    75.87  Surface::Arrange(boost::mul
  5.95     44.84     4.79 132278224     0.00     0.00  Surface::ableSetProton(Wat

А Стало ВОТ ЧО:!!!
Код

 21.03     21.29    21.29 440359184     0.00     0.00  Water::returnProton(bool) 
 15.66     37.15    15.86        1    15.86    93.56  Surface::Arrange(boost::mul
  8.24     45.49     8.34 132278224     0.00     0.00  Surface::ableSetProton(Wat

А общее время по профилю выросло на 10%. Как такое получается?? Может, я чо совсем не так делаю..

И еще - Можно ли сделать асм-вставку?? Или нет смысла?


--------------------
PM MAIL   Вверх
szz
Дата 28.2.2007, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1289
Регистрация: 31.5.2005
Где: Moscow, Jerusalem

Репутация: нет
Всего: 33



так это же инлайн! Ты порекомендвал компилтору вместо отдельной функции просто вставлять ее тело прям в вызываемое место.

Добавлено @ 02:05 
Почитай на википедии поподробнее


--------------------
PM   Вверх
vitlic
Дата 28.2.2007, 02:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 74
Регистрация: 22.2.2007
Где: где home(){return где="тут"}

Репутация: нет
Всего: 1



Согласен с szz

попробуй убрать inline

Мейрс о возможных причинах:
Код

Слишком частое применение встроенных функций на машинах с ограниченной памятью может 
привести к созданию программы, которая превосходит доступную память. Даже 
при наличии виртуальной памяти «разбухание» кода, вызванное применением 
встроенных функций, может привести к дополнительному обмену с диском, 
уменьшить коэффициент попадания команд в кэш и, следовательно, снизить  
производительность программы. 
С другой стороны, если тело встроенной функции очень короткое, то  
сгенерированный для нее код может быть короче кода, сгенерированного для вызова 
функции. В таком случае встраивание функции может привести к уменьшению 
объектного кода и повышению коэффициента попаданий в кэш! 




Это сообщение отредактировал(а) vitlic - 28.2.2007, 02:17
PM WWW   Вверх
comcon1
Дата 28.2.2007, 09:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



Понял. Попробую. 
вставление функции инлайн приводит к разрастанию кода. Но и производительность должна вырасти, вроде. Прога, кстати жрет мало памяти - метра 2-5.


--------------------
PM MAIL   Вверх
MAKCim
Дата 28.2.2007, 10:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 1
Всего: 207



Код

int Water::returnProton(bool exists) {
    int result = 0;
    for (int j=0; j<4; j++)
        result += ((exists && (hydro[j]==1)) || (!exists && (hydro[j]==-1))) ? 1 : 0;
    return result;
}

Код

int Water::returnProton(bool exists) {
    int result;
    __asm__(
        "1: testl %3, %3\n\
              jz     2f\n\
              cmpl $1, (%2)\n\
              setz %%ah\n\
              jmp 3f\n\
          2: cmpl $-1, (%2)\n\
              setz %%ah\n\
          3: addb %%ah, %%al\n\
              addl $4, %2\n\
              xorb %%ah, %%ah\n\
              decl %4\n\
              jnz  1b"
          "=a" (result) : 
          "0" (0), "b" (hydro), "d" (exists), "c" (4)
    );
    return result;
}


Это сообщение отредактировал(а) MAKCim - 28.2.2007, 11:11


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
comcon1
Дата 28.2.2007, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



а не быстрее ли цикл
Код

mov cx, 4
loop ..


или там загрузить массив hydro в регистр EDX при помощи стоса и с ним работать??

Поясните плиз, где прочитать про специфику асм вставок в GCC. А то я посл. раз писал лет пять назад в турбо-паскале, дык там как-то просто было. Или хотя бы поясни на примере.


--------------------
PM MAIL   Вверх
comcon1
Дата 2.3.2007, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



Все, с GCC-шным ассемблером я разобрался.
Вот мой последний более быстрый вариант.
Код

int Water::returnProton(bool exists) {               
    int result;           
    __asm__(                                             
             "xorl  %%eax, %%eax\n\t"                    
             "addb  %2, %2\n\t"                          
             "decb  %2\n\t"                              
         "1:\tcmpb  %%dl, (%1)\n\t"                      
             "setz  %%ah\n\t"                            
             "addb  %%ah, %%al\n\t"                      
             "addl  $2, %1\n\t"                          
             "xorb  %%ah, %%ah\n\t"                      
             "loop  1b"                                  
          : "=a" (result)                                
          : "b" (hydro), "d" (exists), "c" (4)           
          :                                              
    );                                                   
    return result;        
/*    register int ex = -1+2*exists;                                                   
      return (hydro[0] == ex) + (hydro[1] == ex) + (hydro[2] == ex) + (hydro[3] == ex); */
}        

Модератор, перенесите, пожалуйста в ассемблер. 
Хочу обсудить дальнейшие ускорения. 
Или если ускорений больше быть не может, закройте тему)


--------------------
PM MAIL   Вверх
MAKCim
Дата 2.3.2007, 16:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 1
Всего: 207



comcon1, 
я бы сделал вместо loop, dec + jnz


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
comcon1
Дата 2.3.2007, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



у меня в доке к 486 стоит такты:
jnz - 3/1
dec - 1
loop - 2 когда циклит
loop - 6 когда выходит

Таким образом, твой вариант:
(1+3)*4 = 16
Мой вариант:
2*3+6 = 12

Что изменилось на 686 принципиально?

ЗЫ. + сама инструкция луп занимает меньше памяти, чем jnz+dec

Это сообщение отредактировал(а) comcon1 - 2.3.2007, 23:28


--------------------
PM MAIL   Вверх
sgi1981
Дата 3.3.2007, 01:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 16.3.2006

Репутация: 7
Всего: 10



Работает.
При условии, что массив hydro типа char (каждый элемент по 1 байт).
Используется расширение SSE.
Возможно, разные компиляторы поддерживают разное мнемоническое обозначение MMX-регистров, так что поправляйте...
Код

char hydro[4];


Код

int Water::returnProton(bool exists)
{
asm
{
pxor mm2,mm2;
cmp exists,0;
jz @p1;
mov eax,dword ptr hydro;
mov edx,01010101h;
movd mm0,eax;
movd mm1,edx;
pcmpeqb mm0,mm1;
pand mm0,mm1;
psadbw mm0,mm2;
movd eax,mm0;
jmp @end1;
@p1:
mov eax,dword ptr hydro;
mov edx,0ffffffffh;
movd mm0,eax;
movd mm1,edx;
pcmpeqb mm0,mm1;
mov edx,01010101h;
movd mm1,edx;
pand mm0,mm1;
psadbw mm0,mm2;
movd eax,mm0;
@end1:emms;
};
};



--------------------
Тело в нашем пространстве - есть часть пространства, в которой пространство обладает дисторсией относительно внешнего пространства.
PM MAIL   Вверх
W4FhLF
Дата 3.3.2007, 06:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 3
Всего: 121



Цитата(comcon1 @  2.3.2007,  23:27 Найти цитируемый пост)
Что изменилось на 686 принципиально?


C момента 486 процессоры ушли ТАААК далеко, что на данный момент прогнозировать скорость выполнения одной машинной инструкции просто бесполезно, слишком сложна архитектура сейчас. Можно лишь говорить о кол-ве тактов за которые декодируются команды или судить о скорости их выполнения в общей массе. Ну можно предположить, что dec выполнится за один такт совместно с другой командой, т.к. результаты выполнения dec и вышестоящих команд не пересекаются, а дальше уже jnz(где на первых иттерациях будут кэш-промахи, но после процессор может "предсказать" переход), в то время как loop не будет выполнена, пока не выполнятся все команды в цикле. 

Это сообщение отредактировал(а) W4FhLF - 3.3.2007, 06:48


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
comcon1
Дата 3.3.2007, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



Цитата(sgi1981 @  3.3.2007,  01:34 Найти цитируемый пост)
Используется расширение SSE.

где читать про эти команды??

На взгляд код выглядит очень большим... Что именно ускорится??


--------------------
PM MAIL   Вверх
sgi1981
Дата 3.3.2007, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 16.3.2006

Репутация: 7
Всего: 10



Цитата
На взгляд код выглядит очень большим... Что именно ускорится?? 

Да, код немного больше, чем коды предыдущие.
Но есть преимущества.
1 - Отсутствуют циклы. Часть последовательности инструкций выполняется один раз и все.
2 - Реально выполняется только одна из двух частей последовательности инструкций. Какая именно часть выполнится - зависит от значения exists.
3 - Оператора return не нужно. Функции, возвращающие целочисленный результат, возвращают его в регистре eax.

И того, считаем количество инструкций, выполняемых если exists=1

pxor mm2,mm2;
cmp exists,0;
jz @p1;
mov eax,dword ptr hydro;
mov edx,01010101h;
movd mm0,eax;
movd mm1,edx;
pcmpeqb mm0,mm1;
pand mm0,mm1;
psadbw mm0,mm2;
movd eax,mm0;
jmp @end1;
;-------------------------------
@end1:emms;

То бишь 13 инструкций.

При exists=0

pxor mm2,mm2;
cmp exists,0;
jz @p1;
;---------------------------
@p1:
mov eax,dword ptr hydro;
mov edx,0ffffffffh;
movd mm0,eax;
movd mm1,edx;
pcmpeqb mm0,mm1;
mov edx,01010101h;
movd mm1,edx;
pand mm0,mm1;
psadbw mm0,mm2;
movd eax,mm0;
@end1:emms;

14 инструкций.

И тут есть преимущества самого кода. Инструкции, результат выполнения которых не влияет на результат выполнения последующей инструкции выполняются параллельно.

Добавлено @ 15:38 
Цитата

где читать про эти команды??


Про инструкции SSE, SSE2, SSE3, 3DNow! читать в документации по процессору.
Документация на английском.
http://developer.intel.ru/design/pentium4/documentation.htm
Или можно из книги, лучше справочник по ассемблеру, Виктора Юрова, например. Там на русском.



--------------------
Тело в нашем пространстве - есть часть пространства, в которой пространство обладает дисторсией относительно внешнего пространства.
PM MAIL   Вверх
comcon1
Дата 4.3.2007, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 838
Регистрация: 11.6.2005
Где: Москва ДАС-МГУ

Репутация: нет
Всего: 17



Скачал Юрова и документацию с Intel-а. Ботаю SSE. Всем спасибо. 
Осилю - выложу код с гонками.


--------------------
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Asm: Общие вопросы"
MAKCim
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой КОД.
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, MAKCim.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Asm: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1312 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.