Версия для печати темы
Форум разработчиков электроники ELECTRONIX.ru _ Программирование _ VC2015 и VC2010. Файл вырастает в 3,5раза
Автор: megajohn Jul 31 2018, 04:57
Добрый день
вот такой вопрос, есть проект для VC2010, на выходе файл 182k
тот же самый проект, скомпиленный в VC2015 дает файл 614k
посему немного вопросов для тех, кто разбирается в тонкостях линковки:
- каким софтом можно узнать, что же так разрослось ?
- так как конечный результат хочу выложить в свободный доступ для желающих, то какой вариант выкладывать ?
вот эти файлики, если вдруг кому-то проще посмотреть
prj_VC2010_vs_VC2015.ZIP ( 347.36 килобайт )
: 13
Автор: Forger Jul 31 2018, 07:01
Цитата(megajohn @ Jul 31 2018, 07:57)
Добрый день
вот такой вопрос, есть проект для VC2010, на выходе файл 182k
тот же самый проект, скомпиленный в VC2015 дает файл 614k
Очевидно, что в более новой среде используются более "свежие" библиотеки.
Возможно, в чем-то отличаются ключи компиляции и линковки.
зы. Стоит ли того эта "мышиная возня"? Ведь оба этих файла легко уместятся даже на архаичную дискету, даже на античную 5-дюймовую, которые нынче можно найти лишь в музеях
Автор: megajohn Jul 31 2018, 07:55
Кэп, просто человеческое любопытство, не более чем.
Ну раз нет так нет
Автор: mantech Jul 31 2018, 08:27
Цитата(megajohn @ Jul 31 2018, 10:55)
Кэп, просто человеческое любопытство, не более чем.
Ну раз нет так нет
Все, как должно быть, программы больше, диски тоже, скорости по сети аналогично... Вы все должны вносить вклад в развитие потребкультуры, в соответствии с политикой
партии заокеанских буржуев
ЗЫ. Вы заметили, насколько больше стал дистрибутив 15 студии от 10 ?? Вот похоже и на выхлопе прямая зависимость...
Автор: jcxz Jul 31 2018, 08:28
Это "нормально". Компилю сейчас под VS2017 проект, тот же проект скомпилённый VS2005 - даёт примерно в 4.5 раза меньший exe-ник. И это при полной оптимизации.
Такова уж нынешняя тенденция - ресурсов становится больше, значит их надо сожрать.
Автор: Forger Jul 31 2018, 09:55
Цитата(megajohn @ Jul 31 2018, 10:55)
Кэп
Кэп, есть более подходящие ресурсы для того, чтобы задавать подобные необычные вопросы по VS -
там наверняка найдутся гики, которые готовы удавиться ради нескольких лишних килобайтов в exe-ке
Цитата(jcxz @ Jul 31 2018, 11:28)
Такова уж нынешняя тенденция - ресурсов становится больше, значит их надо сожрать.
в новой stdlib банальный printf теперь умеет выводить строку через встроенный vpn-сервер и на гугль-облако
Автор: jcxz Jul 31 2018, 10:15
Цитата(Forger @ Jul 31 2018, 12:55)
в новой stdlib банальный printf теперь умеет выводить строку через встроенный vpn-сервер и на гугль-облако
И что? Я это не использую. А значит линкёр должен это выкидывать из exe.
Автор: Forger Jul 31 2018, 10:20
Цитата(jcxz @ Jul 31 2018, 13:15)
И что? Я это не использую. А значит линкёр должен это выкидывать из exe.
Это нормальный линкер так делает, а тут по-ходу как "звезды лягут"
Автор: x893 Jul 31 2018, 10:36
Соберите из консоли с map файлом.
И изучайте.
Автор: jcxz Jul 31 2018, 11:27
Цитата(Forger @ Jul 31 2018, 13:20)
Это нормальный линкер так делает, а тут по-ходу как "звезды лягут"
Там не только линкёр, а и компилятор - туповатые. Даже в VS2017
на полной оптимизации что творит:
Код
; 397 : nv0 = chain[0]->nv;
mov eax, DWORD PTR [edi+104]
mov eax, DWORD PTR [eax+4]
mov DWORD PTR [edi+4], eax
; 398 : fmtn0 = chain[0]->fmt[ixf0 = chain[0]->ixf].n;
mov eax, DWORD PTR [edi+104]
mov ecx, DWORD PTR [eax+8]
mov DWORD PTR [edi+8], ecx
add ecx, ecx
mov eax, DWORD PTR [edi+104]
mov eax, DWORD PTR [eax+ecx*8+24]
mov DWORD PTR [edi+12], eax
где chain - массив указателей на структуры.
Вместо того, чтобы использовать значение указателя chain[0] ранее загруженное в регистр, зачем-то постоянно перечитывает его из памяти (DWORD PTR [edi+104]). volatile нет.
Даже IAR в этом случае использовал бы копию указателя из регистра, имхо.
Автор: Forger Jul 31 2018, 11:52
Цитата(jcxz @ Jul 31 2018, 14:27)
Там не только линкёр, а и компилятор - туповатые.
А предыдущие версии VS тоже такую дичь плодят?
Автор: jcxz Jul 31 2018, 12:07
Цитата(Forger @ Jul 31 2018, 14:52)
А предыдущие версии VS тоже такую дичь плодят?
Не знаю. Надо будет дома на VS2005 проверить. На работе VS2005 уже не ставится на win64
((
Автор: Forger Jul 31 2018, 12:20
Цитата(jcxz @ Jul 31 2018, 15:07)
На работе VS2005 уже не ставится на win64
((
Виртуалка в помощь
Автор: gte Jul 31 2018, 12:42
Цитата(Forger @ Jul 31 2018, 16:20)
Виртуалка в помощь
Кстати. Вопрос ко всем. Может кто нибудь выложить образ или CRC образа winXP для VirtualBox который раздавался с сайта Майкрософт? Сейчас там только win7x32.
Автор: DASM Jul 31 2018, 19:14
Цитата(gte @ Jul 31 2018, 15:42)
Кстати. Вопрос ко всем. Может кто нибудь выложить образ или CRC образа winXP для VirtualBox который раздавался с сайта Майкрософт? Сейчас там только win7x32.
Оно?
Цитата(jcxz @ Jul 31 2018, 14:27)
Там не только линкёр, а и компилятор - туповатые. Даже в VS2017
на полной оптимизации что творит:
Код
; 397 : nv0 = chain[0]->nv;
mov eax, DWORD PTR [edi+104]
mov eax, DWORD PTR [eax+4]
mov DWORD PTR [edi+4], eax
; 398 : fmtn0 = chain[0]->fmt[ixf0 = chain[0]->ixf].n;
mov eax, DWORD PTR [edi+104]
mov ecx, DWORD PTR [eax+8]
mov DWORD PTR [edi+8], ecx
add ecx, ecx
mov eax, DWORD PTR [edi+104]
mov eax, DWORD PTR [eax+ecx*8+24]
mov DWORD PTR [edi+12], eax
где chain - массив указателей на структуры.
Вместо того, чтобы использовать значение указателя chain[0] ранее загруженное в регистр, зачем-то постоянно перечитывает его из памяти (DWORD PTR [edi+104]). volatile нет.
Даже IAR в этом случае использовал бы копию указателя из регистра, имхо.
это не оптимизация. Можно код исходный?
Автор: jcxz Aug 1 2018, 08:57
Цитата(DASM @ Jul 31 2018, 22:14)
это не оптимизация. Можно код исходный?
Оптимизация
....так как с выключением оной там становится ещё страшнее.
Исходный? Я же листинг привёл с включением исходных строк.
Цитата(jcxz @ Jul 31 2018, 15:07)
Не знаю. Надо будет дома на VS2005 проверить. На работе VS2005 уже не ставится на win64
((
Проверить дома пока не получается - дома +30 и выше - в такой жаре и комп включать не охота.
Автор: DASM Aug 1 2018, 09:27
определения типов , входящих в эти строки можно? что то додумывать не хочется
Автор: jcxz Aug 1 2018, 09:41
Цитата(DASM @ Aug 1 2018, 12:27)
определения типов , входящих в эти строки можно? что то додумывать не хочется
Код
struct OscRaw {
uint chainN; //кол-во не-NULL указателей chain
uint nv0, ixf0, nvf0; //соответственно chain[0].nv, chain[0].ixf и chain[0].fmt[ixf].n на момент защёлкивания Get()
FILETIME timestamp; //временная метка последних принятых данных
char timestampOk; //!=0 - timestamp валидно
uint oscsrcNV[OSCSRC_n]; //кол-во векторов по каждому источнику осц. непрерывным участком от самого нового вектора до ближайшего разрыва по данному источнику
HCOsc *chain[OSC_BRING_N]; //массив блоков данных векторов осц. (каждый имеет заголовок HCOsc)
TIPCALL OscRaw() { ZeroMemory(this, sizeof(*this)); }
TIPCALL OscRaw(OscRaw const &src) { ZeroMemory(this, sizeof(*this)); *this = src; }
TIPCALL ~OscRaw() { Destroy(); }
void TIPCALL Get();
void TIPCALL Destroy();
OscRaw & operator =(OscRaw const &);
};
struct HCOsc {
long volatile use; //кол-во пользователей данного элемента (кол-во link-ов на него)
uint volatile nv; //кол-во векторов в данном элементе
uint ixf; //индекс последнего записанного элемента fmt (кол-во_записанных_элементов_fmt - 1)
struct Format {
u64 map; //бит-карта источников осц. для n векторов
uint n; //кол-во векторов осц. которые соответствуют карте map
uint TIPCALL GetVktOffs(uint) const;
} fmt[64]; //список описателей формата векторов в данном элементе HCOsc
void TIPCALL Delete() { if (!InterlockedDecrement(&use)) delete this; }
};
А приведённый кусок кода - это участок результата компиляции OscRaw::Get():
Код
void TIPCALL OscRaw::Get()
{
HCOsc *p, **pb = &chain[0];
...
if (chainN = n) {
nv0 = (p = chain[0])->nv;
nvf0 = p->fmt[ixf0 = p->ixf].n;
}
timestamp = ::timestamp;
timestampOk = ::timestampOk;
memcpy(oscsrcNV, (void *)&::oscsrcNV[0], sizeof(oscsrcNV));
LeaveCriticalSection(&csb);
}
Как видите - volatile в данных местах нету.
PS: Копирование в промежуточную переменную
p = chain[0] это уже я позже добавил. В таком варианте эти лишние чтения указателя уже пропадают.
Т.е. - компилятор почему-то сам не догадывается так сделать (сохранить chain[0] в регистре), но если ему явно указать на это, поместив указатель в отдельную переменную (p), то p он уже оптимизирует в регистр.
По идее - раз массив chain указан без volatile, то значит не имеет side effects, а значит его члены можно перемещать куда угодно и создавать сколько угодно копий.
Автор: DASM Aug 1 2018, 10:13
if (chainN = n) не компилится, это не член OscRaw
Автор: jcxz Aug 1 2018, 10:16
Цитата(DASM @ Aug 1 2018, 13:13)
if (chainN = n) не компилится, это не член OscRaw
В смысле? Посмотрите на первую строчку объявления OscRaw.
Думаете я листинг сам руками рисовал, чтобы всех в заблуждение ввести?
Автор: DASM Aug 1 2018, 10:18
где там n?
Автор: jcxz Aug 1 2018, 10:22
Цитата(DASM @ Aug 1 2018, 13:18)
где там n?
"..." ни о чём не говорит? Подумайте. Естественно не относящийся к теме код поскипан.
n вычисляется кодом ранее. Потом заносится в chainN. Могли бы догадаться.
Да и зачем вам оно?
Автор: DASM Aug 1 2018, 10:24
ну а вдруг. Догадаться не могу, тупой я.
Автор: XVR Aug 1 2018, 11:33
Цитата(jcxz @ Aug 1 2018, 12:41)
PS: Копирование в промежуточную переменную p = chain[0] это уже я позже добавил. В таком варианте эти лишние чтения указателя уже пропадают.
Т.е. - компилятор почему-то сам не догадывается так сделать (сохранить chain[0] в регистре)
Он не может. У вас там присваивания в поля структуры OscRaw (nv0 и nvf0). Для компилятора это запись в память. Видимо анализ указателей у VC хромает (или выключен), и он считает, что эта запись потенциально может попасть в любой глобальный объект (ч том числе и в те, к которым обращаются через указатель). Поэтому содержимое chain может измениться (с точки зрения компилятора).
Цитата
но если ему явно указать на это, поместив указатель в отдельную переменную (p), то p он уже оптимизирует в регистр.
тут вы взяли отвественность на себя, явно переместив значение в локальную переменную. Для неё pointer анализ говорит, что она ни с какими указателями не пересекается.
Цитата
По идее - раз массив chain указан без volatile, то значит не имеет side effects, а значит его члены можно перемещать куда угодно и создавать сколько угодно копий.
Нет. В массив могут записать 'сбоку' (не через указатель на него).
Автор: jcxz Aug 1 2018, 12:12
Цитата(XVR @ Aug 1 2018, 14:33)
Нет. В массив могут записать 'сбоку' (не через указатель на него).
Мне кажется странными если оптимизатор делает такие предположения.
Вставил этот код в IAR, вот что он выдал:
Код
86 nv0 = chain[0]->nv;
\ 00000004 0x6A41 LDR R1,[R0, #+36];1-е чтение chain[0]
\ 00000006 0x684A LDR R2,[R1, #+4] ;чтение chain[0]->nv
\ 00000008 0x6042 STR R2,[R0, #+4] ;запись nv0
87 nvf0 = chain[0]->fmt[ixf0 = chain[0]->ixf].n;
\ 0000000A 0x6889 LDR R1,[R1, #+8] ;чтение chain[0]->ixf
\ 0000000C 0x6A42 LDR R2,[R0, #+36];3-е чтение chain[0]
\ 0000000E 0x6081 STR R1,[R0, #+8] ;запись ixf0
\ 00000010 0xEB02 0x1101 ADD R1,R2,R1, LSL #+4
\ 00000014 0x6989 LDR R1,[R1, #+24] ;чтение chain[0]->fmt[ixf0].n
\ 00000016 0x60C1 STR R1,[R0, #+12] ;запись nvf0
Как видно - IAR так не предполагает: он выкинул 2-е чтение chain[0] из памяти, использовав старое значение в регистре, хоть перед этим и была запись в память.
3-е чтение он правда оставил, хотя мог бы тоже использовать если-б не разрушил его перед тем.
Более того - он и 3-е чтение расположил до записи ixf0, хотя если следовать Вашей логике не должен был этого делать. Так что на возможности затирания записями ему наплевать, так как: side effects - это забота программиста.
Автор: XVR Aug 1 2018, 15:43
Цитата(jcxz @ Aug 1 2018, 15:12)
Более того - он и 3-е чтение расположил до записи ixf0, хотя если следовать Вашей логике не должен был этого делать. Так что на возможности затирания записями ему наплевать
Он не прав
Цитата
, так как: side effects - это забота программиста.
Это не так. Если в программе нет того, что называется undefined behavior, то разница в её поведении на разных уровнях оптимизации - это ошибка компилятора.
Другое дело, что оптимизатор в VC всегда не являлся сильным местом компилятора. Нормальный оптимизатор в состоянии разобраться (или предположить, если ему пользователь скажет), могут указатели пересекаться или нет.
Попробуйте собрать программу с опцией 'Full program optimization' (или как она там называется). Ещё можно попробовать сделать поля в nv0 и nvf0 другого размера (была такая опция - ansi alias. Она предполагала, что типизированные указатели на память не могут пересекаться, если они указывают на типы, несовместимые по прямому присваиванию. Не знаю, есть ли оно в VC, но всё может быть)
Автор: Gate Aug 1 2018, 15:53
Мне кажется, здесь объяснено поведение компилятора http://electronix.ru/redirect.php?https://m.habr.com/post/114117/
Автор: XVR Aug 1 2018, 15:57
Используйте спецификатор __restrict
Автор: jcxz Aug 1 2018, 16:03
Цитата(XVR @ Aug 1 2018, 18:43)
Это не так. Если в программе нет того, что называется undefined behavior, то разница в её поведении на разных уровнях оптимизации - это ошибка компилятора.
Программа и не ведёт себя по-разному на разных уровнях. Багов нет. Есть неоптимальность.
Цитата(XVR @ Aug 1 2018, 18:43)
Попробуйте собрать программу с опцией 'Full program optimization' (или как она там называется).
У меня и стоит максимальная оптимизация какая только возможно.
PS: Ладно - интерес был скорее академический. Проблем со скоростью/размером нет.
Автор: DASM Aug 1 2018, 16:13
Не не, сливаться не стоит. О restrict точно вспомнили, может попробуете с ним?
Автор: jcxz Aug 1 2018, 17:15
Цитата(DASM @ Aug 1 2018, 19:13)
Не не, сливаться не стоит. О restrict точно вспомнили, может попробуете с ним?
restrict я использовал в CCS, разве в VS он есть?
Автор: XVR Aug 2 2018, 06:32
Цитата(jcxz @ Aug 1 2018, 20:15)
restrict я использовал в CCS, разве в VS он есть?
Есть. Только с двумя подчеркиваниями спререди (т.к. restrict ключевое слово С99, но не С++. Для С++ это расширение)
Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)