Путь к оптимизации производительности компилятора небольших программ

Автор | Марко

Введение

Компилятор апплета — это модуль построения компиляции в инструментах разработчика Baidu, который используется для преобразования кода апплета в код времени выполнения. В связи с развитием бизнеса в старой версии компилятора были проблемы с медленной компиляцией и высоким использованием памяти.Мы сделали масштабную реконструкцию компилятора, приняли архитектуру собственной разработки, а также сделали множество оптимизаций, таких как многопоточность, код кэширование и исходная карта.Производительность и использование памяти были значительно улучшены. В полном тексте представлены идеи дизайна и методы оптимизации новой версии компилятора, а также некоторые технические моменты, которые можно использовать в общих инструментах упаковки.

Полный текст составляет 6629 слов, предполагаемое время чтения — 17 минут.

01 Предисловие

Компиляторы мини-программ необходимы на всех этапах разработки, предварительного просмотра и выпуска мини-программ, поэтому производительность компилятора напрямую влияет на эффективность разработки и опыт использования инструментов разработчика.

Поскольку старая версия компилятора (на основе webpack4) очень медленная при сборке больших проектов и использует большой объем памяти, разработчики жаловались на нее. После долгих исследований и разработок мы, наконец, приняли полностью самостоятельно разработанную архитектуру для новой компиляции, сделали множество оптимизаций для создания небольших программных проектов и в основном решили проблемы старой компиляции.

На следующем рисунке показано сравнение сроков строительства некоторых проектов:

Новая версия компилятора обеспечивает повышение производительности в 2–7 раз по сравнению со старой версией и поддерживает такие функции, как компиляция в реальном времени и горячая перезагрузка, занимает меньше памяти и создает более качественные продукты.

Ниже представлен путь разработки нового компилятора с точки зрения выбора платформы, принципа работы нового компилятора, производительности и методов оптимизации продукта.

02 Выбор кадра

При проектировании новой версии компилятора необходимо уточнить текущую болевую проблему: производительность, и расставить приоритеты в решении проблем с производительностью. Также реализованы другие новые методы и идеи, полезные для компилятора.

Старая версия компилятора на основе webpack4 имеет следующие проблемы:

  • Большие проекты строятся слишком медленно.

  • Запуск dev медленный, а инкрементная компиляция медленная. Он поддерживает только кэширование загрузчика, а пакеты без кэширования также медленнее.

  • Разработка расширений на основе webpack4 требует исправления некоторых модулей для работы, что затрудняет обслуживание.

  • Часть процесса сборки веб-пакета не может быть оптимизирована для структуры кода апплета, и имеются недопустимые сборки.

Недавно составленные цели дизайна:

  • Ускорена полная скорость компиляции и исключен недопустимый процесс сборки веб-пакета.

  • Поддерживает полное кэширование для ускорения первой и инкрементной компиляции.

  • Поддерживает компиляцию в реальном времени, сокращая время запуска разработки и вторичной компиляции.

  • Поддерживает многопоточное ускорение компиляции и горячую перезагрузку страницы.

  • Оптимизируйте структуру продукта и сократите его объем.

2.1 Основные инструменты сборки

Ниже представлены основные инструменты разработки интерфейса, которые мы исследовали. Каждый инструмент имеет применимые сценарии, преимущества и недостатки.

При разработке новой версии архитектуры компилятора стоит обратиться к концепциям проектирования и техническим особенностям других инструментов сборки.

Процесс сборки веб-пакета:

Преимущества Webpack : полный набор функций, активное сообщество, широкие возможности настройки и сильная масштабируемость.

Недостатки Webpack : сложная конфигурация, медленная скорость сборки и сложность вторичной разработки.

Процесс формирования посылки:

Преимущества Parcel : не требуется настройка, высокая скорость построения, встроенная поддержка многопоточности и полного кэша, обмен данными между несколькими потоками осуществляется через lmdb, что позволяет избежать накладных расходов на межпотоковую связь.

Недостатки Parcel : небольшая экосистема, ограниченная настройка, широкое использование плагинов Node и плохая совместимость.

Процесс сборки Vite:

Преимущества Vite : относительно простая настройка, компиляция по требованию, быстрый запуск и хороший опыт во время разработки.

Недостатки Vite : экосистема небольшая, и существует два набора процессов сборки для разработки и выпуска.

Другие мини-программные платформы:

  • WeChat создает небольшие программы на основе модулей gulp и C++, а также предварительно собирает модули npm, что обеспечивает лучшую производительность и удобство разработки.

  • Alipay создает небольшие программы на основе веб-пакета и использует esbuild для ускорения сжатия кода.

  • Мини-программа Douyin использует компилятор собственной разработки, а процесс ее создания относительно прост.

2.2 Новая версия компилятора

При разработке новой среды компиляции мы извлекли уроки из рабочего процесса основных инструментов упаковки в сочетании с характеристиками кода мини-программы и решили не создавать универсальный инструмент упаковки, сосредоточившись на оптимизации производительности упаковки мини-программы.

Наконец, мы выбрали решение самостоятельно разработанного компилятора и проделали большую работу по оптимизации.Точки оптимизации новой версии компилятора включают в себя следующие аспекты:

1. Поддержка совместной работы нескольких компиляторов для разделения создания нескольких типов проектов, таких как разработка динамических библиотек.

2. Весь процесс кэшируется на этапе компиляции, что экономит более 90 % времени вторичной сборки.

В разработке 3.dev по умолчанию используется компиляция по требованию для повышения производительности компиляции одной страницы.

4. Поддерживает многопоточную компиляцию Babel и swc, увеличивая полную скорость компиляции от 2 до 7 раз.

5. Примите новую версию протокола исходной карты, удалите ненужный анализ и слияние и значительно сократите время, затрачиваемое на этапе сборки.

6. Оптимизация разметки во время сборки была выполнена для компиляции шаблонов js, css и Swan, чтобы сократить время слияния пакетов.

7. Для сжатия и обфускации js на этапах предварительного просмотра и выпуска используется параллельное решение terser и esbuild. esbuild используется для быстрого создания пакетов предварительного просмотра, а terser может обеспечить степень сжатия для пакетов выпуска.

Судя по результатам, новый компилятор значительно улучшен по сравнению со старой версией с точки зрения скорости, использования ресурсов и удобства сопровождения.

03 Как работает новая версия компилятора

Поток обработки нового компилятора аналогичен потоку обработки посылки. Компилятор управляет потоком обработки, а процессор выполняет преобразование кода. Основной поток выглядит следующим образом:

Несколько важных модулей:

  • Компилятор CompileEntry — это входной модуль, включающий взаимодействие с помощью cli, взаимодействие с сервером разработки, вызов команд и т. д.

  • CompileManager — это менеджер компиляции, используемый для загрузки и управления зависимыми ресурсами, а также для совместной сборки нескольких компиляторов.

  • Компилятор — это модуль компилятора, используемый для компиляции исходного кода проекта в код среды выполнения. При создании проекта может использоваться несколько компиляторов.

  • Процессор — это модульный процессор, используемый для выполнения отдельных задач компиляции, таких как преобразование кода и слияние кода.

Примечание . Существует 1 компилятор для проекта приложения мини-программы и 2 компилятора для проектов динамической библиотеки и динамических расширений.

3.1 Компилятор компилятор

Используется для компиляции одного небольшого программного проекта и компиляции исходного кода разработчика в работоспособный код.

должностные обязанности:

1. Создайте рабочий контекст и предоставьте конфигурацию, обработку файлов fs, мониторинг наблюдателя, регистратор и другие модули для использования процессором.

2. Полная компиляция и вторая компиляция при изменении файлов, вторая компиляция здесь тоже проходит полный процесс компиляции, но в большинстве случаев используются кэшированные результаты.

3. Управляйте, планируйте и запускайте процессорный блок.

4. Поддерживать зависимости процессора и кэш результатов.

Функции:

1. Внедрить полное кэширование процессов и записать входные параметры и выходные результаты каждого процессора в кеш. Благодаря кэшированию время вторичной компиляции может быть сокращено на 90%.

2. Поддерживает компиляцию по требованию.Каждая компиляция одной страницы по требованию, инкрементальная компиляция и полная компиляция выполняются в одном и том же процессе обработки процессором.

3. Автоматически рассчитывать зависимости параметров кэша с помощью механизма прокси, устраняя необходимость вручную генерировать хэши кэша для каждого процессора, уменьшая количество ошибок по сравнению с веб-пакетом или посылкой.

4. Поддерживается только зависимость процессора, а ModuleGraph не поддерживается, что упрощает процесс обработки.

Что касается полного кэширования процессов, каждый упаковщик имеет свой собственный план реализации.Основной принцип заключается в создании уникального хеша для блока обработки на основе текущих входных параметров и зависимостей.Если хэши согласованы, результаты будут согласованными.

Поскольку веб-пакет и пакет поддерживают ModuleGraph, вычисление и повторное использование кеша будут более сложными. Компилятор апплета выполняет вычисления только на основе входных параметров процессора и зависимостей вызовов.

3.2 Процессорный блок процессора

Процессор имеет следующие характеристики:

1. Когда входные параметры согласованы, выходные данные гарантированно будут согласованными. Как входные, так и выходные данные должны быть сериализуемы в json, реализуя полный кеш процессора.

2. URI в процессоре — это идентификатор сборки. Если идентификатор одинаков в течение одной сборки, результаты обработки будут одинаковыми. Например, при обработке файла app.js URI имеет вид: js:app.js. Преимущество заключается в том, что путь обработки ресурсов процессора может быть унифицирован.

3. Процессоры поддерживают вызовы друг друга: ProcessWith вызывает и продолжает выполнение, ProcessWithResult вызывает и ждет возвращаемого результата.

Примечание . Входные параметры здесь включают uri, конфигурацию приложения, contextFreeData.

Несколько часто используемых процессоров:

1.JS-процессор преобразует код es6 в код es5, что является наиболее трудоемким модулем.

2.Swan Processor преобразует код шаблона лебедя в js-код слоя представления.

3.Css Processor использует postcss для преобразования единиц измерения, сбора зависимостей и другой работы в css.

4. Процессор пакета объединяет файлы, обработанные предыдущим преобразователем, в соответствии с алгоритмом пакета и выводит результаты.

Рабочий процесс процессора:

Поток обработки процессора должен пройти процесс преобразования -> пакет. В мини-программе пакеты шаблонов js, css и лебедя могут обрабатываться отдельно и параллельно. Это отличается от режима обработки веб-пакета, и аналогично конвейеру посылок.

3.3 Методы оптимизации производительности и продукта

3.3.1 Оптимизация многоядерной компиляции

Поскольку скорость инициализации и эффективность связи многопоточного модуля в Node лучше, чем у многопроцессного, новая компиляция предпочитает использовать многопоточность для многоядерной оптимизации.

Есть 2 варианта многопоточной компиляции:

  • Вариант 1: многопоточное планирование на основе процессоров.Поскольку процессоры поддерживают взаимные вызовы, фактическая обработка будет очень сложной и потребует затрат на связь.

  • Старый компилятор создал загрузчик рабочего потока на основе веб-пакета, и прирост производительности был ограниченным (10–15%).

  • Parcel — лучшее решение, основанное на общедоступном кэше lmdb, позволяющее исключить межпотоковую связь и обеспечить эффективность чтения и записи.

  • Вариант 2. Выполняйте многопоточное планирование только для перевода js, затрачивая только две затраты на связь.

  • Используйте jest-worker и Babel Transform для многопоточного перевода js или используйте многопоточный swc для перевода js.

Поскольку большая часть времени сборки уходит на трансляцию js (в js много зависимостей node_modules, все из которых необходимо конвертировать), преобразование модулей css и Swan занимает меньше времени.

Последний вариант 2 выполняет только многопоточную трансляцию js. Процесс обработки прост, а преимущества лучше. Общее улучшение заключается в следующем:

  • Используя многопоточный вавилонский перевод jest-worker, 4 потока позволяют увеличить скорость более чем в 1 раз.

  • Используя swc для перевода js, 4 потока увеличивают скорость более чем в 4 раза.

Многопоточность процессора JS:

в:

uri : создайте идентификатор процессора.

contextFreeData : неизменяемые данные в одной сборке, например элементы конфигурации в app.json.

аргументы контекста : глобальные параметры, такие как переключатель эксперимента по оптимизации, многопоточный переключатель и т. д.

В обработке преобразования js предусмотрен унифицированный интерфейс преобразования преобразователя. На основе интерфейса реализованы три типа процессоров: однопоточный Babel, многопоточный Babel и преобразование swc, при этом переключение процессора может выполняться в любое время.

Гибкие настройки могут быть сделаны для разных сред компиляции:

1. В инструментах разработчика разработчики могут переключаться между режимами многопоточности и компиляции swc в соответствии с конфигурацией машины для повышения эффективности.

2. Конвейер облачной компиляции по умолчанию включает многопоточную компиляцию для повышения производительности.

3. webIDE по умолчанию открывает один поток для снижения потребления ресурсов.

3.3.2 Оптимизация компиляции SWC

По сравнению со старой компиляцией, многопоточный режим нового компилятора улучшен примерно в 1 раз.Во время дев-разработки первая компиляция некоторых больших страниц проекта все еще немного медленная, занимает более 10 секунд, в основном на js трансформировать.

В настоящее время swc в основном развит в переводе js, и большинство сценариев могут увеличить скорость перевода более чем в 4 раза. Поэтому была добавлена ​​поддержка многопоточного перевода swc, и первую компиляцию больших страниц проекта можно контролировать в течение 5 секунд.

Для адаптации к переводу SWC необходимо написать два плагина swc:

  • @swanide/swc-require-rename извлечет информацию о пути модуля в require/import/export, чтобы облегчить последующий анализ зависимостей модуля в js.

  • @swanide/swc-web-debug выполняет инструментальную обработку кода js для поддержки отладки точек останова при отладке реальной машины.

Улучшение производительности, обеспечиваемое компиляцией swc, огромно, но во время использования также были обнаружены некоторые проблемы:

1. В swc произошла утечка памяти. Если на этапе разработки количество полных компиляций слишком велико, это приведет к высокому использованию памяти, и компилятор придется перезапускать вручную.

2. Плагин swc поддерживает меньше API, а некоторые функции, которые легко реализовать с помощью Babel, сложно реализовать в SWC.

3. Поскольку для написания плагинов swc использует Rust, плагины нельзя использовать между разными версиями @swc/core. Плагины Swc необходимо создавать для разных платформ, что будет сложнее при развертывании.

При фактическом использовании в некоторых сценариях, с которыми swc не может справиться должным образом, для обработки его уровень будет понижен до Babel.

3.3.3 Сжатие кода и кэширование во время выполнения

На этапе разработки скомпилированный код не сжимается и его можно запускать в симуляторе. Из-за ограничения размера пакета на этапе предварительной версии для уменьшения размера продукта требуется сжатие кода.

Существует три дополнительных инструмента сжатия кода:

1. terser имеет высокую степень сжатия, небольшой объем продукта и самую медленную скорость.

2.swc сжимается быстро, поддержка mangle неполная, степень сжатия низкая.

3.esbuild имеет самое быстрое сжатие (более чем в 10 раз быстрее, чем terser), поддерживает mangle, а скорость сжатия кода не так хороша, как terser.

В итоге после сравнения и рассмотрения была выбрана следующая схема сжатия:

1. Поскольку на этапе предварительного просмотра нет необходимости в исходной карте, удалите исходную карту и используйте esbuild для сжатия кода, чтобы повысить скорость предварительного просмотра (большое улучшение для сцен автоматического предварительного просмотра).

2. Используйте terser для многопоточного сжатия на этапе выпуска и сохраните исходную карту.

Кэширование во время выполнения означает, что промежуточные результаты процесса сборки кэшируются в памяти, включая результаты обработки процессора и результаты сжатия кода, что позволяет сэкономить большую часть времени на пересборку во время второй сборки. Поскольку строки и объекты json сохраняются в кеше, экономия памяти составляет от 40% до 60% по сравнению со старым компилятором на основе веб-пакета, что находится в пределах допустимого диапазона с точки зрения использования памяти.

3.3.4 Оптимизация обработки шаблона Swan

В старой обработке шаблона Swan используется Swan-Loader для преобразования шаблона. Поскольку область импорта шаблона не обрабатывается должным образом во время разработки, тег <template> и функция фильтра фильтра могут быть встроены только в код страницы. Если шаблон широко используется в шаблона и фильтра, размер конечного сгенерированного кода будет очень большим.

Новый компилятор исправляет взаимосвязь области импорта, изменяет режимы генерации шаблонов и фильтров в скомпилированном продукте со встроенного на требование ссылки, а затем объединяет код на этапе пакета, чтобы одни и те же модули можно было использовать повторно, что заполняет большую дыру. .

Новый процесс обработки шаблона лебедя компилятора:

Возможные продукты после обработки процессором одного файла Swan:

  • модуль компонента компонента, используемый для создания страниц и пользовательских компонентов.

  • модуль шаблона

  • функция фильтра фильтра, функция фильтра sjs

  • промежуточный код преобразованного документа

Преобразуйте шаблоны Swan в различные типы js-модулей и сохраняйте зависимости, чтобы обеспечить более точный контроль во время последующего слияния кода.

По историческим причинам модуль шаблона не может быть сгенерирован напрямую, если импорт/включение содержит ссылки на sjs или шаблоны. Его необходимо сгенерировать в окончательном шаблоне записи. Новая компиляция также предоставляет параметры статической компиляции шаблонов, которые строго ограничивают объем импорта и напрямую генерируют код модуля шаблона.Для небольших программных проектов, созданных taro, это может сэкономить около 30% размера продукта.

3.3.5 Оптимизация исходной карты

Поскольку компилятору необходимо поддерживать отладку js-кода и отслеживание ошибок во время выполнения, карты исходного кода необходимо создавать как на этапе разработки, так и на этапе выпуска.

При генерации кода в веб-пакете карты исходного кода необходимо объединять и рассчитывать. Для более крупных проектов объединение исходных карт займет много времени, и карты исходного кода необходимо пересчитывать каждый раз при их перекомпиляции.

В ходе исследования я обнаружил, что инструменты разработчика браузера очень хорошо поддерживают карту индексов протокола исходной карты. Новый компилятор выполнил оптимизацию слияния исходной карты на основе протокола карты индекса. Предыдущий расчет слияния нескольких файлов исходной карты стал расчетом. для создания карты смещения и объединения содержимого. Таким образом, время, затрачиваемое пакетом js, изменилось с нескольких секунд до десятков секунд до фиксированного времени менее 3 секунд.

Интересно то, что js-отладчик vscode не поддерживал отладку карты индексов до 22 июня (карта индексов была выпущена в 2011 году), а действия Microsoft были немного медленнее.

3.3.6 Последующая работа

При продвижении нового компилятора после завершения разработки принят метод прогрессивного продвижения:

На первом этапе сосуществуют новый и старый компиляторы инструментов разработчика, разработка и предварительная версия используют новый компилятор, а выпуск использует старый компилятор.

На втором этапе все предварительные версии и выпуски внутреннего конвейера используют новую компиляцию.

На третьем этапе все инструменты разработчика переводятся на новый компилятор.

После того, как новая версия скомпилирована и фактически опубликована в Интернете, все еще остаются некоторые незначительные проблемы совместимости.Необходимо выявить проблемы как можно раньше, прежде чем можно будет выпустить полную замену.

Для небольших программных проектов новая компиляция проделала большую работу по оптимизации, а некоторые работы по оптимизации еще не завершены, в том числе:

Горячая перезагрузка HMR : во время разработки, поскольку среда выполнения и инструменты разработчика требуют адаптации интерфейса, отладка занимает много времени, чтобы оправдать ожидания.

Устранение кода встряхивания дерева . Для модулей es6 код встряхивания дерева можно устранить на этапе преобразования.

Scope-Hoisting Scope Hoisting : теоретически осуществимо, эффект сокращения кода необходимо проверить.

Поскольку новая версия компилятора должна быть полностью совместима с результатами сборки старой версии компилятора, в сценарии упаковки пакета все еще есть место для оптимизации. Мы можем провести дополнительную оптимизацию упакованных продуктов в сочетании со средой выполнения. рамки в последующей работе.

04 Резюме

В новой версии компилятора используется самостоятельно разработанное пакетное решение.По сравнению со старым компилятором на основе веб-пакета, он добился огромного улучшения производительности, полностью решая проблемы медленной компиляции и высокого использования ресурсов.Он также имеет хорошие преимущества в производительности по сравнению с составители конкурентов.

Некоторые методы оптимизации, представленные новой компиляцией, такие как перевод SWC, сжатие esbuild и оптимизация исходной карты, также могут использоваться при создании других внешних проектов и иметь эффект ускорения.

В новом проекте компилятора каждый студент очень усердно работал и внес много замечательных идей, и большинство возникших проблем были эффективно решены. Мы продолжим придерживаться двух направлений: производительность и оптимизация продукта, а также постоянно улучшать опыт разработчиков и эффективность выполнения.

--КОНЕЦ--

Рекомендуем к прочтению

Практика оптимизации пакета iOS приложения Baidu размером 50M (6) Бесполезная очистка метода

Стратегия перехвата и распространения проблем в реальном времени, основанная на аномальных онлайн-сценариях

Чрезвычайно оптимизированное планирование параллельного чтения SSD

Практика создания и публикации текстов с помощью ИИ в приложении Baidu

DeeTune: проектирование и применение сетевой инфраструктуры Baidu на основе eBPF

Оштрафован на 200 юаней и конфисковано более 1 миллиона юаней Ю Юйси: важность высококачественных китайских документов Жесткий сервер миграции Маска Solon для JDK 21, виртуальные потоки невероятны! ! ! Контроль перегрузки TCP спасает Интернет Flutter для OpenHarmony уже здесь Срок LTS ядра Linux будет восстановлен с 6 до 2 лет Go 1.22 исправит ошибку переменной цикла for Svelte построила «новое колесо» — руны Google отмечает свое 25-летие
{{o.name}}
{{м.имя}}

рекомендация

отmy.oschina.net/u/4939618/blog/10114374
рекомендация