Сообщение Re[12]: оффтоп+volatile от 14.09.2009 15:26
Изменено 17.05.2015 13:43 netch80
+ gcc asm memory clobber
Здравствуйте, ДимДимыч, Вы писали:
N>>какой "дефолт" вызвала всего лишь попытка перейти на GCC 4.4
ДД>Так GCC 4.4 уже под GPLv3 идет, разве не этот факт вызвал "дефолт"?
Нет, речь о другом. Linux ломается с каждой новой версией, потому что что-то в мелочах меняется (чаще всего стили оптимизации), но в случае 4.4 количество поломок было особенно крупным.
Я разверну мысль из предыдущих сообщений. Отсутствие volatile склоняет компилятор к возможности оптимизировать доступ к переменной его кэшированием (прочитать или записать меньшее количество раз, чем надо), но есть чёткие границы, через которые он не переходит. Это границы тел функций (не в случае инлайнинга) и границы — вызовы функций, но второе — только если он гарантированно не может сам понять, что происходит в этой функции.
Представим себе систему с кооперативной многозадачностью, когда запрет переключения реализуется глобальной переменной. Если установка и снятие такого "лока" сделано напрямую в функции, то компилятор вполне вероятно захочет это оптимизировать. Это код следующего вида:
тут компилятор захочет оптимизировать и наверняка это сделает — именно foo ничем не защищено против этого.
А вот тут мы ему явно ставим барьер:
Главное здесь — чтобы компилятор при сборке данного модуля _не знал_, что такое эти lock_scheduler() и unlock_scheduler(), или для них была явная метка "что-то меняют, а что — ХЗ" (как в asm volatile). Тогда компилятор остережётся кэшировать foo — он не знает, менялось оно в этих вызовах или нет. Незнание реализуется ссылкой на другой модуль и его отделённой компиляцией.
Именно это и является той защитой, которая не позволяет коду в Linux сходить с ума и которая работает и против gcc, и вообще против любого нормального компилятора. И, как видим, в том тексте про это — ни слова. Есть, однако, одна фраза про "it acts as a memory barrier", но она неоднозначна: понятие memory barrier давно закреплено за другим явлением — средствами предотвращения нежелательного переупорядочения операций процессора. И при этом не сказано, что защитой против оптимизации компилятором является любая функция неизвестного компилятору смысла, а не только функции работы с семафорами и спинлоками (хотя именно эти содержат полный комплект необходимых защит, не только против компиляторной оптимизации).
Ну а почему я это связал с версией gcc — потому что качество кода и качество документации тут примерно одинаково по сути, а именно — резко неровно. Рядом с идеальным результатом может находиться кусок гнилого бреда. На что собственно и нарвались в обоих случаях.
Фух... надеюсь, теперь понятно.;)
N>>какой "дефолт" вызвала всего лишь попытка перейти на GCC 4.4
ДД>Так GCC 4.4 уже под GPLv3 идет, разве не этот факт вызвал "дефолт"?
Нет, речь о другом. Linux ломается с каждой новой версией, потому что что-то в мелочах меняется (чаще всего стили оптимизации), но в случае 4.4 количество поломок было особенно крупным.
Я разверну мысль из предыдущих сообщений. Отсутствие volatile склоняет компилятор к возможности оптимизировать доступ к переменной его кэшированием (прочитать или записать меньшее количество раз, чем надо), но есть чёткие границы, через которые он не переходит. Это границы тел функций (не в случае инлайнинга) и границы — вызовы функций, но второе — только если он гарантированно не может сам понять, что происходит в этой функции.
Представим себе систему с кооперативной многозадачностью, когда запрет переключения реализуется глобальной переменной. Если установка и снятие такого "лока" сделано напрямую в функции, то компилятор вполне вероятно захочет это оптимизировать. Это код следующего вида:
extern volatile nosched;
...
foo = 1;
nosched = 0; // разрешили переключение
*bar = 1; // что-то снаружи стронули и возможно нам дали другие данные
nosched = 1; // запретили переключение - работаем с данными
if (foo != 3) {
...
}тут компилятор захочет оптимизировать и наверняка это сделает — именно foo ничем не защищено против этого.
А вот тут мы ему явно ставим барьер:
foo = 1;
unlock_scheduler();
*bar = 1;
lock_scheduler();
if (foo != 3) {
...
}Главное здесь — чтобы компилятор при сборке данного модуля _не знал_, что такое эти lock_scheduler() и unlock_scheduler(), или для них была явная метка "что-то меняют, а что — ХЗ" (как в asm volatile). Тогда компилятор остережётся кэшировать foo — он не знает, менялось оно в этих вызовах или нет. Незнание реализуется ссылкой на другой модуль и его отделённой компиляцией.
Именно это и является той защитой, которая не позволяет коду в Linux сходить с ума и которая работает и против gcc, и вообще против любого нормального компилятора. И, как видим, в том тексте про это — ни слова. Есть, однако, одна фраза про "it acts as a memory barrier", но она неоднозначна: понятие memory barrier давно закреплено за другим явлением — средствами предотвращения нежелательного переупорядочения операций процессора. И при этом не сказано, что защитой против оптимизации компилятором является любая функция неизвестного компилятору смысла, а не только функции работы с семафорами и спинлоками (хотя именно эти содержат полный комплект необходимых защит, не только против компиляторной оптимизации).
Ну а почему я это связал с версией gcc — потому что качество кода и качество документации тут примерно одинаково по сути, а именно — резко неровно. Рядом с идеальным результатом может находиться кусок гнилого бреда. На что собственно и нарвались в обоих случаях.
Фух... надеюсь, теперь понятно.;)
Re[12]: оффтоп+volatile
Здравствуйте, ДимДимыч, Вы писали:
N>>какой "дефолт" вызвала всего лишь попытка перейти на GCC 4.4
ДД>Так GCC 4.4 уже под GPLv3 идет, разве не этот факт вызвал "дефолт"?
Нет, речь о другом. Linux ломается с каждой новой версией, потому что что-то в мелочах меняется (чаще всего стили оптимизации), но в случае 4.4 количество поломок было особенно крупным.
Я разверну мысль из предыдущих сообщений. Отсутствие volatile склоняет компилятор к возможности оптимизировать доступ к переменной его кэшированием (прочитать или записать меньшее количество раз, чем надо), но есть чёткие границы, через которые он не переходит. Это границы тел функций (не в случае инлайнинга) и границы — вызовы функций, но второе — только если он гарантированно не может сам понять, что происходит в этой функции.
Представим себе систему с кооперативной многозадачностью, когда запрет переключения реализуется глобальной переменной. Если установка и снятие такого "лока" сделано напрямую в функции, то компилятор вполне вероятно захочет это оптимизировать. Это код следующего вида:
тут компилятор захочет оптимизировать и наверняка это сделает — именно foo ничем не защищено против этого.
А вот тут мы ему явно ставим барьер:
Главное здесь — чтобы компилятор при сборке данного модуля _не знал_, что такое эти lock_scheduler() и unlock_scheduler(), или для них была явная метка "что-то меняют, а что — ХЗ" (как в asm volatile). Тогда компилятор остережётся кэшировать foo — он не знает, менялось оно в этих вызовах или нет. Незнание реализуется ссылкой на другой модуль и его отделённой компиляцией.
(UPDATE: ещё штатный метод для gcc:
— явное указание, что встраиваемый код изменил содержимое памяти и нельзя через его границу оптимизировать доступ. Должны быть аналоги для других компиляторов.)
Именно это и является той защитой, которая не позволяет коду в Linux сходить с ума и которая работает и против gcc, и вообще против любого нормального компилятора. И, как видим, в том тексте про это — ни слова. Есть, однако, одна фраза про "it acts as a memory barrier", но она неоднозначна: понятие memory barrier давно закреплено за другим явлением — средствами предотвращения нежелательного переупорядочения операций процессора. И при этом не сказано, что защитой против оптимизации компилятором является любая функция неизвестного компилятору смысла, а не только функции работы с семафорами и спинлоками (хотя именно эти содержат полный комплект необходимых защит, не только против компиляторной оптимизации).
Ну а почему я это связал с версией gcc — потому что качество кода и качество документации тут примерно одинаково по сути, а именно — резко неровно. Рядом с идеальным результатом может находиться кусок гнилого бреда. На что собственно и нарвались в обоих случаях.
Фух... надеюсь, теперь понятно.;)
N>>какой "дефолт" вызвала всего лишь попытка перейти на GCC 4.4
ДД>Так GCC 4.4 уже под GPLv3 идет, разве не этот факт вызвал "дефолт"?
Нет, речь о другом. Linux ломается с каждой новой версией, потому что что-то в мелочах меняется (чаще всего стили оптимизации), но в случае 4.4 количество поломок было особенно крупным.
Я разверну мысль из предыдущих сообщений. Отсутствие volatile склоняет компилятор к возможности оптимизировать доступ к переменной его кэшированием (прочитать или записать меньшее количество раз, чем надо), но есть чёткие границы, через которые он не переходит. Это границы тел функций (не в случае инлайнинга) и границы — вызовы функций, но второе — только если он гарантированно не может сам понять, что происходит в этой функции.
Представим себе систему с кооперативной многозадачностью, когда запрет переключения реализуется глобальной переменной. Если установка и снятие такого "лока" сделано напрямую в функции, то компилятор вполне вероятно захочет это оптимизировать. Это код следующего вида:
extern volatile nosched;
...
foo = 1;
nosched = 0; // разрешили переключение
*bar = 1; // что-то снаружи стронули и возможно нам дали другие данные
nosched = 1; // запретили переключение - работаем с данными
if (foo != 3) {
...
}тут компилятор захочет оптимизировать и наверняка это сделает — именно foo ничем не защищено против этого.
А вот тут мы ему явно ставим барьер:
foo = 1;
unlock_scheduler();
*bar = 1;
lock_scheduler();
if (foo != 3) {
...
}Главное здесь — чтобы компилятор при сборке данного модуля _не знал_, что такое эти lock_scheduler() и unlock_scheduler(), или для них была явная метка "что-то меняют, а что — ХЗ" (как в asm volatile). Тогда компилятор остережётся кэшировать foo — он не знает, менялось оно в этих вызовах или нет. Незнание реализуется ссылкой на другой модуль и его отделённой компиляцией.
(UPDATE: ещё штатный метод для gcc:
asm volatile("":::"memory")— явное указание, что встраиваемый код изменил содержимое памяти и нельзя через его границу оптимизировать доступ. Должны быть аналоги для других компиляторов.)
Именно это и является той защитой, которая не позволяет коду в Linux сходить с ума и которая работает и против gcc, и вообще против любого нормального компилятора. И, как видим, в том тексте про это — ни слова. Есть, однако, одна фраза про "it acts as a memory barrier", но она неоднозначна: понятие memory barrier давно закреплено за другим явлением — средствами предотвращения нежелательного переупорядочения операций процессора. И при этом не сказано, что защитой против оптимизации компилятором является любая функция неизвестного компилятору смысла, а не только функции работы с семафорами и спинлоками (хотя именно эти содержат полный комплект необходимых защит, не только против компиляторной оптимизации).
Ну а почему я это связал с версией gcc — потому что качество кода и качество документации тут примерно одинаково по сути, а именно — резко неровно. Рядом с идеальным результатом может находиться кусок гнилого бреда. На что собственно и нарвались в обоих случаях.
Фух... надеюсь, теперь понятно.;)