Pull to refresh

Comments 69

Огромное количество файлов очень хорошо оптимизируется технологией, которая у нас проходит под псевдонимом UnityPack. Рассматривали? Это представление всех cpp файлов как одного единого файла. В идеале на выходе компилятора для линковки получается один объектник. Мы в результате добились примерно той же скорости сборки проекта, но избавились от терминов "разогретая" и "холодная" сборка (есть полный кэш или все новое).

Эм, ну убить инкрементальную сборку, так себе вариант. И подозреваю, что проблема ни только в количестве файлов, но и количестве строк кода.

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

Для типичного кейса разработчика(один раз собрал, исправил или подтянул изменения из гита), инкрементальная сборка почти всегда будет быстрой. У меня был проект, который собирался полностью за 2 часа на 12 ядернике и M.2 SSD, и инкрементально за пару минут, но там был ninja.

UFO just landed and posted this here

Ещё чуть-чуть и можно придумать динамические библиотеки.

UFO just landed and posted this here

Имеено так, да. С юнити файлами можно тюнить N, не теряя распределенности и ускоряя сборку. Более того, если речь идет о кодогенерённом C++, то тут кажется вообще можно всё относительно несложно сделать. Кодогенерация однообразна и может автоматически подготовить такую кодовую базу к юнити сборкам (в нашем случае moc и midl идеально встроились).

Мы тут писали немного о нашем опыте с другой системой сборки
Как мы ускорили сборку CAD-программы на С++ в несколько раз / Хабр (habr.com)

Как это работает с конфликтами анонимных неймспейсов и static функций/переменных?

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

Если через некоторое время отказаться от данного подхода, то придется руками написать овер9000 новых include, которые раньше не писали, потому что их подключал какой-нибудь другой файл, который в "склейке" идет раньше.

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

Сборщик суперфайла можно настроить на игнорирование некоторых файлов по желаемым признакам (ручным или автоматическим) - на скорость сборки до определенного количества это сильно не повлияет, но облегчит этап преодоления внезапных несовместимостей.

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

Ребят, по-моему вам проще сразу писать на C++. Современный C++ это практически совершенно новый язык.

Я думаю, проблема уже в том, что нужно будет переписать все на с++

А кэширование отрабатывает код типа:

#define OPTION_USED_IN_HEADER
#include "header.h"

?

В этом случае хэш "header.h" должен отличаться от хэша "header.h" без использования объявления (define) OPTION_USED_IN_HEADER

Ну непосредственно в этом случае SHA-HASH *.c файла будет отличаться от предыдущей сборки (что автоматически кэш-мис).

А вот что делать, если опция подана через систему сборки -DSOME_DEFINE - вот это интересный вариант

Так опции же тоже в хеш входят

Рассматривали ли bazel и его удаленное исполнение? Если да, то чем он не подошёл?

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

Bazel это всё-таки система сборки, ВМЕСТО Cmake/make. В нашем случае, когда 200к файлов это автоген, то чтобы заюзать Bazel, помимо собственно cpp-шных исходников, пришлось бы генерить Bazel-проект (конфиг?), содержащий ссылки на эти все файлы или glob-выборки. И потом запускать Bazel для сборки бинарника.

Следовательно, Bazel стал бы анализировать автоген как отдельный плюсовый проект. Стал бы чекать, что изменилось, а что нет — для запуска инкрементальной компиляции. И если на перекомпиляции с нуля в чистой папке это допустимо, то в случае инкрементальной компиляции — уже долго.

В случае KPHP, поскольку он сам и так знает, что там за дифф (он же его генерит и записывает), он просто запускает CXX (g++ или nocc g++) для нужных cpp.

Если отображние PHP-файлов на плюсовые файлы фиксированное (одинаковое для всех PHP файлов), то можно написать макрос, включающий и правило генерации из PHP, и правила компиляции уже генеренного кода. Как бонус получаем ещё кеширование генерации и распараллеливание её на удаленных хостах.

Если же отображение зависит от исходного кода, то так не получится. Посмотрел немного доки KPHP - похоже, что набор генерируемых файлов зависит от набора функций и классов в исходном коде. Так что в текущем виде bazel и правда не подходит.

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

Мы тут миграцию на KPHP сделали, теперь приходится работать в режиме "это почти С++" %)) Хотя быстрая проверка алгоритмов в режиме PHP тоже доступна. Во вторник статью выпущу про нашу миграцию.

Если всё время компилируется всего несколько файлов, а связывание всё-равно происходит локально, то не проще сделать общий ccache? Только научить его различать файлы по хэшам.

Сами хэши, кстати, можно из git брать. Чтоб не пересчитывать постоянно

Интересно бы сравнить с гугловым gomacc.
Он тоже распределенный и с кешированием.

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

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

Но сравнить интересно, да. Звучит как задание для какого-нибудь стажёра в будущем :))

Зашёл сегодня во вконтактик, а там реклама ЧВК Вагнер в ленте.
И вот читаю статью и обуревают двойственные мысли. С одной стороны крутые штуки делаете, с другой стороны, для чего эти крутые штуки используются в итоге.

А что крутого в генерации 200 тыс. файлов из ПХП? Тут плакать хочется скорее.

Как я понимаю, дерево исходников синхронизируется между нодами средствами самого nocc?

А если использовать кеширование средствами файловой системы nfs? т.е. централизованно дерево исходников на одном сервере, шарится по nfs, при чтении кешируется cachefile каждой нодой самостоятельно и прозрачно

Вероятно, заработает, если нет макросов внутри инклудов.
не понял про этот момент, ваш инструмент постройки дерева зависимостей не умеет препроцессор?

Как я понимаю, дерево исходников синхронизируется между нодами средствами самого nocc?

Между серверными нодами ничего не нужно синхронизировать: для компиляции a.cpp на сервере S1 достаточно, чтобы все зависимости рекурсивно находились на сервере S1. Они не нужны на S2, S3 и т.д. Ведь a.cpp попадает всегда на S1 (по имени файла).

ваш инструмент постройки дерева зависимостей не умеет препроцессор?

Чтобы определить все зависимости #include рекурсивно (а это делается на клиенте, т.е. для каждого из 200к файлов), используется кастомная парсилка инклудов. `#include "some-file.h"` она зарезолвит, а вот `#include GENERATE_FILENAME(...)` уже нет: здесь без запуска препроцессора на стороне клиента обойтись никак. В нашем случае — и в большинстве случаев в целом — пути к инклудам статичные, без макросов. Кастомную парсилку можно отключить, что приведёт к вызову препроцессора локально на каждый cpp, но это конечно сразу будет дольше.

Между серверными нодами ничего не нужно синхронизировать
для того чтобы компилировать один .cpp, нужно чтобы компилятор имел под рукой (локальной в виде файлов или через stdin или через пайпы) сам этот файл и все его include по всему дереву зависимостей

на сколько я помню distcc каждый раз перемещает по сети все необходимые файлы и не кеширует их, что по сети очень накладно (возможно это дает дополнительный оверхед?)

Конечно, для .cpp нужно скопировать все include по всему дереву. nocc ровно это и делает (1 .cpp + 49 .h загружает, например). Впоследствии, даже если сам .cpp изменится — большинство include'ов из дерева зависимостей окажутся уже загруженными (1 .cpp + 2 .h, условно, остальные 47 уже там).

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

вот я и спрашиваю, что не лучше ли складывать все файлы включая результат прекомпиляции pch на сервере и пусть его кешируют slave ноды компиляции автоматически, а не транслируют по мере необходимости (а она 100% будет) каждый раз когда компиляция запускается?
А мне стало интересно, а сколько же времени занимает линковка 200 тыс. файлов и какой итоговый размер бинарника?

Долго :) Дольше, чем в итоге компиляция с нуля.

Мы используем partial linking: условно, эти 200к файлов разбиты на 100 папочек, по 2к каждов в каждой. Каждая папочка линкуется отдельно (получается 100 объектников) — это можно делать параллельно, делается весьма быстро. А потом 100 объектников линкуются в один большой. И вот это уже долго.

Мы используем lld. Итоговый бинарь линкуется почти 2 минуты, и не очень понятно, что с этим сделать. Когда был просто ld — было почти в 3 раза дольше, всё-таки lld значительно шустрее.

Пробовали завести новый модный mold linker (https://github.com/rui314/mold) — не срослось, он выдаёт закоррапченные бинарники, которые не запускаются, причём нестабильно, как повезёт.

Не секрет ли, какой размер итогового бинарника (с отладкой и без)? Просто любопытны масштабы.

Не секрет :)

С дебаг-символами около 6.5 ГБ.

Без дебаг-символов (стрипнутый) — 1.3 ГБ.

На продакшене крутится стрипнутый бинарь (именно он раскидывается на тысячи бекендов и обслуживает http-запросы). А бинарь с дебаг-символами лежит отдельно и нужен, чтобы запускать addr2line на нём в случае проблем (по адресам, полученным с продового бинарника).

Спасибо, было интересно узнать.
А ещё можете описать процесс как происходит разработка и сколько времени занимает посмотреть результат на машине разработчика?

То есть человек правит строчку, компилирует бинарник - около 70-80 секунд, потом линковка под 100-200 секунд. А потом сам запуск бинарника (сколько это времени занимает с учётом подключения к какой-нибудь БД с данными)? Ну и докликать до результата (я думаю, что там разработчик сразу по ссылке куда-то переходит, чтобы посмотреть результат).

Как больно разрабатывать такой бекенд? :) Мне это любопытно. Может быть у вас есть какой-нибудь dynamic linking библиотек, чтобы не перезапускать бекенд каждый раз.

А вот здесь всё не так :)

Мы пользуемся тем, что мы написаны на PHP. Поэтому VK разрабатывается и прекрасно работает на обычном PHP тоже (только медленно).

Так что бекендер правит строчку в IDE — автоматически через SFTP зеркалится на сервер — и всё. Никакой компиляции. Только интерпретация, будто обычный PHP-сайтик.

Так что разрабатывается на PHP. Юнит-тесты тоже (PHPUnit это всякие там моки, рефлексия — в KPHP этого нет и не должно быть). А KPHP-сборка — это только для продакшена. Базовый флоу именно такой.

Ну и в гит хуках, когда создаёшь MR'ы всякие, там KPHP тоже прогоняется — но там просто трансляция PHP->C++, а это быстро (сборка и линковка не нужны). Предполагаем, что если KPHP на фазе трансляции не упал, то код валиден и конечный C++ на проде уже соберётся и будет работать ровно как изначальный PHP.

Поэтому — совсем не больно разрабатывать такой бекенд :)

А где тогда используется такая сборка на nocc, если большинство разработчиков разрабатывают на php?

Ну, я чуть упростил картину, конечно. Разрабатывают действительно на обычном PHP. А вот когда нужно: если хотят полазить по быстрой версии сайта / если хотят убедиться, что на KPHP тоже работает так же (особенно что касается корутин, параллелизации и других штук, которые реализованных в PHP через полифиллы) / выложить ветку для тестировщиков — тогда и нужна полная сборка. Для тестировщиков, например, разные версии сайта от разных разработчиков деплоятся больше сотни раз за день.

Спасибо вам ещё раз. А можно последний вопрос?

Сколько по времени занимает запуск одного бинарника (в проде) такого размера (влияет ли на это время размер файла)? Наверняка, ещё там всякие соединения/кеши запускаются, что-то инициализируются, сколько ещё времени нужно, чтобы бекенд стал «готовым к работе»?

Запускается, на самом деле, достаточно быстро. Там скорее сложность другая, ведь нельзя погасить старый бинарник и запустить новый вместо него — ведь старый в режиме нон-стоп обрабатывает запросы. Вместо этого используется graceful restart: поднимается рядом новый бинарник и начинает постепенно "утягивать" новые коннекты со старого, а старый продолжает работать, пока не завершит последний скрипт, и потом умирает. Соответственно, за это время, пока коннекты плавно перетекают, сам собой происходит прогрев локальных кешей и другая предварительная инициализация.

А вот раскидывать бинарник такого размера на много тысяч бекендов, даже через gossip deploy — вот это и правда долго, несколько минут :(

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

А как это реализовано?

У kphp сервера есть специальный файлик в разделяемой памяти (см. shm_open).
Когда новый сервер стартует, он через этот специальный файлик связывается со старым сервером, и начинается graceful restart.
Сначала старый сервер через UNIX сокет с помощью SCM_RIGHTS посылает новому открые файловые дескрипторы нужных серверных коннектов.
Затем старый сервер начинает плавно тушить своих воркеров (в kphp prefork сервер), в то время как новый поднимает своих.
В итоге, когда воркеров больше не остается, старый сервер завершается, и получается бесшовный рестарт.

черт вот это интересно, речь именно о передаче текущих открытых соединений между двумя процессами, чтобы второй процесс продолжил их обрабатывать?

можно как то по подробнее что ли?

Да, именно об этом. Все благодаря SCM_RIGHTS.
По UNIX сокету просто передается массив чисел - открытых файловых дескрипторов. Дальше вся магия происходит в kernel space: происходит что-то типа dup файловых дескрипторов из таблицы открытых файлов одного процесса в таблицу открытых файлов другого. В итоге на принимающей стороне в user space просто отдаются полученные файловые дескрипторы.
Сами числа файловых дескрипторов могут отличаться, но они будут указывать на те же записи в системной таблице файлов.

Есть хорошая статья от cloudflare на эту тему.

Еще можно почитать man unix, man open - там довольно хорошо описано.

Выглядит, как какой-то сюр для меня. Я бы поверил, если бы речь шла о бинарнике, представляющем собой AI, не отличимый от человека. Какую-нибудь супер-СУБД с гениальным планировщиком запросов и оптимизатором.

Но какой такой логикой можно НАСТОЛЬКО раздуть бинарник бэкенда соцсети?

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

Ядра ОС, опять таки, решают намного более сложные и разнообразные проблемы, а бинарники занимают не так много.

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

О! Это элементарно! У нас как раз то, о чем говорите "планировщик, оптимизатор", и тд, но для расписания проектов. Общая сборка: 21.000 целей для сборки после KPHP. На выходе c -ggdb почти 2 гига бинарник, без этого 211M. Из них сам рантайм (реализация всех PHP-функций) где-то 70М весит.

Хотя на входе исходных файлов меньше, около 5000. При этом У нас автогенеренного кода еще много-много создаётся (ибо нету в KPHP рефлексии , пришлось написать).

Поэтому, основной объём идёт чисто от автогенерации кода, которая нужна для ускорения. А сам планировщик - там кода очень немного, всего 90 файлов.

Если уж честно, то я сам не понимаю, почему НАСТОЛЬКО много PHP-кода. Иногда поглядываю статистику и ужасаюсь: капец, за полгода ещё миллион строчек добавили, ну как??? Бедный, думаю, KPHP, как он вообще справляется. Но уж что имеем, то имеем. Проблема всех больших компаний, а также монореп с бесконечной цикломатичностью кода ( И уж явно не компилятора.

Спасибо за статью. Подходит ли nocc для сборок с несколькими версиями компилятора? Например при сборке под несколько платформ: Intel, arm. Учитываете ли вы проверку контрольной суммы бинарника компилятора при составлении ключа для объектного файла, как ccache?

Предполагается, что на всех серверах компилятор одинаковый — ровно тот же самый, что и локально. То есть не важно, где исполнить `cxx 1.cpp` — локально или на сервере Х. Даже если везде g++, но разных версий — я считаю это undefined behaviour. Можно добавить какие-то проверки, но мне кажется, это должно решаться именно на уровне конфигурирования.

Поэтому, если nocc-server поставить на ARM'овые сервера, то всё заработает (проверяли).

Кросс-компиляцию тоже можно поддержать, добавив анализ -sysroot / -isysroot, поиск хедеров в нужных папках на клиенте и подмену этих опций на сервере. Я просто их не добавлял на данный момент, но это не сложно.

Статья вызывает у меня чувство гнева. К авторам вопрос к авторам - что за ДИЧЬ вы делаете? Ваша проблема лежит в другой плоскости - вы генерируете 200 000 (двести тысяч) фалов мусорных-исходников. При этом используете конвертацию из бедного и примитивного языка PHP в один из самых гибких и сложных языков C++. Зачем? Чтобы код на C++ был быстрым - он должен быть создан качественно изначально, с проработкой всех иерархических, структурных и архитектурных нюансов проекта и среды исполнения. И сейчас суть вашей проблемы - PHP->C++. Все остальное - ваши попытки натянуть сову на глобус.

P.S. Господа, не хочу никак никого оскорблять. Но тут на лицо эффект Даннинга-Крюгера у команды разработчиков. А другие читают подобное и, что самое страшное, могут ведь вдохновится и начать заниматься тем же самым - деградацией.

P.P.S. А потом участники таких проектов приходят на собеседование и не могут банально рассказать про то, как что такое BSS, TEXT, elf и чем отличается uint32_t* от void*. Зато они могут положить на лопатки 64 ядра с 5 ТБ ОЗУ на сборку проекта "рабасной" игры из ВК.

Всем добра!

Статья вызывает у меня чувство гнева.

Гнев - довольно сильное чувство. Забавно, что техническая статья может так триггерить.

Ваши нападки на меня и мою команду гнева у меня не вызывают, но вот демотивируют и вызывает некоторое удивление - да.

P.P.S. А потом участники таких проектов приходят на собеседование и не могут банально рассказать про то, как что такое BSS, TEXT, elf и чем отличается uint32_t* от void*. Зато они могут положить на лопатки 64 ядра с 5 ТБ ОЗУ на сборку проекта "рабасной" игры из ВК.

Как-то не очень похоже на "всем добра", какие-то осуждения и сомнения в квалификации. Для начала, я не считаю незнание чего-либо пороком, не знать что-то - это нормально. Я далеко не эксперт, но свой вклад сделал в более чем один компилятор (и язык программирования), сделал много статей и докладов, чтобы как-то делиться знаниями, веду более одного популярного open source проекта.

Ваши домыслы о людях, которых вы не знаете, весьма сомнительны на этом фоне. А ещё это не очень приятно и не вполне вежливо. Технологии и код подвергать критике - это ОК, за этим мы здесь и собрались. Но вот о людях так высказываться в этом контексте мне кажется лишним.

У всех бывает синдром самозванца и в целом быть уверенным в своих достижениях - это не так просто. Когда вы так обесцениваете всё, то лишь увеличиваете количество негатива. Вы же не думаете, что помогаете ими кому-то?

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

Спасибо за внимание.

Вы уж извините меня за прямоту и грубость, но дополню. Суть поста не о том, что проблема у вас с командой и проектом - личное дело каждого как ему зарабатывать на хлеб - разбивая большие камни на маленькие, или пройдя ускоренные курсы гикбрейнс начать зарабатывать в IT. Суть поста - что авторы создали проблему из-за своей безграничной узколобости и потом начали решать проблему через задний проход. И писать об этом, как о достижении - это неуважение (профессиональное) к читателю (имхо).

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

Выводы про людей я не делаю - я делаю выводы про специалистов. Это разное.

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

И писать об этом, как о достижении - это неуважение (профессиональное) к читателю (имхо).

А на сколько это "профессионально" и "уважительно" писать об авторах о "безграничной узколобости"?

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

Ну вы и мудак. Простите (нет)

Ну нет, не согласен. Проблема компиляции больших проектов все равно есть. Даже если бы тут все было руками на С++ изначально написано, компиляция была бы все также слишком медленной для одной машины. Возьмите chrome, например. Изначально он написан на С++, но без распределенного компилятора его собирать очень и очень долго. И предложенное тут решение — вполне хорошее.


Генерация кода С++ из PHP — не самое красивое решение, но оно работает. Если уж такой большой проект уже долго развивался на PHP, то переписать руками все просто невозможно, а весьма заметный припрост производительности это решение обеспечивает.

Переписать всегда можно, и даже инвестировать туда кучу ресурсов но... переход на С++ убьёт одну небольшую возможность: БЫСТРАЯ ПРОВЕРКА.

Мы после миграции на KPHP этим активно пользуемся, получается очень мощна связка: Быстрая проверка (в PHP режиме) и Быстрое исполнение (в KPHP сборке).

В С++ проекте чтобы проверить "А как оно выглядит" нужно ждать сборки, это даёт хороший эффект - архитектура становится лучше (потому что работает Закон Васильева). Но... замедляется проверка идей.

Закон Васильева о квалификации разработчика ПО: Время необходимое инженеру для достижения уровня "Профессионал" обратно пропорционально времени сборки сборки проекта.
Обоснование Закона: Чем дольше собирается проект, тем больше разработчик не хочет ждать этой сборки, тем тщательней он проектирует систему на бумаге. Тем быстрее растёт его квалификация в разработке ПО.
Доказательство Закона: сравните знания по ООП у С++ и веб-разработчика с трёх-летним стажем.

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


Но возможность тупо сразу запускать что угодно, хоть и медленнее — это реально круто.

UFO just landed and posted this here
При этом используете конвертацию из бедного и примитивного языка PHP в один из самых гибких и сложных языков C++. Зачем? Чтобы код на C++ был быстрым — он должен быть создан качественно изначально, с проработкой всех иерархических, структурных и архитектурных нюансов проекта и среды исполнения.


Ваш С++ уже настолько разжирел из-за желания комитета впихнуть туда как можно больше новых фишек и нежелания ломать обратную совместимость, что для того, чтобы разрабатывать со всей этой гибкостью и сложностью надо лет пять просидеть, изучая все функции и то, в каких случаях их лучше применять, а потом еще и тратить ощутимую долю рабочего времени для того, чтобы отслеживать все новинки в языке, иначе не дай бог случайно использовать что-то устаревшее.
Не адепту уж плюсов писать тут о том, какой PHP бедный. По сравнению с последними плюсами и пайтон бедный. Мешает это делать на нем софт? Да нифига.

И желание писать на чем угодно, только не на плюсах, и использовать для ускорения этого пусть даже немного экзотические инструменты команды вк я легко понимаю — лучше когда разработчики логики ленты изучают «ограниченный» и «бедный» язык за пол-года, чет вляпываются в С++ на год-другой, разбираясь как им пользоваться, а потом еще год живут интернами, разбираясь как этим пользоваться правильно.

А тем кому интересно по-максимуму поковыряться в си и том, как именно правильно применить инструменты из нового релиза для скорости, коммитят в KPHP.

К авторам вопрос к авторам - что за ДИЧЬ вы делаете? Ваша проблема лежит
в другой плоскости - вы генерируете 200 000 (двести тысяч) фалов
мусорных-исходников.

Так можно же посчитать. Допустим использование KPHP дало им 600% ускорения, при этом их приложение запускается на N серверов. Для поддержания функционирования KPHP им нужно M серверов, на которых запущен обсуждаемый в статье nocc. Если N = 1000, а M скажем равен 10, то это кажется выигрышной стратегией.

Возможно если бы они сразу генерировали что-нибудь типа LLVM IR вместо C/C++, то вместо M=10 хватило бы M = 5. Но даже так это весьма выигрышная стратегия.

Такой огород и все это для товарища майора.

Кажется, с отладкой тут могут возникнуть проблемы. В отладочные символы входит информация о каждом исходнике с его абсолютным путём. А если прилетит "винегрет", где часть файлов в одном месте, другая - распылена по разным /tmp/XYZ - с этим уже сложно. Наверное, для автогенерёного кода это ок (туда всё равно никто не полезет), но вот с реальными, писанными людьми файлами - уже не очень.

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

CMake из коробки умеет Unity Builds: склеивать .cpp в батчи нужного размера (хоть все в один большой .cpp). Это значительно ускоряет сборку (обычно в 2-10 раз), и, в зависимости от железа и размера батча, может по-разному влиять на инкрементальную сборку. Дополнительный плюс — больше потенциальных возможностей компилятору для оптимизации, когда весь код — в одном .cpp. Ещё плюс для дебажных сборок — дебаг символы занимают значительно меньше места. Минусы в том, что может потребоваться исправить одинаковые имена типов и переменных в разных файлах. Примеры использования можете посмотреть в репозитории Organic Maps.

Но в nocc встроен собственный парсер инклудов,

А почему не заиспользовать llvm, который все распарсит и отдаст со всеми раскрученными макросами и все такое, а пришлось написать свой? Ну то есть выглядит, что backend clang как бы не студенческий проект на коленке, вроде...

Так в этом и смысл — чтобы не запускать llvm и т.п. для препроцессора. Ведь это нужно делать локально, для каждого cpp-файла, при вычислении его зависимостей. Препроцессор это дорого. Ну то есть это нормально, но когда мы хотим выжать максимум — то дорого.

Кастомная парсилка появилась не просто так, а уже в самом конце — и тоже разгрузила CPU на локальной машине. Изначально всё по-простому действительно через препроцессор гонялось.

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

Sign up to leave a comment.