Сверка документации с кодом: исправлены расхождения
Сплошная проверка документов против дерева. Код не менялся. docs/rust_vs_cpp.md — числа, снятые с чужого каталога сборки: - «775 МБ исходников зависимостей» и «10 пакетов в графе C++» получены на build/, сконфигурированном из другого дерева (его _deps содержит 262 МБ nlohmann_json, который проект не объявляет). На деле девять объявленных репозиториев дают ~400 МБ исходников; - пакетов в графе Rust 82, а не 76 (cargo tree по текущему Cargo.lock); - итог по строкам 2976/494, а не 2962/492: строка «меш» устарела на 17 строк игнорируемого диагностического теста, тесты в модулях — 176; - «перевес почти весь в Vulkan-слое» — на деле 346 из 542 (64 %), из них 305 на Context и Swapchain; остальное приходится на меш, редактор и приложение; - «ни один замер не даёт разницы в порядок величины» неверно: инкрементальная release — 52.3 против 4.4 с, это 11.9x; - граней с пятью и более вершинами в plane.obj 119, а не 121; - из Catch2 перенесены все три случая, и добавлено ещё два, а не «три перенесены дословно»; - деструктор Renderer::Impl — 22 строки, а не тридцать; - путевых зависимостей у порта две: assets/meshes с откатом на текущий каталог и pipeline_cache.bin рядом с бинарём; - граф целей CMake ацикличен, цикл существует на уровне исходников — именно поэтому CMake и молчит. rust/README.md: - объявленный rust-version = "1.82" недостижим: залоченные egui, egui-winit и epaint 0.36.1 требуют 1.95; - перечни зависимостей крейтов были неполны, приведены целиком; - build.rs читает ../../../shaders, а не ../../shaders; - тесты не «чистая математика»: тесты загрузчика читают файлы из assets/meshes и требуют клон репозитория; - assets/ порту никто не копирует, он находит корневую копию сам; - те же поправки про цикл в CMake и про момент ожидания простоя. README.md: - панель называется Mesh, а не «Mesh load»; - пресета clang-cl не существует, компилятор пресеты не фиксируют; - версии Vulkan SDK и компиляторов сборкой не проверяются; - Buffer и Image перечислены среди рабочих модулей vk/, хотя ими не пользуется никто. docs/theory/solver_2x_sdf/README.md: - предлагался несуществующий переключатель cfg.collision="bgk" и реестр операторов get; тот же файл двумя разделами ниже говорит, что оператор зафиксирован. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+48
-31
@@ -80,15 +80,21 @@
|
||||
| `SimVulcan.exe`, debug | 5.68 МБ | 28.97 МБ |
|
||||
| каталог сборки | 78 МБ | 469 МБ |
|
||||
| объявлено зависимостей | 9 | 15 |
|
||||
| всего пакетов в графе | 10 | **76** |
|
||||
| исходники зависимостей на диске | **775 МБ** на каждый каталог сборки | **80 МБ** в общем реестре |
|
||||
| всего пакетов в графе | 9 | **82** |
|
||||
| исходники зависимостей на диске | **~400 МБ** на каждый каталог сборки | **80 МБ** в общем реестре |
|
||||
|
||||
Пятикратная разница в размере бинаря — это в основном статически влинкованная стандартная
|
||||
библиотека Rust и форматирование `core::fmt`; C++-версия тянет CRT из системы. Разница в
|
||||
числе пакетов (76 против 10) впечатляет ровно до того момента, как посмотреть на объём:
|
||||
76 крейтов Rust занимают в восемь раз меньше места, чем девять библиотек C++, потому что
|
||||
числе пакетов (82 против 9) впечатляет ровно до того момента, как посмотреть на объём:
|
||||
82 крейта Rust занимают в пять раз меньше места, чем девять библиотек C++, потому что
|
||||
`.crate` — это архив выпуска, а `FetchContent` — клон с историей.
|
||||
|
||||
> **Поправка.** В первой редакции здесь стояли «775 МБ» и «10 пакетов». Обе цифры сняты
|
||||
> с каталога `build/`, сконфигурированного из другого дерева исходников: его `_deps/`
|
||||
> содержит 262 МБ `nlohmann_json`, которого этот проект не объявляет. Девять объявленных
|
||||
> репозиториев дают около 400 МБ исходников и около 510 МБ всего `_deps` после сборки.
|
||||
> Число пакетов Rust получено `cargo tree -e normal` по текущему `Cargo.lock`.
|
||||
|
||||
### Выполнение
|
||||
|
||||
Обе версии показывают в режиме FIFO на экране 60 Гц, поэтому частота кадров у них
|
||||
@@ -122,14 +128,16 @@ C++: egui пересобирает раскладку каждый кадр, ImG
|
||||
* **35 вершин.** tinyobjloader отдаёт глобальный массив `attrib.vertices` целиком, включая
|
||||
вершины, на которые не ссылается ни одна грань; tobj такие отбрасывает. Сварка потом
|
||||
всё равно оставила бы их висеть в списке — на картинку они не влияют.
|
||||
* **26 треугольников.** В `plane.obj` 121 грань с пятью и более вершинами. tobj режет
|
||||
* **26 треугольников.** В `plane.obj` 119 граней с пятью и более вершинами. tobj режет
|
||||
n-угольник веером, что даёт ровно `n − 2` треугольника — суммарно 20061, и это
|
||||
совпадает с прямым подсчётом по файлу. tinyobjloader для `n ≥ 5` применяет
|
||||
earcut-подобную триангуляцию и выбрасывает выродившиеся треугольники, отсюда 20035.
|
||||
Разница 0.13% и целиком лежит в библиотеке чтения, а не в переносе.
|
||||
|
||||
Сварка вершин (`weld_vertices`) перенесена построчно, включая бакетирование округлением
|
||||
и FNV-хеш; три её теста из Catch2 перенесены дословно и проходят.
|
||||
и FNV-хеш. Все три случая Catch2 перенесены дословно и проходят; сверх них в порт
|
||||
добавлены ещё два — бакетирование округлением, а не отбрасыванием, и габариты пустого
|
||||
меша.
|
||||
|
||||
### Побочная находка: строка, которой не бывает
|
||||
|
||||
@@ -155,22 +163,25 @@ C++: egui пересобирает раскладку каждый кадр, ImG
|
||||
| | всего | пусто | комм. | **кода** | всего | пусто | комм. | **кода** |
|
||||
| журнал, окно (`core`) | 370 | 83 | 11 | **276** | 310 | 36 | 62 | **212** |
|
||||
| Vulkan (`vk`) | 2120 | 380 | 88 | **1652** | 2491 | 238 | 255 | **1998** |
|
||||
| меш (`mesh`) | 236 | 50 | 14 | **172** | 395 | 50 | 70 | **275** |
|
||||
| меш (`mesh`) | 236 | 50 | 14 | **172** | 412 | 51 | 72 | **289** |
|
||||
| редактор (`editor`) | 305 | 68 | 20 | **217** | 431 | 48 | 62 | **321** |
|
||||
| приложение (`app`) | 85 | 14 | 5 | **66** | 226 | 27 | 43 | **156** |
|
||||
| тесты | 65 | 9 | 5 | **51** | *внутри модулей* | | | *≈150* |
|
||||
| **итого** | **3181** | 604 | 143 | **2434** | **3853** | 399 | 492 | **2962** |
|
||||
| тесты | 65 | 9 | 5 | **51** | *внутри модулей* | | | *176* |
|
||||
| **итого** | **3181** | 604 | 143 | **2434** | **3870** | 400 | 494 | **2976** |
|
||||
| система сборки | 431 | | | **399** | 232 | | | **197** |
|
||||
|
||||
Порт длиннее примерно на пятую часть, и перевес почти весь в Vulkan-слое: +346 строк кода
|
||||
в `simv-vk` — это написанная руками замена vk-bootstrap. Приложение выросло с 66 до 156
|
||||
строк, потому что в него переехал `App` из `simv_core` (см. расхождение 1) и поиск
|
||||
каталога моделей стал честным обходом предков вместо пяти захардкоженных `../`.
|
||||
Порт длиннее примерно на пятую часть, и большая часть перевеса — в Vulkan-слое: +346
|
||||
строк кода в `simv-vk` — это написанная руками замена vk-bootstrap. Но «почти весь» было
|
||||
бы преувеличением: из 542 строк общего перевеса на Vulkan-слой приходится 346 (64 %), а
|
||||
внутри него на `Context` + `Swapchain` — 305 (56 % от общего). Остальное настоящее: меш
|
||||
+117, редактор +104, приложение +90, `core` −64. Приложение выросло с 66 до 156 строк,
|
||||
потому что в него переехал `App` из `simv_core` (см. расхождение 1) и поиск каталога
|
||||
моделей стал честным обходом предков вместо пяти захардкоженных `../`.
|
||||
|
||||
Комментариев в порте втрое больше (492 против 143), и это перекос замера, а не свойство
|
||||
Комментариев в порте втрое больше (494 против 143), и это перекос замера, а не свойство
|
||||
языка: значительная их часть — пометки «здесь расхождение с C++-версией и вот почему»,
|
||||
написанные ради этого документа. По строкам собственно кода разрыв — 2962 против 2434,
|
||||
и он меньше, если вычесть тесты: они в Rust живут внутри модулей (≈150 строк), в C++ —
|
||||
написанные ради этого документа. По строкам собственно кода разрыв — 2976 против 2434,
|
||||
и он меньше, если вычесть тесты: они в Rust живут внутри модулей (176 строк), в C++ —
|
||||
отдельной целью (51 строка).
|
||||
|
||||
## Структурные расхождения
|
||||
@@ -179,10 +190,11 @@ C++: egui пересобирает раскладку каждый кадр, ImG
|
||||
|
||||
### 1. `App` переехал в исполняемый крейт
|
||||
|
||||
В C++ граф целей цикличен: `core::App` владеет `vk::Renderer`, а `vk::Renderer`
|
||||
принимает `core::Window&`. Работает это только потому, что `simv_vk` **не линкует**
|
||||
`simv_core`, а видит его заголовки через `target_include_directories(simv_vk PUBLIC ..)`,
|
||||
и всё сходится на компоновке исполняемого файла. Cargo цикл между крейтами отвергает
|
||||
В C++ цикличны исходники: `core::App` владеет `vk::Renderer`, а `vk::Renderer`
|
||||
принимает `core::Window&`. Граф целей CMake при этом ацикличен — потому CMake ни на что
|
||||
и не жалуется: `simv_vk` **не линкует** `simv_core`, а видит его заголовки через
|
||||
`target_include_directories(simv_vk PUBLIC ..)`, и всё сходится на компоновке
|
||||
исполняемого файла. Cargo цикл между крейтами отвергает
|
||||
сразу, поэтому `App` (25 строк) поднят на уровень выше обоих — в `simv-app`.
|
||||
|
||||
Это единственный пункт, где Rust потребовал перекладывать код, и заодно единственный,
|
||||
@@ -270,8 +282,9 @@ renderer.draw_frame(window, |ctx| {
|
||||
`include_bytes!`. Вместе с этим исчезли: функция `FindSpvPath` с перебором путей, два
|
||||
POST_BUILD-шага копирования каталогов в `CMakeLists.txt`, требование запускать редактор
|
||||
из его собственного каталога и целый класс ошибок «шейдер не найден» во время выполнения
|
||||
— отсутствующий шейдер теперь ломает сборку. Из путевых зависимостей остался только
|
||||
`assets/meshes`, и он ищется от бинаря, а не от текущего каталога.
|
||||
— отсутствующий шейдер теперь ломает сборку. Путевых зависимостей осталось две:
|
||||
`assets/meshes`, который ищется подъёмом по предкам бинаря и лишь затем — по предкам
|
||||
текущего каталога, и `pipeline_cache.bin`, который пишется рядом с бинарём.
|
||||
|
||||
### 9. Цикл событий принадлежит библиотеке
|
||||
|
||||
@@ -333,8 +346,8 @@ let (f13, f12, f10) = {
|
||||
};
|
||||
```
|
||||
|
||||
**Rust помог — порядок уничтожения.** В C++ `Renderer::Impl::~Impl` — это тридцать строк
|
||||
ручного разрушения в правильном порядке, и любая перестановка полей в объявлении структуры
|
||||
**Rust помог — порядок уничтожения.** В C++ `Renderer::Impl::~Impl` — это двадцать две
|
||||
строки ручного разрушения в правильном порядке, и любая перестановка полей в объявлении структуры
|
||||
её не сломает, но и не поможет: связи нет. В Rust порядок полей **и есть** порядок
|
||||
уничтожения, а `Drop` у каждой обёртки снимает вопрос «а это уже освободили?». Ловушка
|
||||
осталась одна и она подписана в коде: `ash::Device` клонируется как таблица функций, а не
|
||||
@@ -356,14 +369,18 @@ C++ тоже опасен, не притворяясь, что их нет.
|
||||
|
||||
## Итог
|
||||
|
||||
Ни один из замеров не даёт разницы в порядок величины, так что решение к таблице не
|
||||
сводится. Что можно утверждать по итогам порта:
|
||||
Кроме одной клетки, ни один замер не даёт разницы в порядок величины, так что решение к
|
||||
таблице не сводится. Исключение — инкрементальная сборка release: 52.3 с против 4.4 с,
|
||||
это 11.9×, и объясняется оно thin LTO, а не языком (разбор ниже). Следующие по величине
|
||||
разрывы уже укладываются в порядок: исходники зависимостей ~5×, размер бинаря 4.9×.
|
||||
Что можно утверждать по итогам порта:
|
||||
|
||||
**Порт занял примерно на пятую часть больше строк**, и почти весь перевес пришёлся на
|
||||
`simv-vk`. Причина одна и она названа выше: замены vk-bootstrap нет, и 301 строка
|
||||
`Context` с `Swapchain` превратилась в 606. Остальной Vulkan-слой — запись кадра, барьеры,
|
||||
сборка конвейеров — совпадает почти строка в строку. Если проект растёт дальше именно в
|
||||
Vulkan-часть, перевес разовый: инициализация пишется один раз.
|
||||
**Порт занял примерно на пятую часть больше строк**, и бо́льшая часть перевеса пришлась на
|
||||
`simv-vk`. Главная причина названа выше: замены vk-bootstrap нет, и 301 строка
|
||||
`Context` с `Swapchain` превратилась в 606 — это 305 строк из 542 общего перевеса, то есть
|
||||
чуть больше половины, а весь Vulkan-слой даёт 346 (64 %). Остальной Vulkan-слой — запись
|
||||
кадра, барьеры, сборка конвейеров — совпадает почти строка в строку. Если проект растёт
|
||||
дальше именно в Vulkan-часть, эта доля перевеса разовая: инициализация пишется один раз.
|
||||
|
||||
**Сборка: паритет везде, кроме одной клетки.** Полная сборка release у C++ вдвое быстрее
|
||||
(114 с против 194 с), полная debug — наоборот, медленнее (112 с против 83 с),
|
||||
|
||||
Reference in New Issue
Block a user