Собственно речь о том что если бы умели нормально их утилизировать — не нужны были бы специфические оптимизации на основе параметрических многогранников и прочего, а так для каждой SIMD инструкции или подчистки кэша надо лезть в Intrinsics интерфейс...
WPO/PGO не означает что MSVC откажется от существующих x64 ABI и начнёт их ломать в угоду утилизации регистровой памяти. К сожалению WPO/PGO не приводят к ожидаемому вами эффекту на х64'ой платформе, а на x86 просто подбирается наиболее эффективная конвенция вызовов, но существующее ABI сохраняется.
С MSDN'a:
When /LTCG is used to link modules… following optimizations are performed:
• Cross-module inlining
• Interprocedural register allocation (64-bit operating systems only)
• Custom calling convention (x86 only)
• Small TLS displacement (x86 only)
• Stack double alignment (x86 only)
• Improved memory disambiguation
Register Allocation вставляет хинты на подобие USES в MASM'е для резервирования регистровой памяти.
У ICC в целом есть пару особенностей — он обычно мелочёвку оптимизирует на много лучше GCC/LLVM (20-30% компактнее и шустрее), но любые сложные вещи любит раздувать до непонятных размеров (почти в 3 раза). По этому у него свои, особенные глюки с оптимизациями… Для научных вычислений и прочего он подходит лучше чем GCC/LLVM, но любые пользовательские приложения он будет раздувать до совсем несуразных размеров.
rust использует llvm… и к форточкам это не имеет никакого отношения.
Любая C/С++ функция под форточками будет использовать существующее ABI — там нет понятия "whole program optimization" так как подобные оптимизации могут быть выполнены только во время линковки, и они не реализованы в существующих линковщиках.
Какой смысл в компиляторе, который не может полноценно использовать весь набор инструкций процессора, и требует что бы программист сам вставлял их где это нужно ?
Прямое, это и есть сишное ABI, — унифицированная конвенция вызова сишных функций в форточках на x64 системах.
Какой-то компилятор генерирует код под форточки, который противоречит этому ману?
Не один существующий компилятор не генерирует код который ему следует.
… до которых так просто и не додумаешся
Не используется многопроходный GA.
Оно не сможет эффективно использовать большую часть существующих SIMD инструкций и менять последовательности команд в различных оптимизационных целях… приходится самому всегда колупаться в intrinsics'ах. Даже полигидральные плюшки не решают этот вопрос.
Действительно плохой пример. Просто на практике сталкивался с подобными вещами довольно часто, чаще чем хотелось бы.
Да что уж там, один и тот же байткод будет отличатся от компилятора к компилятору ну и что?
Есть micro и macro fusion операции внутри самого блока трансляции процессора… различие в результирующем коде означает что везде они будут применяться по разному, и зависеть от солнечной радиации и положения звёзд на небе… как и производительность результирующего кода.
Есть очень много особенностей и ограничений целевых компиляторов, а также отсутствие вменяемой оптимизации в случае с Сишкой на форточках. В llvm этот вопрос решён хоть как-то, но по уровню оптимизации сишка уступает тому же rust'у. По этому от фронтенда до фронтенда один и тот же биткод (они решили отличиться) будет оптимизирован по разному.
На практике большая часть существующих оптимизаций:
• разворачивание циклов для последующего использования SIMD операций
• комбинирование макро команд для выполнение за один такт процессора (mov, test, cmp etc).
• контроль заполнения очереди комманд
• принудительная подчистка кэша
• контроль глубины ветвлений
• минимизация количества операций со стэком
• использование регистровой памяти для передачи аргументов функций
не применяются вообще, особенно в форточках, либо применяются довольно криво...
У ABI cишки слишком много консервативных и устаревших ограничений для сохранения портабельности, которые нынче не то что не нужны, а просто ставят крест на вертикальном масштабировании большинства решений.
В примерах со статьи — имеет смысл использовать SSE2/SSE4 и AVX2 операции.
Даже банальные strstr / strcmp имеют ассемблерные SIMD аналоги выполняющиеся ровно за один такт, а если правильно чистить кэш и предовращать ITLB/DTLB miss, то и по 4 штуки за такт (по 64/128 байт).
Приложения со статьи получат на выходе приблизительно одинаковый листинг ассемблерных инструкций без каких либо вменяемых оптимизаций, по этому сравнивать их не совсем корректно и целесообразно. Особенно что касается скорости системных вызовов I/O — это просто не самая удачная метрика.
Также есть специализированное File mapping API — аналог mmap Posix вызова.
Понятие "Демона" отсутствует — используется свой планировщик с поддержкой афинности (affinity), всё в foreground'e без переключения контекста выполнения процесса. Получается так что логические ядра жёстко привязаны к процессу с DPDK. Пакеты складываются непосредственно в оперативку и большие страницы (huge pages) без участия процессора через RDMA, а целевой процесс с DPDK ловит единичное прерывание по заполнению буфера или других критериев. Доступ к сетевому интерфейсу монопольный посредством VFIO и IOMMU. Любое IPC через shmem подразумевает копирование с целевого буфера, что сильно повлияет на производительность. Идея DPDK в том что бы успевать обработать инфу в существующем буфере пока сетевуха пишет в соседний, любое копирование значительно снизит производительность. Грубо-говоря надо успевать обработать 1 клиентский запрос за 500-600 тактов процессора, желательно с использованием SIMD операций и Cache Streaming подходом. shmem используется только в качестве коммуникации для QEMU с ivshmem.
Кроме OVS есть ещё outscale/butterfly, возможно его использование в вашем случае будет более целесообразным. Так же есть порт BSD TCP/IP стэка на DPDK.
Опыта разработки мобильных приложений нет, но есть 5 лет опыта разработки высоконагруженных проектов на node.js, asp.net mvc.
Опыт временем не меряют.
Не бывает "высоконагруженных проектов" на node.js / asp.net, просто масштабируется простой процессора в разных вариациях. Без упоминания слов: "профилирование", "аффинитет" и "большие страницы" — не один проект нельзя назвать высоконагруженным.
Ну да, конечно "автор ниасилил, реакт сырой, потому что… автор ниасилил". Ок, смысл в целом понятен.
Если нет опыта с нативной мобильной разработкой — нет смысла лениво надеятся что всё поедет с полпинка.
Все серьёзные конторы (SoundCloud, Facebook, AirBnB) давно пишут нативные компоненты под себя, и сами их же и поддерживают. А надеятся на посредственные поделки с гитхаба слишком наивно.
Как это весело наблюдать когда одни матерят Cordova и говорят ехать в сторону React-Native, другие матерят React-Native и призывают менять религию на Cordova… а конструктивности и конкретики в обоих случаях как-то вот совсем не наблюдается.
Вопрос "любимого дистрибутива на VPS хостинге" малость морально устарел.
Прикрутите заливку образов/менеджмент через packer.io / bosh.io / ironic — дайте людям возможность загружать что им самим будет угодно.
Я сейчас пишу Scala фреймворк на Scala-Native c интеграцией DPDK.
До выхода Java9 нет смысла колупаться — слишком много надо патчить в OpenJDK.
В общем Netty + DPDK потеряла актуальность из-за кучи оверхедов о которых я тогда и предположить не мог.
Сейчас вышло SPDK — есть задумки прикрутить хранилище на SPDK к PostgreSQL и ScyllaDB.
А зачем что-то оставлять, если стандартный вариант использования подразумевает NUMA аффинность и запуск приложения на полностью изолированных от планировщика ядрах с пачкой больших страниц?
Там линукс нужен только для того что бы инициализировать RDMA, CBDMA и IOMMU в рамках VFIO, и всё.
В принципе, для этого можно реализовать отдельный загрузчик и полностью избавится от ядра ОС… с другой стороны вопрос менеджмента и поддержки окружения усложняется на несколько порядков.
p.s. CBDMA — common buffer DMA, есть ещё S/GDMA — Scatter/gather DMA. Разница заключается в принципе обращения и работы с памятью. Scatter/Gather может работать с фрагментированной памятью, что требует отдельных mapping регистров и снижает размер блока данных DMA транзакции SDV (Single DMA Volume). CBDMA работает с непрерывной памятью, которая называется Common buffer и является набором больших страниц, и для его работы не требуется mapping соответственно и SDV с пропускной способностью у него на много выше. S/GDMA стоит применять когда нет возможности выделить большие страницы.
Интересуют конкретные цифры.
То что там будет Overhead из-за копирования — и ежу понятно.
Профилятор — профилятору рознь. Надо понимать что есть multisample profiling, есть monitoring gap и прочие нюансы.
Было бы просто замечательно прогнать это всё в афинном окружении (numactl/taskset) на изолированных ядрах, да отрисовать flame graph'ы. Даже банального ptrace хватило бы.
Были бы цифры и графики для каждого из вариантов — было бы понятно конкретно что и сколько времени выполняется.
Собственно речь о том что если бы умели нормально их утилизировать — не нужны были бы специфические оптимизации на основе параметрических многогранников и прочего, а так для каждой SIMD инструкции или подчистки кэша надо лезть в Intrinsics интерфейс...
WPO/PGO не означает что MSVC откажется от существующих x64 ABI и начнёт их ломать в угоду утилизации регистровой памяти. К сожалению WPO/PGO не приводят к ожидаемому вами эффекту на х64'ой платформе, а на x86 просто подбирается наиболее эффективная конвенция вызовов, но существующее ABI сохраняется.
С MSDN'a:
Register Allocation вставляет хинты на подобие
USES
в MASM'е для резервирования регистровой памяти.Это радует.
Правда на форточках пока мною замечено не было.
Про эти оптимизации во время линковки я в курсе…
Не знаю, не смотрел что на выходе получается, но вряд ли они будут ломать существующее глючное ABI.
У ICC в целом есть пару особенностей — он обычно мелочёвку оптимизирует на много лучше GCC/LLVM (20-30% компактнее и шустрее), но любые сложные вещи любит раздувать до непонятных размеров (почти в 3 раза). По этому у него свои, особенные глюки с оптимизациями… Для научных вычислений и прочего он подходит лучше чем GCC/LLVM, но любые пользовательские приложения он будет раздувать до совсем несуразных размеров.
rust использует llvm… и к форточкам это не имеет никакого отношения.
Любая C/С++ функция под форточками будет использовать существующее ABI — там нет понятия "whole program optimization" так как подобные оптимизации могут быть выполнены только во время линковки, и они не реализованы в существующих линковщиках.
Какой смысл в компиляторе, который не может полноценно использовать весь набор инструкций процессора, и требует что бы программист сам вставлял их где это нужно ?
Прямое, это и есть сишное ABI, — унифицированная конвенция вызова сишных функций в форточках на x64 системах.
Не один существующий компилятор не генерирует код который ему следует.
Не используется многопроходный GA.
Оно не сможет эффективно использовать большую часть существующих SIMD инструкций и менять последовательности команд в различных оптимизационных целях… приходится самому всегда колупаться в intrinsics'ах. Даже полигидральные плюшки не решают этот вопрос.
Например вот это нечто пожирающее стэк без острой необходимости.
С официальным гайдом по оптимизации.
Действительно плохой пример. Просто на практике сталкивался с подобными вещами довольно часто, чаще чем хотелось бы.
Есть micro и macro fusion операции внутри самого блока трансляции процессора… различие в результирующем коде означает что везде они будут применяться по разному, и зависеть от солнечной радиации и положения звёзд на небе… как и производительность результирующего кода.
Есть очень много особенностей и ограничений целевых компиляторов, а также отсутствие вменяемой оптимизации в случае с Сишкой на форточках. В llvm этот вопрос решён хоть как-то, но по уровню оптимизации сишка уступает тому же rust'у. По этому от фронтенда до фронтенда один и тот же биткод (они решили отличиться) будет оптимизирован по разному.
На практике большая часть существующих оптимизаций:
• разворачивание циклов для последующего использования SIMD операций
• комбинирование макро команд для выполнение за один такт процессора (mov, test, cmp etc).
• контроль заполнения очереди комманд
• принудительная подчистка кэша
• контроль глубины ветвлений
• минимизация количества операций со стэком
• использование регистровой памяти для передачи аргументов функций
не применяются вообще, особенно в форточках, либо применяются довольно криво...
У ABI cишки слишком много консервативных и устаревших ограничений для сохранения портабельности, которые нынче не то что не нужны, а просто ставят крест на вертикальном масштабировании большинства решений.
В примерах со статьи — имеет смысл использовать SSE2/SSE4 и AVX2 операции.
Даже банальные strstr / strcmp имеют ассемблерные SIMD аналоги выполняющиеся ровно за один такт, а если правильно чистить кэш и предовращать ITLB/DTLB miss, то и по 4 штуки за такт (по 64/128 байт).
Приложения со статьи получат на выходе приблизительно одинаковый листинг ассемблерных инструкций без каких либо вменяемых оптимизаций, по этому сравнивать их не совсем корректно и целесообразно. Особенно что касается скорости системных вызовов I/O — это просто не самая удачная метрика.
Также есть специализированное File mapping API — аналог
mmap
Posix вызова.С тех же, когда 30К RPS стал "высоконагрузом" PHP сайтика на конференциях по типу Highload++.
Понятие "Демона" отсутствует — используется свой планировщик с поддержкой афинности (affinity), всё в foreground'e без переключения контекста выполнения процесса. Получается так что логические ядра жёстко привязаны к процессу с DPDK. Пакеты складываются непосредственно в оперативку и большие страницы (huge pages) без участия процессора через RDMA, а целевой процесс с DPDK ловит единичное прерывание по заполнению буфера или других критериев. Доступ к сетевому интерфейсу монопольный посредством VFIO и IOMMU. Любое IPC через shmem подразумевает копирование с целевого буфера, что сильно повлияет на производительность. Идея DPDK в том что бы успевать обработать инфу в существующем буфере пока сетевуха пишет в соседний, любое копирование значительно снизит производительность. Грубо-говоря надо успевать обработать 1 клиентский запрос за 500-600 тактов процессора, желательно с использованием SIMD операций и Cache Streaming подходом. shmem используется только в качестве коммуникации для QEMU с
ivshmem
.Кроме OVS есть ещё outscale/butterfly, возможно его использование в вашем случае будет более целесообразным. Так же есть порт BSD TCP/IP стэка на DPDK.
Надеюсь стало чуток понятнее.
Отличная статья, Спасибо.
Было бы неплохо написать вторую часть об RxSwift.
Если нет опыта с нативной мобильной разработкой — нет смысла лениво надеятся что всё поедет с полпинка.
Все серьёзные конторы (SoundCloud, Facebook, AirBnB) давно пишут нативные компоненты под себя, и сами их же и поддерживают. А надеятся на посредственные поделки с гитхаба слишком наивно.
Как это весело наблюдать когда одни матерят Cordova и говорят ехать в сторону React-Native, другие матерят React-Native и призывают менять религию на Cordova… а конструктивности и конкретики в обоих случаях как-то вот совсем не наблюдается.
Вопрос "любимого дистрибутива на VPS хостинге" малость морально устарел.
Прикрутите заливку образов/менеджмент через packer.io / bosh.io / ironic — дайте людям возможность загружать что им самим будет угодно.
Читаю статью, сравниваю с документацией.
Кому-то нужно сделать соответствующие правки.
До выхода Java9 нет смысла колупаться — слишком много надо патчить в OpenJDK.
В общем Netty + DPDK потеряла актуальность из-за кучи оверхедов о которых я тогда и предположить не мог.
Сейчас вышло SPDK — есть задумки прикрутить хранилище на SPDK к PostgreSQL и ScyllaDB.
Статью оставил сугубо по историческим причинам.
Часть 1 может быть весной 2017ого, может…
Там линукс нужен только для того что бы инициализировать RDMA, CBDMA и IOMMU в рамках VFIO, и всё.
В принципе, для этого можно реализовать отдельный загрузчик и полностью избавится от ядра ОС… с другой стороны вопрос менеджмента и поддержки окружения усложняется на несколько порядков.
p.s. CBDMA — common buffer DMA, есть ещё S/GDMA — Scatter/gather DMA. Разница заключается в принципе обращения и работы с памятью. Scatter/Gather может работать с фрагментированной памятью, что требует отдельных mapping регистров и снижает размер блока данных DMA транзакции SDV (Single DMA Volume). CBDMA работает с непрерывной памятью, которая называется Common buffer и является набором больших страниц, и для его работы не требуется mapping соответственно и SDV с пропускной способностью у него на много выше. S/GDMA стоит применять когда нет возможности выделить большие страницы.
То что там будет Overhead из-за копирования — и ежу понятно.
Профилятор — профилятору рознь. Надо понимать что есть multisample profiling, есть monitoring gap и прочие нюансы.
Было бы просто замечательно прогнать это всё в афинном окружении (numactl/taskset) на изолированных ядрах, да отрисовать flame graph'ы. Даже банального ptrace хватило бы.
Были бы цифры и графики для каждого из вариантов — было бы понятно конкретно что и сколько времени выполняется.