Результат профилирования nfqws2, слинкованного с libluajit, на x86_64 системе на сплошном потоке выгрузки iperf
без ограничителей connbytes
2 инстанса - multisplit и fake без ограничителя standard payload. без внутрипрофильных фильтров на оба направления
valgrind --tool=callgrind --callgrind-out-file=callgrind.out
/opt/zapret2/nfq2/nfqws2 --user=root --qnum 200
--lua-init=@/opt/zapret2/lua/zapret-lib.lua
--lua-init=@/opt/zapret2/lua/zapret-antidpi.lua
--in-range=a
--lua-desync=multisplit:payload=all
--lua-desync=fake:ip_ttl=1:badsum:blob=0x10000000:payload=all
--debug=0
gprof2dot.py -f callgrind callgrind.out | dot -Tpng -o 1.png
Что здесь примечательно.
- Вся логика C кода без процедуры desync занимает всего 5% cpu. desync - это анализ какие есть lua функции, какие у них внутрипрофильные фильтры, проверить фильтры, проверить условие cutoff, если проходит - запушить содержимое desync и вызывать через pcall саму функцию
- Само выполнение кода lua в варианте JIT занимает всего 15% cpu.
- Остальное - это накладные расходы, чтобы каждый раз пушить всю таблицу desync. lua API работает очень небыстро, львиная доля сьедается на подготовке структуры до передачи в функцию. Затем и был придуман FFI в luajit, но я его не использую, потому что не будет совместимости со стандартным lua и отлетят некоторые платформы. А 2 кода писать нет желания. Да и не очень хотел бы давать возможности FFI непонятно кем писанном скриптам. Уж слишком там low level все. Загоняю в песочницы, а тут возможность вызвать любую C функцию.
- При lua cutoff 95% сразу отлетает - не выполняется. Понимаете теперь зачем нужно ставить внутрипрофильные фильтры по range, если нет connbytes ? При превышении up limit по range всех инстансов наступает тишина - lua больше нет !
Вот что творится без lua совсем, когда все ушло в cutoff или функций просто нет.
Большие проценты начинают занимать C функции, которые в lua варианте отьедали доли процента
Почему lua работает так медленно ? Любую строку он уникализирует.
Видимо считает какой-то хэш и сравнивает с базой строк, и если уже есть, то пишет просто указатель.
Потому pushstring работает очень нешустро. string - это не только “abc123”, а любые бинарные блобы, которые могут быть несколько кб
Да и tables не особо скачут.
Там чуть что сразу malloc, копирование памяти.
А пушить приходится много - структура desync довольно обширна
Но NFQUEUE еще больше жрет. Сам процесс перехвата, переключение контекстов, копирование в user mode, возврат вердикта.
Совсем без lua функций - жрет 45% ядра, упираясь в возможности роутера принимать 600-700 мбит.
С 2 инстансами - жрет 55% ядра, выдавая ту же скорость.
Получается, что вся обработка в lua сьедает около 20% от NFQUEUE.
Видите как важно не гнать лишнее на nfqws ?
tun, кстати, по той же причине тормоз. разница openvpn через tun и wireguard - 5-10 раз
Итак :
- Главный монстр - NFQUEUE
- Монстр поменьше - LUA
- C код - на закуску

