Сохраняйте оптимизации локальными, делайте их очевидными, хорошо документируйте их и упростите сравнение оптимизированных версий друг с другом и с неоптимизированной версией как с точки зрения исходного кода, так и с точки зрения производительности во время выполнения.
Полный ответ
Если такая оптимизация действительно так важна для вашего продукта, вам нужно не только знать, почему оптимизации были полезны раньше, но и предоставлять достаточно информации, чтобы помочь разработчикам понять, будут ли они полезны в будущем.
В идеале вам необходимо включить тестирование производительности в процесс сборки, чтобы вы могли узнать, когда новые технологии делают недействительными старые оптимизации.
Помнить:
Первое правило оптимизации программы: не делайте этого.
Второе правило оптимизации программы (только для экспертов!): Пока не делайте этого ».
- Майкл А. Джексон
Для того, чтобы узнать, настало ли сейчас время, требуется бенчмаркинг и тестирование.
Как вы упоминаете, самая большая проблема с высокооптимизированным кодом заключается в том, что его трудно поддерживать, поэтому, насколько это возможно, вы должны держать оптимизированные части отдельно от неоптимизированных частей. Делаете ли вы это через компиляцию во время компиляции, вызовы виртуальных функций во время выполнения или что-то среднее между ними, не должно иметь значения. Важно иметь в виду, что когда вы запускаете свои тесты, вы хотите иметь возможность протестировать все версии, которые вас интересуют.
Я был бы склонен построить систему таким образом, чтобы базовая неоптимизированная версия производственного кода всегда могла использоваться для понимания цели кода, а затем создавать различные оптимизированные модули наряду с этим, содержащим оптимизированную версию или версии, явно документируя где бы то ни было оптимизированная версия отличается от базовой линии. Когда вы запускаете свои тесты (модуль и интеграция), вы запускаете его на неоптимизированной версии и на всех текущих оптимизированных модулях.
пример
Например, допустим, у вас есть функция быстрого преобразования Фурье . Может быть, у вас есть базовая алгоритмическая реализация fft.c
и тесты в fft_tests.c
.
Затем приходит Pentium, и вы решаете реализовать версию fft_mmx.c
с фиксированной запятой, используя инструкции MMX . Позже Пентиум 3 приходит и вы решили добавить версию , которая использует Streaming SIMD Extensions в fft_sse.c
.
Теперь вы хотите добавить CUDA , поэтому вы добавляете fft_cuda.c
, но обнаруживаете, что с набором тестовых данных, который вы использовали годами, версия CUDA медленнее, чем версия SSE! Вы делаете некоторый анализ и в итоге добавляете набор данных, который в 100 раз больше, и вы получаете ускорение, которое вы ожидаете, но теперь вы знаете, что время установки для использования версии CUDA является значительным и что с небольшими наборами данных вы должны использовать Алгоритм без этой стоимости установки.
В каждом из этих случаев вы реализуете один и тот же алгоритм, все должны вести себя одинаково, но будут работать с разной эффективностью и скоростью на разных архитектурах (если они вообще будут работать). Однако с точки зрения кода вы можете сравнить любую пару исходных файлов, чтобы выяснить, почему один и тот же интерфейс реализован по-разному, и, как правило, самый простой способ - вернуться к исходной неоптимизированной версии.
Все то же самое относится к реализации ООП, где базовый класс, который реализует неоптимизированный алгоритм, и производные классы реализуют различные оптимизации.
Важно сохранять одинаковые вещи одинаковыми , чтобы различия были очевидны .