TGViewer
C++95 C++95 @cxx95 · 1.5K subscribers
Post #55 767
#compiler

Как компилятор замеряет скорость компиляции? 🕰

В C++ легко сделать так, чтобы проект собирался очень долго. В моем личном топе - юнит-тест (в виде одного .cpp-файла) компилировался 4.5 минуты.

К счастью, скорость компиляции можно дебажить. Во время компиляции одного файла нужно указать настройку -ftime-trace:
-ftime-trace
Turn on time profiler. Generates JSON file based on output filename. Results can be analyzed with chrome://tracing or Speedscope App for flamegraph visualization.
-ftime-trace-granularity=<arg>
Minimum time granularity (in microseconds) traced by time profiler

Команда может выглядеть так:
clang++ main.cpp -c -ftime-trace -ftime-trace-granularity=50

Получившийся json-файл main.json можно визуализовать на 🔬SpeedScope. (На гитхабе есть гифка, как это примерно выглядит)

Что делает компилятор:
⚙️ Перед началом компиляции, если задана настройка -ftime-trace, clang вызовет метод llvm::timeTraceProfilerInitialize.
⚙️ В этом методе проинициализируется объект структуры llvm::TimeTraceProfiler.
⚙️ Когда начинается какое-то событие, нужно вызвать метод llvm::TimeTraceProfiler::begin, чтобы запомнить время начала.
⚙️ Когда событие заканчивается, нужно вызвать метод llvm::TimeTraceProfiler::end, чтобы добавить запись о событии.
⚙️ Как видно по коду, используется стек, потому что события вложены друг в друга (например внутри события "компиляция файла" есть событие "распарсить класс").
⚙️ После компиляции файла вызывается метод llvm::TimeTraceProfiler::write для записи в json-файл.

По умолчанию параметр -ftime-trace-granularity равен 500 (500 микросекунд). Записываются не все события, а только достаточно "долгие", которые длились дольше чем 500μs - участок кода.

В коде нужные методы не вызывают "вручную" - используется стандартная идиома RAII в виде структуры llvm::TimeTraceScope.
Как видно, в момент вызова конструктора "событие начинается", вызова деструктора "событие заканчивается".
(если компиляция вызывалась без флага -ftime-trace, то этот объект не делает ничего)

Можно привести примеры - вот так засекается время на инстанциацию шаблонов (которая происходит после парсинга файла): PerformPendingInstantiations.
Пока происходит инстанциация шаблонов, засекаются всякие "вложенные" события, например InstantiateFunction.

Вот так компилятор нехитрым образом делает нужный flame graph 🙂
По моему опыту наблюдений за скоростью компиляции, "фронтенд" компилятора (парсинг файла в AST) занимает в 3-20 раз больше времени чем "бэкенд" (перевод AST в LLVM IR, оптимизация и перевод в бинарник).
Основная причина этого дисбаланса - огромный объем исходного файла после того, как раскроются все #include (в почти всех современных проектах на C++).

На основе этих данных становится видно, что нужно поправить, чтобы ускорить компиляцию. А впрочем, это уже совсем другая история...
  • 👍 8
  • ❤ 1
  • 🔥 1
  • 😁 1
More from @cxx95
  1. Sep 21, 2026#offtop Великое Мидревью 💼 В последнее время темы про C++ накапливаются медленно, и то та…
  2. Jun 17, 2026#jostik Обзор жостиков C++ 💼 (номер 5️⃣) В последние несколько месяцев совсем ничего не п…
  3. Jun 17, 2026document post
  4. Jan 7, 2026#compiler #ai На фото из марта 2024 - мерч с работы, это кофта и набор нашивок, которые мо…
  5. Jan 7, 2026document post
  6. Aug 18, 2025#books Текст в окружности - первые слова в опере (услышать) 🎤 📕 Обзор на книгу про памят…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →