Зачастую, знакомство с алиасингом в C++ у многих программистов начинается и заканчивается одинаково: -fno-strict-aliasing. На вопросы новичка, более опытные коллеги отвечают в стиле: «не трогай! а то все сломаешь!». Новичок и не трогает. В докладе будет предпринята попытка заглянуть под капот и понять, что же там, внутри. Что такое алиасинг, где он может быть полезен и какие реальные преимущества дает. Тема будет рассмотрена и со стороны программиста и со стороны разработчика компилятора. А по сему, вопрос «зачем?» будет центральным в повествовании.
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
В последнее время в промышленной разработке ПО особую популярность обретают Domain-Specific Lanugages (DSL). Они драматически упрощают разработку и дают возможность “программировать” не только программистам, но и пользователям прикладных программ.
В своем докладе я расскажу об опыте использования DSL применительно к С++, причем упор будет сделан на производительность кода DSL, и его мгновенную “встраиваемость” в запущенную программу путем компиляции DSL-кода в нативный код с помощью инструментария LLVM.
В рамках данного выступления вас ждут:
* рассказ о полезных и интересных вещах из Boost
* новости с передовиц разработки Boost и о новинках ожидаемых в следующих версиях
* что из Boost готовится к переезду в новый стандарт С++
* как экспериментировать с Boost, имея под рукой только браузер
* что людям не нравится в Boost и как с этими людьми бороться (-:
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
В докладе перед нами откроется великолепный мир велосипедов и устаревших технологий, которые люди продолжают переносить в новые проекты и повсеместно использовать. Мы поговорим о:
Copy-On-Write
разработке без оглядки на готовые решения и к чему это приводит
force inline
оптимизациях, которые отлично себя показывают на бенчмарках и плохо себя ведут в реальной жизни
бездумно отключаемых оптимизациях компилятора
тонкостях стандартной библиотеки для повседневного использования
супер качественном велосипедостроении
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияPlatonov Sergey
В этом докладе Дмитрий кратко рассказывает о таком звере, как LLVM, о котором много кто слышал, но немногие щупали.
Что такое компилятор на самом деле? Как происходит компиляция программы, как работают оптимизации и, наконец, откуда берется неопределенное поведение в детерменированных программах на C++?
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
Практика показывает, что использование подхода, основанного на колбеках для асинхронного программирования обычно не является удобным и подвержено различным ошибкам. Для упрощения написания и поддержки сложных асинхронных программ можно использовать несколько иной подход: использовать сопрограммы для переключения контекста на время ожидания события. Такой подход позволяет реализовать интересные неблокирующие примитивы, включая неблокирующее сетевое взаимодействие, неблокирующие мьютексы, а также удобное переключение между различными пулами потоков для разнесения выполнения задач, которые требуют различные ресурсы.
ЛЕКЦИЯ 8. Многопоточное программирование без использования блокировок. Модель потребитель-производитель. Потокобезопасный стек. Проблема ABA. Указатели опасности.
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Догнать и перегнать boost::lexical_castRoman Orlov
Разбор нестандартной реализации преобразования целого числа в строку без использования циклов и рекурсивных вызовов времени исполнения - только рекурсия на этапе компиляции
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
В последнее время в промышленной разработке ПО особую популярность обретают Domain-Specific Lanugages (DSL). Они драматически упрощают разработку и дают возможность “программировать” не только программистам, но и пользователям прикладных программ.
В своем докладе я расскажу об опыте использования DSL применительно к С++, причем упор будет сделан на производительность кода DSL, и его мгновенную “встраиваемость” в запущенную программу путем компиляции DSL-кода в нативный код с помощью инструментария LLVM.
В рамках данного выступления вас ждут:
* рассказ о полезных и интересных вещах из Boost
* новости с передовиц разработки Boost и о новинках ожидаемых в следующих версиях
* что из Boost готовится к переезду в новый стандарт С++
* как экспериментировать с Boost, имея под рукой только браузер
* что людям не нравится в Boost и как с этими людьми бороться (-:
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
В докладе перед нами откроется великолепный мир велосипедов и устаревших технологий, которые люди продолжают переносить в новые проекты и повсеместно использовать. Мы поговорим о:
Copy-On-Write
разработке без оглядки на готовые решения и к чему это приводит
force inline
оптимизациях, которые отлично себя показывают на бенчмарках и плохо себя ведут в реальной жизни
бездумно отключаемых оптимизациях компилятора
тонкостях стандартной библиотеки для повседневного использования
супер качественном велосипедостроении
Дракон в мешке: от LLVM к C++ и проблемам неопределенного поведенияPlatonov Sergey
В этом докладе Дмитрий кратко рассказывает о таком звере, как LLVM, о котором много кто слышал, но немногие щупали.
Что такое компилятор на самом деле? Как происходит компиляция программы, как работают оптимизации и, наконец, откуда берется неопределенное поведение в детерменированных программах на C++?
Григорий Демченко, Асинхронность и неблокирующая синхронизацияSergey Platonov
Практика показывает, что использование подхода, основанного на колбеках для асинхронного программирования обычно не является удобным и подвержено различным ошибкам. Для упрощения написания и поддержки сложных асинхронных программ можно использовать несколько иной подход: использовать сопрограммы для переключения контекста на время ожидания события. Такой подход позволяет реализовать интересные неблокирующие примитивы, включая неблокирующее сетевое взаимодействие, неблокирующие мьютексы, а также удобное переключение между различными пулами потоков для разнесения выполнения задач, которые требуют различные ресурсы.
ЛЕКЦИЯ 8. Многопоточное программирование без использования блокировок. Модель потребитель-производитель. Потокобезопасный стек. Проблема ABA. Указатели опасности.
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Догнать и перегнать boost::lexical_castRoman Orlov
Разбор нестандартной реализации преобразования целого числа в строку без использования циклов и рекурсивных вызовов времени исполнения - только рекурсия на этапе компиляции
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Yandex
Основываясь на опыте разработки Крипты, Дмитрий рассмотрит средства реализации статического и динамического полиморфизма в C++, а также некоторые их паттерны и антипаттерны.
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
Флеш-накопители используются в самых разных устройствах, от мобильных телефонов до компьютеров и серверов. Для каждой модели накопителя нужна прошивка с определённым набором параметров, которые могут отличаться в зависимости от ситуации. В докладе будет описан универсальный фреймфорк на С++, который предоставляет разработчикам симуляторов простой, прозрачный и быстрый доступ к любому параметру. Тестировщикам же он позволяет управлять конфигурациями при помощи стандартных инструментов редактирования и слияния.
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
ЛЕКЦИЯ 6. Атомарные операции. Внеочередное выполнение инструкций. Барьеры памяти. Семантика захвата-освобождения. Модель памяти C++
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
ЛЕКЦИЯ 5. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 3. Реентерабельность. Сигналы. Локальные данные потоков. Принудительное завершение потоков
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Доклад Кулагина И.И., Пазникова А.А., Курносова М.Г. "Оптимизация информационных обменов в параллельных PGAS-программах" на 3-й Всероссийской научно-технической конференции «Суперкомпьютерные технологии» (СКТ-2014)
29 сентября – 4 октября 2014 г., с. Дивноморское
В третьей главе рассматриваются базовые свойства акторов, описанные в PhD диссертации Gul Agha: каждый актор имеет адрес, большой почтовый ящик, куда доставляются сообщения, адресованные актору и поведение. В ответ на входящее сообщение актор может отправить конечный набор сообщений другим акторам и/или создать конечное число новых акторов и/или поменять свое поведение для обработки следующего сообщения.
В рамках данного курса будет разработана библиотека для разработки параллельных приложений на платформе .NET, построенная по модели акторов.
Исходные коды библиотеки будут выкладываться на GitHub: https://github.com/hwdtech/HWdTech.DS
Код библиотеки будет разработан с использованием следующих принципов, приемов и методик:
S.O.L.I.D. - принципы
Unit-tests
Mock
IoC контейнеры
Для удобства слушателей курса краткий обзор данных практик приведен в Главе 4.
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
ЛЕКЦИЯ 5. Многопоточное программирование в языке С++. Работа с потоками. Защита данных. Синхронизация. Будущие результаты
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
ЛЕКЦИЯ 4. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
Одной из проблем C++ является большое количество конструкций, поведение которых не определено или просто неожиданно для программиста. С такими ошибками мы часто сталкиваемся при разработке статического анализатора кода. Но, как известно, лучше всего находить ошибки ещё на этапе компиляции. На этом докладе мы поговорим о том, какие техники из современного C++ позволяют писать не только более простой и выразительный, но и безопасный код. Вы увидите ошибки в коде различных Open Source проектов и узнаете, как можно их избежать, используя новые стандарты
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
В докладе рассмотрены подходы к созданию надежных юнит-тестов, которые просты в поддержке и модернизации, а также принципы создания кода пригодного для покрытия автотестами. Приведены два способа внедрения зависимости: с использованием конструктора тестируемого объекта, а также с использованием подхода "выделить и переопределить". Каждый из способов разобран на примере, демонстрирующем особенности его реализации и применения. Приведен ряд практических советов, нацеленных на создание надежных юнит-тестов. Использование на практике приведенных подходов и принципов позволяет упростить процесс поддержки и модификации существующего кода, а также дает уверенность в надежности работы добавляемого нового функционала. В конечном итоге это приводит к повышению качества разрабатываемого продукта.
Причины потерь процессорного времени при организации последовательности вычислений внутри потока: 1. Ожидание ответа на запрос (поток спит). 2. Выполнение дополнительных "лишних" действий. Как способ устранения этих потерь - паттерн Пул потоков. Анализ императивного и функционального подхода к борьбе с "жадными" операциями. Эволюция методов организации параллельных вычислений на основе пула потоков.
ЛЕКЦИЯ 7. Многопоточное программирование без блокировок. Модель потребитель-производитель. Потокобезопасный стек: проблема ABA, указатели опасности, сборщики мусора, счётчик ссылок, применение модели памяти С++.
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Модель памяти C++ - Андрей Янковский, ЯндексYandex
В докладе Андрей расскажет о моделях памяти различных процессоров, о тонкостях реализации неблокирующих алгоритмов и о том, какое отношение всё это имеет к С++.
В докладе будут сделаны попытки ответить на вопросы, какой тип скрывается под маской auto, почему T&& не всегда rvalue, и почему move ничего не двигает.
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...Alexey Paznikov
ЛЕКЦИЯ 2. POSIX Threads. Жизненный цикл потоков. Планирование. Синхронизация
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
http://techtalks.nsu.ru
Видеозапись: http://www.youtube.com/watch?v=v7uBLSm6ft8
06 октября 2015. Как приручить дракона: введение в LLVM (Дмитрий Кашицын, HDsoft)
«В этом докладе мы кратко расскажем о таком звере, о котором много кто слышал, но немногие щупали. Что такое компилятор на самом деле? Чем LLVM отличается от других компиляторов? Как в LLVM происходит компиляция программы, как работают оптимизации? Наконец, какой путь проходит программа от разбора исходного текста до генерации исполняемого файла?
Лекция будет обзорной и не потребует от слушателей глубоких знаний теории компиляторов.»
Лекция прочитана в рамках проекта Tech Talks @NSU – серии открытых лекций о разработке ПО и карьере в IT, проводимых в Новосибирском государственном университете.
Подробности: http://techtalks.nsu.ru
Некоторые паттерны реализации полиморфного поведения в C++ – Дмитрий Леванов,...Yandex
Основываясь на опыте разработки Крипты, Дмитрий рассмотрит средства реализации статического и динамического полиморфизма в C++, а также некоторые их паттерны и антипаттерны.
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
Флеш-накопители используются в самых разных устройствах, от мобильных телефонов до компьютеров и серверов. Для каждой модели накопителя нужна прошивка с определённым набором параметров, которые могут отличаться в зависимости от ситуации. В докладе будет описан универсальный фреймфорк на С++, который предоставляет разработчикам симуляторов простой, прозрачный и быстрый доступ к любому параметру. Тестировщикам же он позволяет управлять конфигурациями при помощи стандартных инструментов редактирования и слияния.
ПВТ - осень 2014 - Лекция 6 - Атомарные операции. Внеочередное выполнение инс...Alexey Paznikov
ЛЕКЦИЯ 6. Атомарные операции. Внеочередное выполнение инструкций. Барьеры памяти. Семантика захвата-освобождения. Модель памяти C++
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
ЛЕКЦИЯ 5. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
ЛЕКЦИЯ 3. Реентерабельность. Сигналы. Локальные данные потоков. Принудительное завершение потоков
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Доклад Кулагина И.И., Пазникова А.А., Курносова М.Г. "Оптимизация информационных обменов в параллельных PGAS-программах" на 3-й Всероссийской научно-технической конференции «Суперкомпьютерные технологии» (СКТ-2014)
29 сентября – 4 октября 2014 г., с. Дивноморское
В третьей главе рассматриваются базовые свойства акторов, описанные в PhD диссертации Gul Agha: каждый актор имеет адрес, большой почтовый ящик, куда доставляются сообщения, адресованные актору и поведение. В ответ на входящее сообщение актор может отправить конечный набор сообщений другим акторам и/или создать конечное число новых акторов и/или поменять свое поведение для обработки следующего сообщения.
В рамках данного курса будет разработана библиотека для разработки параллельных приложений на платформе .NET, построенная по модели акторов.
Исходные коды библиотеки будут выкладываться на GitHub: https://github.com/hwdtech/HWdTech.DS
Код библиотеки будет разработан с использованием следующих принципов, приемов и методик:
S.O.L.I.D. - принципы
Unit-tests
Mock
IoC контейнеры
Для удобства слушателей курса краткий обзор данных практик приведен в Главе 4.
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
ЛЕКЦИЯ 5. Многопоточное программирование в языке С++. Работа с потоками. Защита данных. Синхронизация. Будущие результаты
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
ЛЕКЦИЯ 4. Шаблоны многопоточного программирования
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Павел Беликов, Как избежать ошибок, используя современный C++Sergey Platonov
Одной из проблем C++ является большое количество конструкций, поведение которых не определено или просто неожиданно для программиста. С такими ошибками мы часто сталкиваемся при разработке статического анализатора кода. Но, как известно, лучше всего находить ошибки ещё на этапе компиляции. На этом докладе мы поговорим о том, какие техники из современного C++ позволяют писать не только более простой и выразительный, но и безопасный код. Вы увидите ошибки в коде различных Open Source проектов и узнаете, как можно их избежать, используя новые стандарты
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
В докладе рассмотрены подходы к созданию надежных юнит-тестов, которые просты в поддержке и модернизации, а также принципы создания кода пригодного для покрытия автотестами. Приведены два способа внедрения зависимости: с использованием конструктора тестируемого объекта, а также с использованием подхода "выделить и переопределить". Каждый из способов разобран на примере, демонстрирующем особенности его реализации и применения. Приведен ряд практических советов, нацеленных на создание надежных юнит-тестов. Использование на практике приведенных подходов и принципов позволяет упростить процесс поддержки и модификации существующего кода, а также дает уверенность в надежности работы добавляемого нового функционала. В конечном итоге это приводит к повышению качества разрабатываемого продукта.
Причины потерь процессорного времени при организации последовательности вычислений внутри потока: 1. Ожидание ответа на запрос (поток спит). 2. Выполнение дополнительных "лишних" действий. Как способ устранения этих потерь - паттерн Пул потоков. Анализ императивного и функционального подхода к борьбе с "жадными" операциями. Эволюция методов организации параллельных вычислений на основе пула потоков.
ЛЕКЦИЯ 7. Многопоточное программирование без блокировок. Модель потребитель-производитель. Потокобезопасный стек: проблема ABA, указатели опасности, сборщики мусора, счётчик ссылок, применение модели памяти С++.
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Модель памяти C++ - Андрей Янковский, ЯндексYandex
В докладе Андрей расскажет о моделях памяти различных процессоров, о тонкостях реализации неблокирующих алгоритмов и о том, какое отношение всё это имеет к С++.
В докладе будут сделаны попытки ответить на вопросы, какой тип скрывается под маской auto, почему T&& не всегда rvalue, и почему move ничего не двигает.
ПВТ - весна 2015 - Лекция 2. POSIX Threads. Основные понятия многопоточного п...Alexey Paznikov
ЛЕКЦИЯ 2. POSIX Threads. Жизненный цикл потоков. Планирование. Синхронизация
Курс "Параллельные вычислительные технологии" (ПВТ), весна 2015
Сибирский государственный университет телекоммуникаций и информатики
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
http://cpct.sibsutis.ru/~apaznikov
Tech Talks @NSU: Как приручить дракона: введение в LLVMTech Talks @NSU
http://techtalks.nsu.ru
Видеозапись: http://www.youtube.com/watch?v=v7uBLSm6ft8
06 октября 2015. Как приручить дракона: введение в LLVM (Дмитрий Кашицын, HDsoft)
«В этом докладе мы кратко расскажем о таком звере, о котором много кто слышал, но немногие щупали. Что такое компилятор на самом деле? Чем LLVM отличается от других компиляторов? Как в LLVM происходит компиляция программы, как работают оптимизации? Наконец, какой путь проходит программа от разбора исходного текста до генерации исполняемого файла?
Лекция будет обзорной и не потребует от слушателей глубоких знаний теории компиляторов.»
Лекция прочитана в рамках проекта Tech Talks @NSU – серии открытых лекций о разработке ПО и карьере в IT, проводимых в Новосибирском государственном университете.
Подробности: http://techtalks.nsu.ru
10 июня 2015. Дмитрий Кашицын (HDsoft) дает обзор LLVM.
http://techtalks.nsu.ru
Видеозапись: https://plus.google.com/events/ctes98f7uhf19t5jlvlbk24dan4
В этом докладе мы кратко расскажем о таком звере, как LLVM, о котором много кто слышал, но немногие щупали. Что такое компилятор на самом деле? Чем LLVM отличается от других компиляторов? Как в LLVM происходит компиляция программы, как работают оптимизации? Наконец, какой путь проходит программа от разбора исходного текста до генерации исполняемого файла?
Лекция будет обзорной и не потребует от слушателей глубоких знаний теории компиляторов.
Лекция прочитана в рамках проекта Tech Talks @NSU – серии открытых лекций о разработке ПО и карьере в IT, проводимых в Новосибирском государственном университете.
Подробности: http://techtalks.nsu.ru
Продолжаем говорить о микрооптимизациях .NET-приложенийAndrey Akinshin
Этот доклад продолжает тему моего выступления с прошлого DotNext про сложную науку о микрооптимизациях. Вас ждут новые увлекательные истории о том, что же происходит под капотом .NET-программ. Будем обсуждать различия разных C# и JIT компиляторов (Roslyn и RyuJIT в том числе), медитировать на IL и ASM листинги, а также разбираться с особенностями современных CPU.
ЛЕКЦИЯ 4. Стандарт POSIX Threads. Реентерабельность функций. Обработка сигналов. Локальные данные потоков. Принудительное завершение потоков. Шаблоны программирования с использованием потоков
Курс "Параллельные вычислительные технологии" (ПВТ), осень 2014
Сибирский государственный университет телекоммуникаций и информатики
преподаватель:
Пазников Алексей Александрович
к.т.н., доцент кафедры вычислительных систем СибГУТИ
Название для привлечение внимания. На самом деле, презентация о том, что а) писать парсеры это просто, б) писать всякие вычислялки это просто, в) делается это вот так, г) бояться этого не нужно, а нужно делать.
Shader magic: Breakdown of popular visual effects for gamesDevGAMM Conference
The session focuses on analysis of how popular visual effects are made. Sergey reproduces these effects in popular game engine Unity and talks about the use of shaders and simple math.
#MadeWithUnity
Мы все допускаем ошибки при программировании и тратим массу времени на их устранение.
Один из методов который позволяет быстро диагностировать дефекты – статический анализ исходного кода.
Языки C, C++ и C++0x как набор ножей по дереву. С их помощью создаются великолепные изделия, но немного неаккуратности и можно глубоко порезаться. Одной из самых ранних методик обнаружения ошибок в коде программ является статический анализ кода. Запуская анализ сразу после написания нового кода или во время ночных сборок, можно выявить множество ошибок еще до этапа тестирования. Это сокращает стоимость и время их исправления. Также могут быть обнаружены дефекты, редко проявляющие себя, которые могут являться головной болью на протяжении многих месяцев сопровождения программы.
В докладе будет продемонстрировано множество примеров ошибок в известных open source программах и библиотеках, которые можно обнаружить с помощью статических анализаторов.
Андрей Карпов
Вы узнаете, что такое статический анализ кода и историю его развития. Узнаете, как эффективно применять инструменты статического анализа в своей работе, увидите практические примеры использования этой методологии. Доклад ориентирован на программистов, использующих языки Си/Си++, но будет полезен всем
C++ CoreHard Autumn 2018. Кодогенерация C++ кроссплатформенно. Продолжение - ...corehard_by
В докладе будет рассмотрена генерация кода при компиляции различных языковых конструкций, как простых, так и сложных, на различных платформах, как общераспространённых x86/x64, так и тех, которым уделяется меньше внимания: ARM, AVR. Также будут встречаться примеры для совсем экзотических процессоров вроде PowerPC и даже MicroBlaze. Основной упор будет делаться не на обработку данных, а именно на сопоставление различных конструкций кода с инструкциями целевых платформ.
Доклад вводит в рассмотрение универсальный адаптер, позволяющий обернуть любой класс с целью добавления новых свойств, отсутствующих в оригинальном классе. Получаемые классы могут иметь в точности такой же интерфейс, как и первоначальные, что позволяет прозрачно заменять их и оборачивать любое количество раз.
Это позволяет добавлять необходимые свойства объектам, не переписывая его с нуля. Предложенная обобщенная концепция будет последовательно введена и проиллюстрирована простыми, но интересными примерами.
На протяжении всего существования C++ тема компайл-тайм рефлексии поднимается постоянно, но, к сожалению, до сих пор Стандарт языка не дает достаточных возможностей для извлечения и манипулирования компайл-тайм информацией. Большое количество библиотек и препроцессоров было придумано для того, чтобы решить эту проблему, начиная от простых макросов и заканчивая Qt-moc или ODB. В докладе Антон расскажет о том, как на эту проблему смотрит Комитет по Стандартизации: какие решения были предложены, и какое стало доминирующим.
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itSergey Platonov
The talk will look at limitations of compilers when creating fast code and how to make more effective use of both the underlying micro-architecture of modern CPU's and how algorithmic optimizations may have surprising effects on the generated code. We shall discuss several specific CPU architecture features and their pros and cons in relation to creating fast C++ code. We then expand with several algorithmic techniques, not usually well-documented, for making faster, compiler friendly, C++.
Note that we shall not discuss caching and related issues here as they are well documented elsewhere.
Василий Сорокин, Простой REST сервер на Qt с рефлексиейSergey Platonov
Библиотека Qt имеет довольно мощную систему рефлексии. На примере простого в использовании класса, позволяющего с помощью наследования быстро построить REST сервер под ваши нужды, я покажу как элегантно ее можно задействовать в реальной жизни. В заключительной части, покажу еще один пример когда рефлексия Qt помогает красиво протестировать испускание сигналов классом.
Сергей Шамбир, Адаптация Promise/A+ для взаимодействия между C++ и JavascriptSergey Platonov
Шаблоны — мощный инструмент, добавляющий в язык новые возможности, а программистам в команде — новые проблемы. Доклад покажет, как тщательно продуманный шаблонный код может не усложнить, а упростить жизнь и дать надёжную абстракцию межпроцессных межъязыковых асинхронных вызовов функций. С помощью шаблонов можно:
адаптировать Promise/A+ из Javascript для C++
автоматически проверять и раскладывать динамический массив аргументов на статичные аргументы функции
сделать аналог std::bind для weak_ptr.
Эти вещи будут показаны на примере взаимных вызовов между C++ и Javascript в одном приложении с помощью CEF3.
Антон Бикинеев, Writing good std::future< C++ >Sergey Platonov
В докладе Антон расскажет о грядущих мажорных изменениях языка, которые, не войдя в Стандарт 17-го года и оставшись в Technical Specifications, будут ждать своего мержа в 20-м, а также быть уже реализованными в некоторых компиляторах. Осветятся также минорные, уже одобренные фичи следующего Стандарта, как языковые, так и библиотечные. Антон расскажет об их целях, покажет методы использования, а также осветит некоторые гайдлайны и трики.
Павел Филонов, Разделяй и управляй вместе с Conan.ioSergey Platonov
Несмотря на солидный возраст С++, одной из больших проблем, возникающих при разработке с его использованием, до сих пор является управление зависимостям. Особенно остро этот вопрос возникает при наличии нескольких различных целевых платформ. В докладе будет рассмотрено, как менеджер пакетов Conan.io позволяет решить проблему управления зависимостями и, как следствие, значительно улучшить скорость разработки на C++ и повысить модульность разрабатываемых систем.
Хочется чего-то новенького, необычного? Тогда добро пожаловать в мир чудеc C++17:
if constexpr (auto& [number, ok] = variable; ok)
return "Hi"
else
return number + 42;
Вы услышите о новом стандарте C++, обнаружите для себя новые полезные классы, функции и возможности языка. Для каждой новинки я приведу примеры использования, расскажу о нюансах и подводных камнях.
А ещё вы узнаете о том, как проходят заседания комитета по стандартизации C++ и сможете задать интересующие вас вопросы связанные с нововведениями С++17 и С++Next.
Тестирование графического интерфейса пользователя является одним из основных видов тестирования графических приложений. В докладе будут рассмотрены задачи и особенности такого тестирования.
Далее будут рассмотрены плюсы и минусы использования стандартной Qt библиотеки QTest, и представлен проект QSpec, как альтернатива QTest. Также будут представлены примеры использования QSpec и дальнейшие планы по развитию этого проекта.
Адрес проекта: https://github.com/ugeneunipro/QSpec
Не так давно Гор Нишанов представил свой доклад: C++ Coroutines a negative overhead abstraction. В этом докладе Гор упомянул, что предложенный дизайн корутин позволяет их использовать практически в любых окружениях, в том числе и с "бедным" C++ рантаймом.
Я решил попробовать запустить корутины в следующих окружениях: обычное приложение, драйвер ОС Windows, EFI приложение. Только в одном из этих окружений есть полноценный C++ рантайм и поддержка исключений, в остальных ничего этого нет. Более того, EFI приложение вообще выполняется до старта ОС.
Я хочу рассказать о том, как мне удалось запустить корутины в этих окружениях, поговорим о том, какие проблемы существуют в асинхронном системном программировании и как их можно обойти.
7. 7
Нормализация векторов
● Очень частая операция в 3D графике
(миллионы операций на кадр)
● Нормали используются при расчете
освещения, теней, отражений и т. п.
● С помощью черной магии вычисление может
быть существенно ускорено
14. 14
Алгоритм rsqrt(X)
1.Вычислить половину X и запомнить
2.Сдвинуть X как uint32_t на 1 бит вправо
3.Вычесть полученное значение из магической
константы 0x5F3759DF ?! о_О
15. 15
Алгоритм rsqrt(X)
1.Вычислить половину X и запомнить
2.Сдвинуть X как uint32_t на 1 бит вправо
3.Вычесть полученное значение из магической
константы 0x5F3759DF ?! о_О
4.Интерпретировать разность, как первое
приближение результата в float
16. 16
Алгоритм rsqrt(X)
1.Вычислить половину X и запомнить
2.Сдвинуть X как uint32_t на 1 бит вправо
3.Вычесть полученное значение из магической
константы 0x5F3759DF ?! о_О
4.Интерпретировать разность, как первое
приближение результата в float
5.Методом Ньютона получить более точное
приближение (с помощью значения из 1.)
17. 17
Вариант реализации в Quake III
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
// evil floating point bit level hacking
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 ); // what the f*ck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
return y;
}
18. 18
Готовим плацдарм
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
// evil floating point bit level hacking
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 ); // what the f*ck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
return y;
}
19. 19
Вычисляем половину
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
// evil floating point bit level hacking
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 ); // what the f*ck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
return y;
}
20. 20
Черная магия №1
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
// evil floating point bit level hacking
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 ); // what the f*ck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
return y;
}
21. 21
Черная магия №2
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
// evil floating point bit level hacking
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 ); // what the f*ck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
return y;
}
22. 22
Уточнение по Ньютону
float Q_rsqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
// evil floating point bit level hacking
i = * ( long * ) &y;
i = 0x5f3759df - ( i >> 1 ); // what the f*ck?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration
return y;
}
23. 23
Но зачем?!
● Используются простые битовые операции
● Позволяет вычислить значение в среднем
в 4 раза быстрее, чем считать в лоб на FPU
● Забавный пример хакинга
● В современных реалиях не имеет смысла
24. 24
Type Punning на примере сокетов
// Прототип функции bind()
int bind(int sockfd, struct sockaddr* my_addr, socklen_t addrlen);
// Заполняем параметры вызова
struct sockaddr_in sa = {0};
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
// ...
// Делаем вызов
bind(sockfd, (struct sockaddr*) &sa, sizeof sa);
25. 25
#include <sys/socket.h>
/* This is the type we use for generic socket address arguments.
With GCC 2.7 and later, the funky union causes redeclarations or
uses with any of the listed types to be allowed without complaint.
G++ 2.7 does not support transparent unions so there we want the
old-style declaration, too. */
#if defined __cplusplus || !__GNUC_PREREQ (2, 7) || !defined __USE_GNU
# define __SOCKADDR_ARG struct sockaddr* __restrict
#else
# define __SOCKADDR_ALLTYPES
__SOCKADDR_ONETYPE (sockaddr)
__SOCKADDR_ONETYPE (sockaddr_in)
__SOCKADDR_ONETYPE (sockaddr_in6)
...
# define __SOCKADDR_ONETYPE(type) struct type* __restrict __##type##__;
typedef union {
__SOCKADDR_ALLTYPES
} __SOCKADDR_ARG __attribute__ ((__transparent_union__));
# undef __SOCKADDR_ONETYPE
#endif
27. 27
Transparent union
// Объявление сложного типа
typedef union {
int *__ip;
union wait *__up;
} wait_status_ptr_t __attribute__ ((__transparent_union__));
// Прототип билиотечной функции
pid_t wait (wait_status_ptr_t);
//Вариант вызова согласно Posix
int w;
wait (&w);
//Вариант вызова согласно BSD 4.1
union wait w;
wait (&w);
31. 31
Pointer aliasing
● Возникает, когда несколько указателей
ссылаются на один участок памяти
● Анализ указателей позволяет выполнять
более агрессивные оптимизации
● Обширные возможности стрельбы по ногам
33. 33
Основные идеи оптимизаций
● Не делать то, что никому не нужно
● Не делать дважды то, что можно сделать
один раз (а лучше не делать вообще)
● Если можно получить тот же результат, но
меньшими усилиями — это нужно сделать
● Сокращение издержек на всех уровнях
34. 34
Виды оптимизаций
● Peephole оптимизации — буквально
«через замочную скважину». Локальные
оптимизации в пределах базового блока
● Внутрипроцедурные оптимизации
● Межпроцедурные оптимизации
● Оптимизации во время линковки
36. 36
Подопытный код
int sum_array(const int* input, int* max, size_t length) {
int sum = 0;
*max = 0;
for (size_t i = 0; i < length; i++) {
*max = (input[i] > *max) ? input[i] : *max;
sum += input[i];
}
return sum;
}
37. 37
Обращения к input
int sum_array(const int* input, int* max, size_t length) {
int sum = 0;
*max = 0;
for (size_t i = 0; i < length; i++) {
*max = (input[i] > *max) ? input[i] : *max;
sum += input[i];
}
return sum;
}
38. 38
Обращения к max
int sum_array(const int* input, int* max, size_t length) {
int sum = 0;
*max = 0;
for (size_t i = 0; i < length; i++) {
*max = (input[i] > *max) ? input[i] : *max;
sum += input[i];
}
return sum;
}
39. 39
Выделение общих подвыражений
int sum_array(const int* input, int* max, size_t length) {
int sum = 0;
*max = 0;
for (size_t i = 0; i < length; i++) {
const int _max = *max;
const int _input = input[i];
*max = (_input > _max) ? _input : _max;
sum += _input;
}
return sum;
}
40. 40
Clang -m32 -O3 -mno-mmx -mno-sse
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
41. 41
Инициализация и загрузка аргументов
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
42. 42
Быстрая проверка на выход
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
43. 43
Инициализация цикла по массиву
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
44. 44
Вычисление максимума
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
45. 45
Запись максимума и накопление суммы
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
46. 46
Приращение переменных индукции
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
47. 47
Проверка граничного условия на выход
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
48. 48
Два чтения в цикле…
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
add eax, dword ptr [edi] ; sum += input[i]
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
50. 50
Пытаемся использовать ebx
sum_array(int*, int*, int):
mov ecx, dword ptr [esp + 24] ; ecx = *length
mov edx, dword ptr [esp + 20] ; edx = max
mov dword ptr [edx], 0 ; *max = 0
xor esi, esi ; max = 0
test ecx, ecx
jle .EXIT_0 ; if (! length) return sum = 0;
mov edi, dword ptr [esp + 16] ; edi = & input[0]
xor eax, eax ; sum = 0
.LOOP_BODY:
mov ebx, dword ptr [edi] ; _input = input[i]
cmp ebx, esi ; flag = _max > _input
cmovge esi, ebx ; esi = flag ? _max : _input
mov dword ptr [edx], esi ; *max = esi
— add eax, dword ptr [edi] ; sum += input[i]
+ add eax, ebx ; sum += _input
add edi, 4
dec ecx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor eax, eax ; sum = 0
.EXIT:
ret
51. 51
Программы пишут человеки…
Хитрость компилятора легко компенсируется
глупостью программиста:
int fill_array(int* output, size_t length);
int sum_array(const int* input, int* max, size_t length);
void omg() {
int array[100] = {0};
fill_array(array, 100);
const int sum = sum_array(array, &array[42], 100);
return sum;
}
52. 52
Вносим max внутрь функции
int sum_array(const int* input, int* _max, size_t length) {
int sum = 0;
int max = 0;
int * const pmax = &max;
for (size_t i = 0; i < length; ++i) {
*pmax = (input[i] > *pmax) ? input[i] : *pmax;
sum += input[i];
}
*_max = *pmax; // восстанавливаем справедливость
return sum;
}
53. 53
В цикле используем pmax
int sum_array(const int* input, int* _max, size_t length) {
int sum = 0;
int max = 0;
int * const pmax = &max;
for (size_t i = 0; i < length; ++i) {
*pmax = (input[i] > *pmax) ? input[i] : *pmax;
sum += input[i];
}
*_max = *pmax; // восстанавливаем справедливость
return sum;
}
54. 54
В конце — записываем out параметр
int sum_array(const int* input, int* _max, size_t length) {
int sum = 0;
int max = 0;
int * const pmax = &max;
for (size_t i = 0; i < length; ++i) {
*pmax = (input[i] > *pmax) ? input[i] : *pmax;
sum += input[i];
}
*_max = *pmax; // восстанавливаем справедливость
return sum;
}
55. 55
Clang -m32 -O3 -mno-mmx -mno-sse
sum_array(int*, int*, int):
mov edx, dword ptr [esp + 24]
mov ecx, dword ptr [esp + 20]
xor eax, eax
test edx, edx
jle .EXIT_0
mov edi, dword ptr [esp + 16]
xor esi, esi
.LOOP_BODY:
mov ebx, dword ptr [edi]
cmp ebx, esi
cmovge esi, ebx
add eax, ebx
add edi, 4
dec edx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor esi, esi
.EXIT:
mov dword ptr [ecx], esi
ret
56. 56
Нормальный человеческий цикл
sum_array(int*, int*, int):
mov edx, dword ptr [esp + 24]
mov ecx, dword ptr [esp + 20]
xor eax, eax
test edx, edx
jle .EXIT_0
mov edi, dword ptr [esp + 16]
xor esi, esi
.LOOP_BODY:
mov ebx, dword ptr [edi]
cmp ebx, esi
cmovge esi, ebx
add eax, ebx
add edi, 4
dec edx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor esi, esi
.EXIT:
mov dword ptr [ecx], esi
ret
57. 57
Один раз читаем массив…
sum_array(int*, int*, int):
mov edx, dword ptr [esp + 24]
mov ecx, dword ptr [esp + 20]
xor eax, eax
test edx, edx
jle .EXIT_0
mov edi, dword ptr [esp + 16]
xor esi, esi
.LOOP_BODY:
mov ebx, dword ptr [edi]
cmp ebx, esi
cmovge esi, ebx
add eax, ebx
add edi, 4
dec edx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor esi, esi
.EXIT:
mov dword ptr [ecx], esi
ret
58. 58
…и один раз записываем результат
sum_array(int*, int*, int):
mov edx, dword ptr [esp + 24]
mov ecx, dword ptr [esp + 20]
xor eax, eax
test edx, edx
jle .EXIT_0
mov edi, dword ptr [esp + 16]
xor esi, esi
.LOOP_BODY:
mov ebx, dword ptr [edi]
cmp ebx, esi
cmovge esi, ebx
add eax, ebx
add edi, 4
dec edx
jne .LOOP_BODY
jmp .EXIT
.EXIT_0:
xor esi, esi
.EXIT:
mov dword ptr [ecx], esi
ret
59. 59
Лучше не использовать out параметры
● Переменная max переехала в тело функции
● Результаты возвращаются парой
● Компилятор может оптимизировать
std::pair<int, int> sum_array(const int* input, size_t length) {
int sum = 0;
int max = 0;
for (size_t i = 0; i < length; i++) {
max = (input[i] > max) ? input[i] : max;
sum += input[i];
}
return std::make_pair(sum, max);
}
62. 62
Вспоминаем основы RISC
● Простой фиксированный формат команды
● Простые регистровые операции
● Мухи и котлеты: работа с памятью отдельно
от операций с регистрами
63. 63
LLVM IR напоминает RISC
● Работа с памятью через load и store
● Работа с «регистрами» — SSA
80. 80
● Позволяет не накосячить с оптимизацией
потенциально зависимых значений
● Медленный, но корректный код
● Значение по умолчанию
Отношение MayAlias:
81. 81
Если указатели не пересекаются
int x;
int y;
int* a = &x;
int* b = &y;
*a = 1;
*b = 2;
int c = *a + 1;
85. 85
NoAlias позволяет:
● Удалить лишние операции с памятью
● Выполнять перестановку операций
● Выполнять оптимизации над независимыми
значениями, без оглядки друг на друга
● Результат — более эффективный код
91. 91
MustAlias позволяет:
● Доказать связь отдельных операций
● Выполнять оптимизации с учетом истории
● Результат — более эффективный код
92. 92
Strict aliasing и TBAA
● Cпособ уменьшить MayAlias
в пользу NoAlias и MustAlias
● Работает на базе системы типов языка
и другой «внешней» для LLVM информации
● Позволяет проводить оптимизации там,
где информация о контексте недостаточна
93. 93
Подход С
float invert(float value) {
uint32_t* const raw = (uint32_t*) &value;
*raw ^= (1 << 31); // меняем знак
return * (float*) raw;
}
95. 95
Подход Fortran
● Аргументы функций всегда независимы (кроме target)
● Тем не менее, не мешает выстрелить в ногу
● Программист ожидает «2, 4, 4». В реальности будет «2, 2, 2»
...
I = 1
CALL FOO(I, I)
PRINT *, I
END
SUBROUTINE FOO(J, K)
J = J + K
K = J * K
PRINT *, J, K
END
96. 96
Подход Java
● Язык запрещает опасную работу с указателями (почти)
● Escape analysis позволяет размещать объекты на стеке
public String getHello() {
Vector v = new Vector();
v.add("Hello");
v.add("from");
v.add("Java!");
return v.toString();
}
97. 97
Подход Rust
● Иммутабельность по умолчанию
● Концепция заимствования ссылок
● Алгебраические типы данных и сопоставление
по образцу
● Обобщенный код, типажи
● Выделенные unsafe блоки
● Контроль на этапе компиляции
● Отсутствие состояния гонок,
потокобезопасность кода гарантируется
● Абстракции нулевой стоимости
98. 98
Пример программы на Rust
fn test(vec: &Vec<i32>) -> (i32, i32) {
let mut sum: i32 = 0;
let mut max: i32 = vec[1];
for i in vec {
sum = sum + i;
max = if i > &max { *i } else { max };
}
(sum, max)
}
fn main() {
let vec = vec![1, 2, 3];
let (sum, max) = test(&vec);
println!("The sum is {}, max is {}", sum, max);
}
99. 99
Что можно почитать
● blog.llvm.org
● llvm.org/docs
● isocpp.org/std/the-standard
● doc.rust-lang.org
● halt.habrahabr.ru/topics/
● llst.org