Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: VC2015 и VC2010. Файл вырастает в 3,5раза
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
megajohn
Добрый день
вот такой вопрос, есть проект для VC2010, на выходе файл 182k
тот же самый проект, скомпиленный в VC2015 дает файл 614k

посему немного вопросов для тех, кто разбирается в тонкостях линковки:
- каким софтом можно узнать, что же так разрослось ?
- так как конечный результат хочу выложить в свободный доступ для желающих, то какой вариант выкладывать ?

вот эти файлики, если вдруг кому-то проще посмотреть
Нажмите для просмотра прикрепленного файла
Forger
Цитата(megajohn @ Jul 31 2018, 07:57) *
Добрый день
вот такой вопрос, есть проект для VC2010, на выходе файл 182k
тот же самый проект, скомпиленный в VC2015 дает файл 614k

Очевидно, что в более новой среде используются более "свежие" библиотеки.
Возможно, в чем-то отличаются ключи компиляции и линковки.

зы. Стоит ли того эта "мышиная возня"? Ведь оба этих файла легко уместятся даже на архаичную дискету, даже на античную 5-дюймовую, которые нынче можно найти лишь в музеях biggrin.gif


megajohn
Кэп, просто человеческое любопытство, не более чем.
Ну раз нет так нет
mantech
Цитата(megajohn @ Jul 31 2018, 10:55) *
Кэп, просто человеческое любопытство, не более чем.
Ну раз нет так нет

Все, как должно быть, программы больше, диски тоже, скорости по сети аналогично... Вы все должны вносить вклад в развитие потребкультуры, в соответствии с политикой партии заокеанских буржуев biggrin.gif

ЗЫ. Вы заметили, насколько больше стал дистрибутив 15 студии от 10 ?? Вот похоже и на выхлопе прямая зависимость...
jcxz
Это "нормально". Компилю сейчас под VS2017 проект, тот же проект скомпилённый VS2005 - даёт примерно в 4.5 раза меньший exe-ник. И это при полной оптимизации.
Такова уж нынешняя тенденция - ресурсов становится больше, значит их надо сожрать. sad.gif
Forger
Цитата(megajohn @ Jul 31 2018, 10:55) *
Кэп
Кэп, есть более подходящие ресурсы для того, чтобы задавать подобные необычные вопросы по VS -
там наверняка найдутся гики, которые готовы удавиться ради нескольких лишних килобайтов в exe-ке wink.gif

Цитата(jcxz @ Jul 31 2018, 11:28) *
Такова уж нынешняя тенденция - ресурсов становится больше, значит их надо сожрать. sad.gif

в новой stdlib банальный printf теперь умеет выводить строку через встроенный vpn-сервер и на гугль-облако biggrin.gif
jcxz
Цитата(Forger @ Jul 31 2018, 12:55) *
в новой stdlib банальный printf теперь умеет выводить строку через встроенный vpn-сервер и на гугль-облако biggrin.gif

И что? Я это не использую. А значит линкёр должен это выкидывать из exe.
Forger
Цитата(jcxz @ Jul 31 2018, 13:15) *
И что? Я это не использую. А значит линкёр должен это выкидывать из exe.

Это нормальный линкер так делает, а тут по-ходу как "звезды лягут" sm.gif
x893
Соберите из консоли с map файлом.
И изучайте.
jcxz
Цитата(Forger @ Jul 31 2018, 13:20) *
Это нормальный линкер так делает, а тут по-ходу как "звезды лягут" sm.gif

Там не только линкёр, а и компилятор - туповатые. Даже в 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
Цитата(jcxz @ Jul 31 2018, 14:27) *
Там не только линкёр, а и компилятор - туповатые.

А предыдущие версии VS тоже такую дичь плодят?
jcxz
Цитата(Forger @ Jul 31 2018, 14:52) *
А предыдущие версии VS тоже такую дичь плодят?

Не знаю. Надо будет дома на VS2005 проверить. На работе VS2005 уже не ставится на win64 sad.gif((
Forger
Цитата(jcxz @ Jul 31 2018, 15:07) *
На работе VS2005 уже не ставится на win64 sad.gif((

Виртуалка в помощь sm.gif
gte
Цитата(Forger @ Jul 31 2018, 16:20) *
Виртуалка в помощь sm.gif

Кстати. Вопрос ко всем. Может кто нибудь выложить образ или CRC образа winXP для VirtualBox который раздавался с сайта Майкрософт? Сейчас там только win7x32.
DASM
Цитата(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
Цитата(DASM @ Jul 31 2018, 22:14) *
это не оптимизация. Можно код исходный?

Оптимизация wink.gif ....так как с выключением оной там становится ещё страшнее. smile3046.gif
Исходный? Я же листинг привёл с включением исходных строк.

Цитата(jcxz @ Jul 31 2018, 15:07) *
Не знаю. Надо будет дома на VS2005 проверить. На работе VS2005 уже не ставится на win64 sad.gif((

Проверить дома пока не получается - дома +30 и выше - в такой жаре и комп включать не охота. 05.gif
DASM
определения типов , входящих в эти строки можно? что то додумывать не хочется
jcxz
Цитата(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
if (chainN = n) не компилится, это не член OscRaw
jcxz
Цитата(DASM @ Aug 1 2018, 13:13) *
if (chainN = n) не компилится, это не член OscRaw

В смысле? Посмотрите на первую строчку объявления OscRaw.
Думаете я листинг сам руками рисовал, чтобы всех в заблуждение ввести? biggrin.gif
DASM
где там n?
jcxz
Цитата(DASM @ Aug 1 2018, 13:18) *
где там n?

"..." ни о чём не говорит? Подумайте. Естественно не относящийся к теме код поскипан.
n вычисляется кодом ранее. Потом заносится в chainN. Могли бы догадаться.
Да и зачем вам оно?
DASM
ну а вдруг. Догадаться не могу, тупой я.
XVR
Цитата(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
Цитата(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
Цитата(jcxz @ Aug 1 2018, 15:12) *
Более того - он и 3-е чтение расположил до записи ixf0, хотя если следовать Вашей логике не должен был этого делать. Так что на возможности затирания записями ему наплевать
Он не прав sm.gif

Цитата
, так как: side effects - это забота программиста.
Это не так. Если в программе нет того, что называется undefined behavior, то разница в её поведении на разных уровнях оптимизации - это ошибка компилятора.

Другое дело, что оптимизатор в VC всегда не являлся сильным местом компилятора. Нормальный оптимизатор в состоянии разобраться (или предположить, если ему пользователь скажет), могут указатели пересекаться или нет.
Попробуйте собрать программу с опцией 'Full program optimization' (или как она там называется). Ещё можно попробовать сделать поля в nv0 и nvf0 другого размера (была такая опция - ansi alias. Она предполагала, что типизированные указатели на память не могут пересекаться, если они указывают на типы, несовместимые по прямому присваиванию. Не знаю, есть ли оно в VC, но всё может быть)

Gate
Мне кажется, здесь объяснено поведение компилятора https://m.habr.com/post/114117/
XVR
Используйте спецификатор __restrict
jcxz
Цитата(XVR @ Aug 1 2018, 18:43) *
Это не так. Если в программе нет того, что называется undefined behavior, то разница в её поведении на разных уровнях оптимизации - это ошибка компилятора.

Программа и не ведёт себя по-разному на разных уровнях. Багов нет. Есть неоптимальность.

Цитата(XVR @ Aug 1 2018, 18:43) *
Попробуйте собрать программу с опцией 'Full program optimization' (или как она там называется).

У меня и стоит максимальная оптимизация какая только возможно.

PS: Ладно - интерес был скорее академический. Проблем со скоростью/размером нет.
DASM
Не не, сливаться не стоит. О restrict точно вспомнили, может попробуете с ним?
jcxz
Цитата(DASM @ Aug 1 2018, 19:13) *
Не не, сливаться не стоит. О restrict точно вспомнили, может попробуете с ним?

restrict я использовал в CCS, разве в VS он есть?
XVR
Цитата(jcxz @ Aug 1 2018, 20:15) *
restrict я использовал в CCS, разве в VS он есть?
Есть. Только с двумя подчеркиваниями спререди (т.к. restrict ключевое слово С99, но не С++. Для С++ это расширение)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.