и посмотреть медиа
S0ER - архитектура и кодинг
и посмотреть медиа
Материалы по архитектуре ПО, программированию и карьерному росту в IT.
Материалы по архитектуре ПО, программированию и карьерному росту в IT.
S0ER фокусируется на архитектуре программного обеспечения, программировании и профессиональном развитии. Канал предлагает глубокие разборы, примеры кода и стратегии для продвижения в IT-сфере.
TurboFan: анализ оптимизаций в V8 с помощью ассемблера (часть 1) Чем глубже мы узнаем языки программирования, тем больше начинаем любить и ценить ассемблер. Сегодня покажу, как знание ассемблера помогает в изучении возможностей движка V8. V8 — это движок для работы с языком JavaScript, он используется в NodeJS и браузере Chrome. Одна из особенностей этого движка — представление «горячего» кода в виде оптимизированных машинных инструкций. Для этого в движок интегрирован оптимизирующий JIT-компилятор TurboFan. Основные задачи, которые решает TurboFan: 💡 Анализ и оптимизация «горячих» функций (которые вызываются часто); 💡 Специализация кода под конкретные типы данных; 💡 Удаление избыточных операций; 💡 Векторизация вычислений; 💡 Инлайнинг функций. Для работы с машинным кодом традиционно используется ассемблер, поэтому давайте разберем небольшой пример, который позволит лучше понять, как работает TurboFan. В этой статье будет общее описание блоков кода, а в будущих статьях разберем детали каждого из них. Основные моменты, которые нужны для старта: 1️⃣ Мы будем использовать nodejs для получения машинного кода функции, для этого нужно запомнить следующий шаблон команды: node --print-opt-code --code-comments -allow-natives-syntax your_script.js 2️⃣Мы будем использовать специальную инструкцию %OptimizeFunctionOnNextCall, без нее ничего не получится. Давайте сделаем простой скрипт: // sum.js function sum(a, b) { return a + b; } // Прогреваем функцию (вызываем много раз, чтобы V8 её оптимизировал) for (let i = 0; i < 10000; i++) { sum(i, i + 1); // используем целые числа, чтобы TurboFan сделал оптимизацию именно под них } // Явно просим V8 оптимизировать функцию (требует --allow-natives-syntax) иначе в выводе не будет описане функции %OptimizeFunctionOnNextCall(sum); // Вызываем ещё раз (теперь с оптимизацией) sum(1, 2); Теперь запустим скрипт node --print-opt-code --code-comments -allow-natives-syntax sum.js, если мы сделали всё правильно, то получим огромный вывод на экран, из которого интересна вот эта часть: --- Raw source --- (a, b) { return a + b; } --- Optimized code --- optimization_id = 1 source_position = 22 kind = TURBOFAN name = sum stack_slots = 6 compiler = turbofan address = 0x2edae09247a1 Instructions (size = 184) ; загрузка hidden класса объекта (проверка структуры) 0x1097064c0 0 488b59f8 REX.W movq rbx, [rcx-0x8] ; проверка контекста 0x1097064c4 4 f6433501 testb [rbx+0x35],0x1 0x1097064c8 8 0f85f2e03dfb jnz 0x104ae45c0 (CompileLazyDeoptimizedCode) ;; деоптимизация ; пролог 0x1097064ce e 55 push rbp 0x1097064cf f 4889e5 REX.W movq rbp, rsp 0x1097064d2 12 56 push rsi 0x1097064d3 13 57 push rdi 0x1097064d4 14 50 push rax ; выравнивание стека и проверка лимитов 0x1097064d5 15 4883ec08 REX.W subq rsp,0x8 0x1097064d9 19 488975e0 REX.W movq [rbp-0x20],rsi 0x1097064dd 1d 493b65a0 REX.W cmpq rsp, [r13-0x60] (external value (StackGuard::address_of_jslimit())) 0x1097064e1 21 0f8653000000 jna 0x10970653a ; если стек переполнен, переходим ; ====== Основная функция ====== ; Загрузка аргумента "a" 0x1097064e7 27 488b5518 REX.W movq rdx, [rbp+0x18] 0x1097064eb 2b f6c201 testb rdx,0x1 0x1097064ee 2e 0f8572000000 jnz 0x109706566 ; Загрузка аргумента "b" 0x1097064f4 34 488b4d20 REX.W movq rcx, [rbp+0x20] 0x1097064f8 38 48c1f920 REX.W sarq rcx, 32 ; сразу распаковка SMI для "b" ; Подготовка аргументов к сложению 0x1097064fc 3c 488bfa REX.W movq rdi,rdx 0x1097064ff 3f 48c1ff20 REX.W sarq rdi, 32 ; распаковка для "a"
Открыть канал и посмотреть медиаТолько зарегистрированные пользователи могут делиться своим мнением.
Станьте первым, кто поделится своим впечатлением об этом ресурсе!