Поиск:

Ответ в темуСоздание новой темы Создание опроса
> MSVC компилит плохой код 
:(
    Опции темы
Abyx
Дата 24.8.2010, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Компилятор msvc2010
Код

// compile as "Release" with /MT /GS-

#include <algorithm>

#pragma pack(push, 4)
struct Foo
{
    char unused[24];
    int value;
};
#pragma pack(pop)

extern "C" __declspec(dllexport)
unsigned __stdcall count(Foo* array, int size, int value)
{
    return std::count_if(array, array + size, [value](const Foo& x){return x.value == value;});
}

получается
Код

.text:10001000 count           proc near               ; DATA XREF: .rdata:off_10007FA8o
.text:10001000
.text:10001000 arg_0           = dword ptr  8
.text:10001000 arg_4           = dword ptr  0Ch
.text:10001000 arg_8           = dword ptr  10h
.text:10001000
.text:10001000                 push    ebp
.text:10001001                 mov     ebp, esp
.text:10001003                 mov     edx, [ebp+arg_4]
.text:10001006                 mov     ecx, [ebp+arg_0]
.text:10001009                 push    esi
.text:1000100A                 lea     esi, ds:0[edx*8]
.text:10001011                 sub     esi, edx
.text:10001013                 lea     edx, [ecx+esi*4]
.text:10001016                 xor     eax, eax
.text:10001018                 cmp     ecx, edx
.text:1000101A                 jz      short empty_array
.text:1000101C                 mov     esi, [ebp+arg_8]
.text:1000101F                 nop
.text:10001020
.text:10001020 loo:                                    ; CODE XREF: count+2Bj
.text:10001020                 cmp     [ecx+18h], esi
.text:10001023                 jnz     short not_a_value
.text:10001025                 inc     eax
.text:10001026
.text:10001026 not_a_value:                            ; CODE XREF: count+23j
.text:10001026                 add     ecx, 1Ch
.text:10001029                 cmp     ecx, edx
.text:1000102B                 jnz     short loo
.text:1000102D
.text:1000102D empty_array:                            ; CODE XREF: count+1Aj
.text:1000102D                 pop     esi
.text:1000102E                 pop     ebp
.text:1000102F                 retn    0Ch
.text:1000102F count           endp

вместо cmp     [ecx+18h], esi
хорошо бы чтобы константа прибавлялась не на каждой итерации цикла, а один раз в самом начале
также не есть хорошо jnz short not_a_value / inc eax / not_a_value


------------
Тема не предполагает какого-то обсуждения, просто примеры плохого кода генерируемого MSVC.
Как написать код С++ с явным циклом вместо std::count, чтобы сгенерился оптимальный код - я знаю, объяснять мне это не надо.
PM MAIL   Вверх
djamshud
Дата 24.8.2010, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пердупержденный
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 23.11.2009

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



MSVC-* - гуан* и ее STL - тоже гуан*. © Abyx

Прошу прощение, не удержался.


--------------------
'Cuz I never walk away from what I know is right
Alice Cooper - Freedom
PM   Вверх
Abyx
Дата 24.8.2010, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



djamshud, так ведь g++ то еще хуже =)
PM MAIL   Вверх
djamshud
Дата 24.8.2010, 11:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пердупержденный
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 23.11.2009

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



Abyx, может и хуже, но я на нем пишу так, что решения из STL сливают, изредко многократно. Когда писал на MSVC тоже сливали. Так что мое имхо, что STL само по себе тупое неповоротливое решение by design.


--------------------
'Cuz I never walk away from what I know is right
Alice Cooper - Freedom
PM   Вверх
Abyx
Дата 24.8.2010, 12:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Эх... не могу удержаться... Нами всеми любимая std::sort
Код

extern "C" __declspec(dllexport)
void __stdcall sort(Foo* first, Foo* last)
{
    std::sort(first, last, [](const Foo& a, const Foo& b){return a.value > b.value;});
}


..... барабанная дробь...

Код

public sort
sort proc near

var_4= dword ptr -4
arg_0= dword ptr  8
arg_4= dword ptr  0Ch

push    ebp
mov     ebp, esp
push    ecx
push    esi
mov     esi, [ebp+arg_4]
push    edi
mov     edi, [ebp+arg_0]
mov     byte ptr [ebp+var_4], 0
mov     eax, [ebp+var_4]
push    eax
mov     ecx, esi
sub     ecx, edi
mov     eax, 92492493h
imul    ecx
add     edx, ecx
sar     edx, 4
mov     ecx, edx
shr     ecx, 1Fh
add     ecx, edx
push    ecx
push    esi
push    edi
call    std___Sort_Foo___int__anonymous_namespace____lambda0___
add     esp, 10h
pop     edi
pop     esi
mov     esp, ebp
pop     ebp
retn    8
sort endp


????!!!!

поясняю: mov eax, 92492493h / imul ecx это деление на sizeof(Foo), чтобы получить число элементов диапазона.
деление умножением это быстро. (у нас стоит оптимизация по скорости) 

смотрим дальше.
Код

std___Adjust_heap_Foo___int_Foo__anonymous_namespace____lambda0___ proc near
............
.text:1000185F                 lea     esi, [ebx+edx*4]
.text:10001862                 mov     edx, [esi+18h]
.text:10001865                 cmp     edx, [edi+18h]

all the same shit, +18h

однако лямбда заинлайнилась везде где есть ее вызов (об этом кстати говорят и имена функций)

----------------------
как убрать +18h в каждой итерации, и при этом использовать std::sort я тоже знаю
PM MAIL   Вверх
Abyx
Дата 24.8.2010, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(djamshud @  24.8.2010,  12:44 Найти цитируемый пост)
Abyx, может и хуже, но я на нем пишу так, что решения из STL сливают, изредко многократно. Когда писал на MSVC тоже сливали. 

А я... а Я.... вы либо код показывайте, либо прекращайте сказки рассказывать %)

Добавлено через 13 минут и 32 секунды
продолжаем....

возьмем-ка мы, и уберем лямбду
Код

bool pred(const Foo& a, const Foo& b)
{
    return a.value > b.value;
}

extern "C" __declspec(dllexport)
void __stdcall sort(Foo* first, Foo* last)
{
    std::sort(first, last, pred);
}

дизасмим, и...
Код

public sort
sort proc near
....
push    offset pred
add     eax, edx
push    eax
push    esi
push    edi
call    std___Sort_Foo___int_bool____cdecl___Foo_const___Foo_const____

ой, передача указателя...

а теперь лулзы:
Код

pred proc near

arg_0= dword ptr  8
arg_4= dword ptr  0Ch

push    ebp
mov     ebp, esp
mov     eax, [ebp+arg_0]
mov     ecx, [eax+18h]
mov     edx, [ebp+arg_4]
xor     eax, eax
cmp     ecx, [edx+18h]
setnle  al
pop     ebp
retn
pred endp

да... и вот эта _cdecl хрень вызывается на каждой итерации, с прологами, эпилогами....

пишем "inline bool pred(const Foo& a, const Foo& b)"...
... и ничего не происходит.

пишем "bool __fastcall pred(const Foo& a, const Foo& b)", и получаем
Код

pred proc near
mov     eax, [ecx+18h]
xor     ecx, ecx
cmp     eax, [edx+18h]
setnle  al
retn
pred endp

да, прологов\эпилогов нет, компилятор даже воткнул xor ecx, ecx чтобы спарить инструкции, но всеравно вызов функции на каждой итерации это дороговато, по сравнению с ее телом.
PM MAIL   Вверх
djamshud
Дата 24.8.2010, 13:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Пердупержденный
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 23.11.2009

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



Abyx,

>А я... а Я.... вы либо код показывайте, либо прекращайте сказки рассказывать %)

Хорошо, вечером я попробую найти сортировку, писанную мной года три-четыре назад чисто в академическом интересе, которая сильно нагибала std::sort и std::sort_как_его_там. Но вообще как я уже писал, считаю сортировку (в чистом виде!) мало применимой в реальном программировании. Что касается вектора, строки и списка - они в STL очень тупы даже несмотря на реализованый для них (в gcc) CoW. Но свои реализации сейчас выложить не могу, так что это пусть пока останется сказкой о силе.

Добавлено через 2 минуты
Abyx, эмм. Так мое предположение о вызовах функций таки подтвердилось? В gcc, я смотрел, на агрессивной оптимизации коллбеки разворачивались в инлайны.


--------------------
'Cuz I never walk away from what I know is right
Alice Cooper - Freedom
PM   Вверх
Abyx
Дата 24.8.2010, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



djamshud, да, я тоже счя смотрю гцц, там последний пример инлайнится. И у гцц вроде существенно меньше кода.
Хотя я хз хорошо или это или нет, надо замерить производительность.
PM MAIL   Вверх
Abyx
Дата 24.8.2010, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



не.. там все интереснее, у гцц. оно инлайнит, но не везде, о_О

coming soon в соседнем разделе
PM MAIL   Вверх
Abyx
Дата 24.8.2010, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



тот же код, скомпилированный gcc:
http://forum.vingrad.ru/index.php?showtopi...t&p=2202122

Это сообщение отредактировал(а) Abyx - 24.8.2010, 14:11
PM MAIL   Вверх
jonie
Дата 24.8.2010, 20:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 6
Всего: 118



у вас что-то тормозит или это просто преждевременная оптимизация?


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
Abyx
Дата 24.8.2010, 20:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



jonie, перечитайте тему, если не осилили.
PM MAIL   Вверх
ИванМ
Дата 24.8.2010, 21:23 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1260
Регистрация: 19.6.2006
Где: СПб

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



Цитата(Abyx @  24..8.2010,  11:31 Найти цитируемый пост)
Тема не предполагает какого-то обсуждения, просто примеры плохого кода генерируемого MSVC.

И в чем тогда смысл этого топика? Все знают, что VC плохой, g++ плохой, C++ Builder еще хуже, и что дальше? Люди пишут на них программы (причем, часто с использованием STL), они отлично работают и никто не жалуется.
Оптимизация ради оптимизации - это, ИМХО, дело людей, которые не создают реальных проектов.
PM MAIL   Вверх
Abyx
Дата 29.8.2010, 01:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Продолжаем.

Хвостовая рекурсия, оптимизируем по размеру.
Код

unsigned __fastcall calc_hash(const char* str, unsigned hash = 0)
{
    return *str ? calc_hash(str + 1, (hash + *str) * 7) : hash;
}

Код

.text:00401000 calc_hash       proc near               ; CODE XREF: calc_hash+13j
.text:00401000                                         ; main+30p ...
.text:00401000                 mov     al, [ecx]
.text:00401002                 push    esi
.text:00401003                 mov     esi, edx
.text:00401005                 test    al, al
.text:00401007                 jz      short loc_401018
.text:00401009                 movsx   edx, al
.text:0040100C                 add     edx, esi
.text:0040100E                 imul    edx, 7
.text:00401011                 inc     ecx
.text:00401012                 pop     esi
.text:00401013                 jmp     calc_hash
.text:00401018 ; ---------------------------------------------------------------------------
.text:00401018
.text:00401018 loc_401018:                             ; CODE XREF: calc_hash+7j
.text:00401018                 mov     eax, esi
.text:0040101A                 pop     esi
.text:0040101B                 retn
.text:0040101B calc_hash       endp

Если убрать __fastcall, код разрастется из за прологов\эпилогов и не будет разворачиваться.
Видим что присутствует лишняя работа с регистром esi.
Студия следует соглашениям вызова, и не хочет использовать другие регистры для предачи параметров.

Интересно то, что функция не инлайнится. Однако в месте вызова мы видим
Код

.text:004010B9                 mov     edx, 214h       ; 'L' * 7
.text:004010BE                 mov     ecx, (offset aLoadlibrarya+1)
.text:004010C3                 call    calc_hash

Т.е. первая итерация инлайнится, а остальные - нет.
PM MAIL   Вверх
icecrashldr
Дата 7.9.2010, 19:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Developer
*


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

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



Abyx, Посмотрите реализацию АПИ в kernel32.dll на Windows 7 вообще улыбает...
     Сохранения кадра стека.
      Перенаправления на kernelbase.dll

На самом деле все решает алгоритм, а не несколько инструкция(дажет если это 1000 инструкция или миллион, за частую это виду только в крипто алгоритмах).

PM MAIL WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




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


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

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