LINUX.ORG.RU

Локализовать гнилую оптимизацию

 ,


0

2

Привет, проблема в следующем - имеется проект, без оптимизаций всё нормально работает, с оптимизациями ГЦЦ выдаёт криво работающую поделку, шланг нормальную. Включил все возможные воринги - ничего серьёзного. Адресный санитайзер проблем не находит. -fsanitize=undefined - аналогично, но с ним ошибка пропадает и софтина работает годно.

Чувствую, что проблема в ГЦЦ, но как подступиться и состряпать баг репорт - не могу сообразить. Ну не слать же портянку в несколько К строк, кто там разбираться с ней будет. Можно ли ткнуть в какую-то сущность в коде и отседить производимые оптимизации над ней?

★★

дженерик апроач - смотреть асм код интересующего места с оптимизациями и без.

Keltir
()

без оптимизаций всё нормально работает, с оптимизациями ГЦЦ выдаёт криво работающую поделку, шланг нормальную. Включил все возможные воринги - ничего серьёзного. Адресный санитайзер проблем не находит. -fsanitize=undefined - аналогично, но с ним ошибка пропадает и софтина работает годно.

Чувствую, что проблема в ГЦЦ

Ну да, не с под-опциями же играть и уж точно не UB у себя искать.

t184256 ★★★★★
()
Ответ на: комментарий от kvpfs

Ну не слать же портянку в несколько К строк, кто там разбираться с ней будет.

А сколько строк после препроцессора? Тысяч 100 +- это норм. Может и будут разбираться. Это не так долго на самом деле…

fsb4000 ★★★★★
()

Локализуй место, где твоя поделка превращается в криво работающую и дебаж. Отладчиком или принтами например. Если поделка многопоточная, любое неловкое движение может переводить ее из состояния поделки в криво работающую поделку и наоборот. В том числе санитайзер.

filosofia
()

Включать оптимизации поименно пока не сломается, например, c и без -ffast-math.

Какие оптимизации включаются при -Ox можно посмотреть:

$ gcc -O3 -Q --help=optimizers
anonymous
()
Ответ на: комментарий от kvpfs

В баше можно например смотреть дифф:

$ diff -u <(gcc -O2 -Q --help=optimizers) <(gcc -O3 -Q --help=optimizers)
anonymous
()

Привет, проблема в следующем - имеется проект, без оптимизаций всё нормально работает, с оптимизациями ГЦЦ выдаёт криво работающую поделку, шланг нормальную.

  1. В чем заключается кривость и можно ли установить ее наличие автоматизированным тестом? Например, шелл-скриптом сверить результат с нужным или проверить упало или не упало.

  2. Есть ли понимание или подозрения, в каком именно месте кода происходит «неправильная оптимизация»?

Если ответ «да» на оба вопроса, то можно по стандартной инструкции https://gcc.gnu.org/wiki/A_guide_to_testcase_reduction получить минимальный тест-кейс. Но чтобы не получилась ерунда, нужно сначала определить, какой именно уровень оптмизации сбоит, например, в простейшем случае тест будет проверять, что с -O2 результат правильный, а с -O3 неправильный. Если так не делать, то в процессе минимизации в коде появятся UB и прочие радости, которые сделают его бесполезным. Лучше конечно перебором с осмысленным угадыванием отыскать конкретную опцию, меняющую поведение кода, и включать/выключать в тесте конкретно ее.

Если ответ «нет» на один из вопросов, то остается только дебажить получившийся бинарник до просветления, или сдаться и снизить уровень оптимизации. Более конкретные советы возможны только после ответа на то, в чем кривость.

annulen ★★★★★
()

локалилую говнокод у тебя

anonymous
()
Ответ на: комментарий от kvpfs

Eщё можно для отдельных функций включать/выключать оптимизации, смотри тут:

optimize

    The optimize attribute is used to specify that a function is to be compiled with different optimization options than specified on the command line. Arguments can either be numbers or strings. Numbers are assumed to be an optimization level. Strings that begin with O are assumed to be an optimization option, while other options are assumed to be used with a -f prefix. You can also use the `#pragma GCC optimize' pragma to set the optimization options that affect more than one function. See Function Specific Option Pragmas, for details about the `#pragma GCC optimize' pragma. 
shkolnick-kun ★★★★★
()
Ответ на: комментарий от annulen

В чем заключается кривость и можно ли установить ее наличие автоматизированным тестом?

Неправильно отрисовываются граф элемент на экране. Никаких сегфолтов и подобного.

kvpfs ★★
() автор топика

Спасибо. Пока найду оптимизацию, отпишусь. Забить и компилить без оптимизаций не выйдет - либа, выпустить такой кусок Г - не вариант.

kvpfs ★★
() автор топика

-fsanitize=undefined - аналогично, но с ним ошибка пропадает и софтина работает годно.

$ diff -U0 <(gcc -O2 -Q --help=optimizers -fsanitize=undefined) <(gcc -O2 -Q --help=optimizers)
--- /dev/fd/63	2021-08-09 19:16:13.984633084 +0300
+++ /dev/fd/62	2021-08-09 19:16:13.986633063 +0300
@@ -6 +6 @@
-  -faggressive-loop-optimizations 	[disabled]
+  -faggressive-loop-optimizations 	[enabled]
@@ -37 +37 @@
-  -fdelete-null-pointer-checks 		[disabled]
+  -fdelete-null-pointer-checks 		[enabled]
anonymous
()

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

недавно вот пропустил возврат инта из функции… от которой даже реально результат то не брали… так прога падала, то ли с оптимизацией, то ли без. вот не помню. ну естесно посмотрел по варнингам, увидел, поправил и все стало нормально

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 2)

Gdb watchpoints помогут пока стек цел. Но стек тоже можно глянуть когда переписывается если аккуратно

pon4ik ★★★★★
()
Ответ на: комментарий от kvpfs

Неправильно отрисовываются граф элемент на экране. Никаких сегфолтов и подобного.

Можно попробовать собирать собирать по одному файлу в проекте без оптимизации до тех пор, пока не найдется «сбойный», проверять вручную. Если файлов много, то бинарный поиск: собрать половину проекта без оптимизаций, сбойную половину делить дальше и т.д.

annulen ★★★★★
()
Ответ на: комментарий от alysnix

недавно вот пропустил возврат инта из функции… от которой даже реально результат то не брали…

Частая ошибка, с -Werror=return-type надо все собирать

annulen ★★★★★
()
Ответ на: комментарий от annulen

Частая ошибка, с -Werror=return-type надо все собирать

варнинг то был, просто его просмотрели, в куче других неопасных варнингов.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Варнинги либо все выпиливаются, и после этого все собирается с -Werror, либо их регулярно просматривают в куче других. А -Werror=return-type это беспроигрышный вариант.

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от kvpfs

Или натыкать дебагов в код, который рисует неправильный элемент, дальше разобраться, из какой функции приходят неправильные координаты (смотря что там происходит).

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от alysnix

невозврат результата из функции, неинициализированная переменная

это ловится -fsanitize=undefined

anonymous
()

нельзя комментировать удаленные комментарии

Крутить по одной оптимизации тоже может на что-то навести, но их много. А вот более гранулярно выключать -fsanitize=undefined и выяснить, от чего именно твоё «нет у меня там никакого УБ» начнет рассыпаться тебе гордость не позволяет? Куда быстрее ж будет.

t184256 ★★★★★
()

Проблема в твоём коде. Приведи проблему к юнит-тесту, потом убирай куски своего кода, чтобы локализовать проблему в нескольких десятках строк. Скорей всего там и найдёшь её. Ну или таки сможешь составить баг в gcc, на который кто-нибудь посмотрит.

Legioner ★★★★★
()
Ответ на: комментарий от kvpfs

Забить и компилить без оптимизаций не выйдет

Иногда замороченные участки помогает найти pmccabe. Пример: Opustags (комментарий)

anonymous
()

Да, я сам накосячил - был массив, я инициализировал лишь тот кусок, что вмещается на экран. Черех Х времени благополучно забыл о том, какой я умный и какой хитрый фокус провернул ), а влияние -faggressive-loop-optimizations на результат окончательно запутало.

Спасибо за ответы.

kvpfs ★★
() автор топика
Ответ на: комментарий от sniper21

Прогнал код с ней - не, не находит проблем. Наверное, следует вводить в свою практику какие-то обёртки, которые будут выражать задумку через некоторое время в будущем, partly_initalized, например. Без всякиех там проверок, просто обозначить идею, вроде not_null (как пример простой обёртки, противоположность тем переусложненным вариантам, которые ходят по сети)

template <typename T>
	requires std::is_pointer_v<T>
	using not_null = T;
kvpfs ★★
() автор топика
Последнее исправление: kvpfs (всего исправлений: 1)
Ответ на: комментарий от alysnix

неверный порядок статической инициализации,

Это ворнинги не пишут.

недавно вот пропустил возврат инта из функции… от которой даже реально результат то не брали… так прога падала, то ли с оптимизацией, то ли без.

Та ж хрень, -O2. :)

dimgel ★★★★★
()
Ответ на: комментарий от safocl

так у тебя си++ — есть же std::array и std::vector — они вроде помогают недопустить такой ошибки.

Каким образом?

anonymous
()

Начать стоит с -Werror

andreyu ★★★★★
()
Ответ на: комментарий от Andrey_Karpov_2020
struct Column_properties
{
	color_e clr;             // enum
	alignment_e alignment;   // enum
	cursor_pos_t cursor_pos; // typedef
};

template <std::size_t column_number>
bool Highlevel_rendering<column_number>::f_draw_body()
{
	...
	int beg_col = m_context->m_draw_start.m_column;
	int end_col = m_render->f_calc_end_column(
			m_context->m_draw_start.m_column, m_row_image);
	...
	std::array<Column_properties, column_number> props;
	auto set_props = [this, &props, beg_col, end_col](ssize_t i) {
		bool selected = m_context->m_selected.contains(i);
		for (ssize_t ppos = beg_col;  ppos < end_col;  ++ppos) {
			bool cursor_field = i == m_context->m_pointer_pos.m_row  &&
				ppos == m_context->m_pointer_pos.m_column;
			if (selected) {
				if (cursor_field)
					props[ppos].clr = e_text_select_cusor;
				else
					props[ppos].clr = e_text_select;
			}
			else if (cursor_field)
				props[ppos].clr = e_text_cusor;
			else
				props[ppos].clr = e_text;
			props[ppos].alignment = m_alignment;
			props[ppos].cursor_pos =
				(m_cursor_loc == cursor_location_e::active_field && cursor_field)
				?  m_cursor_pos : no_cursor_pos;
		}
	};

	for (ssize_t i = m_context->m_draw_start.m_row;
			i != end_row;  i += add) {
		...
		set_props(i);
		...
	}
	...
}

Я через PVS не смотрел, может он чего бы и нашёл. На мой взгляд пожаловаться можно на то что дефолтно инициализированный props из trivial constructable типа получает значение в цикле for (ssize_t ppos = beg_col; ppos < end_col; ++ppos), в котором beg_col и end_col приходят из рантайма, т.е. не проверишь границы.

kvpfs ★★
() автор топика
Последнее исправление: kvpfs (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.