LinuxCon Europe 2013 - О поиске "гонок" в ядре Linux
м (оформление) |
|||
Строка 3: | Строка 3: | ||
22 октября состоялось [http://linuxconcloudopeneu2013.sched.org/event/918f111663374602fe344259b188d807 выступление] нашего сотрудника Евгения Шатохина на конференции LinuxCon Europe 2013. Речь шла о средствах поиска таких трудноуловимых ошибок, как [http://ru.wikipedia.org/wiki/Race_condition «состояния гонки»], они же [http://en.wikipedia.org/wiki/Race_condition «data races»] в компонентах ядра Linux ([http://cdn.2safe.com/153759033759/LinuxCon_2013-Shatokhin-v03.pdf слайды], [http://cdn.2safe.com/200700033759/speaker_notes.odt пояснения к слайдам]). | 22 октября состоялось [http://linuxconcloudopeneu2013.sched.org/event/918f111663374602fe344259b188d807 выступление] нашего сотрудника Евгения Шатохина на конференции LinuxCon Europe 2013. Речь шла о средствах поиска таких трудноуловимых ошибок, как [http://ru.wikipedia.org/wiki/Race_condition «состояния гонки»], они же [http://en.wikipedia.org/wiki/Race_condition «data races»] в компонентах ядра Linux ([http://cdn.2safe.com/153759033759/LinuxCon_2013-Shatokhin-v03.pdf слайды], [http://cdn.2safe.com/200700033759/speaker_notes.odt пояснения к слайдам]). | ||
− | [[File:LinuxConEurope2013_Races.jpg|right|384px]] По одному из определений, ''data race'' | + | [[File:LinuxConEurope2013_Races.jpg|right|384px]] По одному из определений, ''data race'' — это такая ситуация, когда два или более потока выполнения (''threads'') одновременно обращаются к одной и той же области памяти и хотя бы один из этих потоков что-то записывает в эту область памяти. |
− | Такие ситуации далеко не всегда просто выявить, а последствия у них могут быть самыми разными, от незначительных до критических. Для ядра Linux это особенно актуально: код драйверов, например, может выполняться многими потоками одновременно. Добавим к этому обработку прерываний и других асинхронных событий, а также учтём, что правила синхронизации доступа к общим данным из разных потоков далеко не всегда описаны чётко (а нередко | + | Такие ситуации далеко не всегда просто выявить, а последствия у них могут быть самыми разными, от незначительных до критических. Для ядра Linux это особенно актуально: код драйверов, например, может выполняться многими потоками одновременно. Добавим к этому обработку прерываний и других асинхронных событий, а также учтём, что правила синхронизации доступа к общим данным из разных потоков далеко не всегда описаны чётко (а нередко — не описаны вообще)… |
− | Об инструментах, позволяющих выявлять data races в компонентах ядра Linux, в основном, и шла речь в выступлении. Наиболее подробно | + | Об инструментах, позволяющих выявлять data races в компонентах ядра Linux, в основном, и шла речь в выступлении. Наиболее подробно — о системах [http://code.google.com/p/kernel-strider/ KernelStrider] и [https://github.com/winnukem/racehound RaceHound], одним из основных разработчиков которых Евгений и является. |
− | KernelStrider собирает информацию об анализируемом компоненте ядра (например, драйвере) в процессе работы этого компонента. Информация об обращениях к памяти, выделении и освобождении памяти, блокировках и т.д. затем, уже в user space, анализируется инструментом [http://code.google.com/p/data-race-test/ ThreadSanitizer] (Google). Алгоритм поиска races коротко описан [http://code.google.com/p/data-race-test/wiki/ThreadSanitizerAlgorithm тут]. | + | <tt>KernelStrider</tt> собирает информацию об анализируемом компоненте ядра (например, драйвере) в процессе работы этого компонента. Информация об обращениях к памяти, выделении и освобождении памяти, блокировках и т. д. затем, уже в user space, анализируется инструментом [http://code.google.com/p/data-race-test/ ThreadSanitizer] (Google). Алгоритм поиска races коротко описан [http://code.google.com/p/data-race-test/wiki/ThreadSanitizerAlgorithm тут]. |
KernelStrider может в некоторых случаях выдавать сообщения о data races там, где data races нет («false positives»). Например, при анализе сетевых драйверов такое было в случаях, когда драйвер отключал генерацию прерываний соотв. устройством и затем обращался к каким-то общим данным, не опасаясь конфликтов с функцией-обработчиком прерываний. | KernelStrider может в некоторых случаях выдавать сообщения о data races там, где data races нет («false positives»). Например, при анализе сетевых драйверов такое было в случаях, когда драйвер отключал генерацию прерываний соотв. устройством и затем обращался к каким-то общим данным, не опасаясь конфликтов с функцией-обработчиком прерываний. | ||
− | Система [https://github.com/winnukem/racehound RaceHound] позволяет проверить результаты, полученные с помощью KernelStrider, найти среди них те, которые, действительно | + | Система [https://github.com/winnukem/racehound RaceHound] позволяет проверить результаты, полученные с помощью KernelStrider, найти среди них те, которые, действительно говорят о data races. RaceHound работает так: |
* На инструкцию в коде ядра, которая может быть «замешана» в data race, ставится программная точка прерывания («software breakpoint»). | * На инструкцию в коде ядра, которая может быть «замешана» в data race, ставится программная точка прерывания («software breakpoint»). | ||
Строка 20: | Строка 20: | ||
* Если во время задержки какой-то другой поток обратится к указанной области памяти, аппаратная точка прерывания сработает и RaceHound сообщит о найденной data race. | * Если во время задержки какой-то другой поток обратится к указанной области памяти, аппаратная точка прерывания сработает и RaceHound сообщит о найденной data race. | ||
− | + | То есть при анализе компонентов ядра KernelStrider работает своего рода «детективом-аналитиком», сужая круг «подозреваемых» — мест в коде, которые могут участвовать в data races. RaceHound тогда — система слежки за этими подозреваемыми. Если ей удаётся поймать подозреваемого с поличным (то есть при выполнении конфликтующих доступов к памяти) — всё ясно. Если не удаётся — это ничего не значит. | |
Как во время, так и после доклада, вопросов было довольно много. Слушателей интересовали, например, такие вещи, как: | Как во время, так и после доклада, вопросов было довольно много. Слушателей интересовали, например, такие вещи, как: | ||
− | * Планируется ли поддержка ARM (пока всё работает только на x86), | + | * Планируется ли поддержка ARM (пока всё работает только на x86), — ''возможно, но не в ближайшем будущем''. |
− | * Может ли KernelStrider пропускать data races ( | + | * Может ли KernelStrider пропускать data races (то есть возможны ли false negatives) — ''да, может в некоторых случаях, в основном, из-за особенностей [http://code.google.com/p/data-race-test/wiki/ThreadSanitizerAlgorithm алгоритма работы ThreadSanitizer] и из-за неточностей используемых правил определения порядка событий''. |
− | * Переживает ли KernelStrider suspend/resume | + | * Переживает ли KernelStrider suspend/resume — ''да, переживает''. |
− | * Можно ли с помощью KernelStrider и RaceHound анализировать не только модули ядра, но и само ядро | + | * Можно ли с помощью KernelStrider и RaceHound анализировать не только модули ядра, но и само ядро — ''пока нет''. |
− | * Можно ли в KernelStrider инструментировать код анализируемого драйвера не при загрузке этого драйвера, как сейчас, а при компиляции | + | * Можно ли в KernelStrider инструментировать код анализируемого драйвера не при загрузке этого драйвера, как сейчас, а при компиляции — ''очень вероятно; это одно из возможных направлений развития''. |
− | * и т.д. | + | * и т. д. |
− | В обсуждении data races, найденных указанными выше инструментами, активно участвовали сотрудники Intel, что немудрено: речь шла о [http://sourceforge.net/mailarchive/message.php?msg_id=31245543 races в сетевом драйвере e1000], разработанном как раз в этой компании. Во время обсуждения выяснился интересный факт: для обращений к памяти в некоторых частях сетевых драйверов средства синхронизации использовать почему-то не принято, хотя там из-за этого могут быть | + | В обсуждении data races, найденных указанными выше инструментами, активно участвовали сотрудники Intel, что немудрено: речь шла о [http://sourceforge.net/mailarchive/message.php?msg_id=31245543 races в сетевом драйвере e1000], разработанном как раз в этой компании. Во время обсуждения выяснился интересный факт: для обращений к памяти в некоторых частях сетевых драйверов средства синхронизации использовать почему-то не принято, хотя там из-за этого могут быть «гонки» (они там и обнаружились). Это, в частности, относится к NAPI и функциям драйвера, участвующим в передаче данных по сети. Вроде бы всё так делается, чтобы избежать потерь производительности из-за блокировок, но ни оценок этих потерь, ни конкретных рекомендаций, как при этом избежать проблем из-за «гонок», пока найти не удалось. |
В целом, похоже, что отношение к data races у многих разработчиков ядра такое: | В целом, похоже, что отношение к data races у многих разработчиков ядра такое: | ||
<blockquote> | <blockquote> | ||
− | + | — Что-то из-за этой data race упало или стало работать неправильно? | |
− | + | — Пока не замечали. | |
− | + | — А, ну, ладно. | |
</blockquote> | </blockquote> | ||
− | И на этом разговор кончается. | + | И на этом разговор кончается. |
− | Логично? Вроде бы да, но, если вспомнить, например, [https://www.usenix.org/legacy/event/hotpar11/tech/final_files/Boehm.pdf вот эту статью], всё уже не так очевидно. | + | Логично? Вроде бы да, но, если вспомнить, например, [https://www.usenix.org/legacy/event/hotpar11/tech/final_files/Boehm.pdf вот эту статью], всё уже не так очевидно. |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
[[Category:ToROSAPoint]] | [[Category:ToROSAPoint]] | ||
{{wl-publish: 2013-10-29 13:15:07 +0400 | Eugene.shatokhin }} | {{wl-publish: 2013-10-29 13:15:07 +0400 | Eugene.shatokhin }} |
Текущая версия на 16:12, 29 октября 2013
22 октября состоялось выступление нашего сотрудника Евгения Шатохина на конференции LinuxCon Europe 2013. Речь шла о средствах поиска таких трудноуловимых ошибок, как «состояния гонки», они же «data races» в компонентах ядра Linux (слайды, пояснения к слайдам).
Такие ситуации далеко не всегда просто выявить, а последствия у них могут быть самыми разными, от незначительных до критических. Для ядра Linux это особенно актуально: код драйверов, например, может выполняться многими потоками одновременно. Добавим к этому обработку прерываний и других асинхронных событий, а также учтём, что правила синхронизации доступа к общим данным из разных потоков далеко не всегда описаны чётко (а нередко — не описаны вообще)…
Об инструментах, позволяющих выявлять data races в компонентах ядра Linux, в основном, и шла речь в выступлении. Наиболее подробно — о системах KernelStrider и RaceHound, одним из основных разработчиков которых Евгений и является.
KernelStrider собирает информацию об анализируемом компоненте ядра (например, драйвере) в процессе работы этого компонента. Информация об обращениях к памяти, выделении и освобождении памяти, блокировках и т. д. затем, уже в user space, анализируется инструментом ThreadSanitizer (Google). Алгоритм поиска races коротко описан тут.
KernelStrider может в некоторых случаях выдавать сообщения о data races там, где data races нет («false positives»). Например, при анализе сетевых драйверов такое было в случаях, когда драйвер отключал генерацию прерываний соотв. устройством и затем обращался к каким-то общим данным, не опасаясь конфликтов с функцией-обработчиком прерываний.
Система RaceHound позволяет проверить результаты, полученные с помощью KernelStrider, найти среди них те, которые, действительно говорят о data races. RaceHound работает так:
- На инструкцию в коде ядра, которая может быть «замешана» в data race, ставится программная точка прерывания («software breakpoint»).
- Когда эта точка прерывания срабатывает, RaceHound определяет адрес области памяти, куда эта инструкция обратится, и ставит аппаратную точку прерывания («hardware breakpoint»), чтобы отследить обращения нужного вида к этой области (только запись или произвольные обращения).
- Делается небольшая задержка перед выполнением интересующей инструкции.
- Если во время задержки какой-то другой поток обратится к указанной области памяти, аппаратная точка прерывания сработает и RaceHound сообщит о найденной data race.
То есть при анализе компонентов ядра KernelStrider работает своего рода «детективом-аналитиком», сужая круг «подозреваемых» — мест в коде, которые могут участвовать в data races. RaceHound тогда — система слежки за этими подозреваемыми. Если ей удаётся поймать подозреваемого с поличным (то есть при выполнении конфликтующих доступов к памяти) — всё ясно. Если не удаётся — это ничего не значит.
Как во время, так и после доклада, вопросов было довольно много. Слушателей интересовали, например, такие вещи, как:
- Планируется ли поддержка ARM (пока всё работает только на x86), — возможно, но не в ближайшем будущем.
- Может ли KernelStrider пропускать data races (то есть возможны ли false negatives) — да, может в некоторых случаях, в основном, из-за особенностей алгоритма работы ThreadSanitizer и из-за неточностей используемых правил определения порядка событий.
- Переживает ли KernelStrider suspend/resume — да, переживает.
- Можно ли с помощью KernelStrider и RaceHound анализировать не только модули ядра, но и само ядро — пока нет.
- Можно ли в KernelStrider инструментировать код анализируемого драйвера не при загрузке этого драйвера, как сейчас, а при компиляции — очень вероятно; это одно из возможных направлений развития.
- и т. д.
В обсуждении data races, найденных указанными выше инструментами, активно участвовали сотрудники Intel, что немудрено: речь шла о races в сетевом драйвере e1000, разработанном как раз в этой компании. Во время обсуждения выяснился интересный факт: для обращений к памяти в некоторых частях сетевых драйверов средства синхронизации использовать почему-то не принято, хотя там из-за этого могут быть «гонки» (они там и обнаружились). Это, в частности, относится к NAPI и функциям драйвера, участвующим в передаче данных по сети. Вроде бы всё так делается, чтобы избежать потерь производительности из-за блокировок, но ни оценок этих потерь, ни конкретных рекомендаций, как при этом избежать проблем из-за «гонок», пока найти не удалось.
В целом, похоже, что отношение к data races у многих разработчиков ядра такое:
— Что-то из-за этой data race упало или стало работать неправильно?
— Пока не замечали.
— А, ну, ладно.
И на этом разговор кончается.
Логично? Вроде бы да, но, если вспомнить, например, вот эту статью, всё уже не так очевидно.
[ Хронологический вид ]Комментарии
Понятно что в сетевых никто и не будет сделать за этим - если гонки заложены в основу сетевых алгоритмов и лечатся банальным реконнектом, то смысл?
Речь идёт об обращениях к внутренним структурам драйвера, а тут всё не так очевидно. Например, в одном из случаев, о котором я писал интеловцам, были одновременные обращений к переменной, в которой хранится текущее количество пакетов в очереди передачи (Tx queue). Один thread читал эту переменную, другой в то же время увеличивал её значение на 1. Может, это и не приведёт в данном случае к неприятностям, но, как минимум, тут надо разобраться.
Вот описание этой "гонки", если интересно: http://sourceforge.net/mailarchive/message.php?msg_id=31452821 (самое первое в списке).
Войдите, чтобы комментировать.