Чи я передчасно оптимізую?


9

Зараз я перебуваю на стадії проектування архітектури на основі компонентів в C ++.

Мій сучасний дизайн включає використання таких функцій, як:

  • std::vectors з std::shared_ptrs для утримання компонентів
  • std::dynamic_pointer_cast
  • std::unordered_map<std::string,[yada]>

Компоненти представлятимуть дані та логіку різних елементів, які потрібні в ігровому програмному забезпеченні, такому як графіка, фізика, AI, аудіо тощо.

Я всюди читав, що пропуск у кеші важкий для продуктивності, тому я провів кілька тестів, завдяки чому я повірив, що це дійсно може пригальмувати додаток.

Я не зміг перевірити вищезгадані мовні особливості, але в багатьох місцях кажуть, що вони, як правило, коштують великих витрат, і, якщо можливо, їх слід уникати.

Оскільки я перебуваю на стадії проектування архітектури, і вони будуть включені до ядра дизайну, я повинен спробувати знайти способи їх уникнути зараз, оскільки це буде дуже важко змінити пізніше, якщо є продуктивність питань?

Або я просто спійманий у передчасній оптимізації?


3
Я б дуже неохоче погоджувався на дизайн, який дуже важко змінив пізніше, незалежно від проблем із виконанням. Уникайте цього, якщо можете. Існує багато конструкцій, які є гнучкими і швидкими.
candied_orange

1
Навіть не знаючи деталей, відповідь на це питання майже завжди є гучним "ТАК !!".
Мауг каже, що повернемо Моніку

2
@Mawg "... І все-таки ми не повинні пропускати свої можливості в цих критичних 3%". Оскільки це суть дизайну, то як я міг знати, чи працюю я на цих 3%?
Vaillancourt

1
Чудовий момент, Олександре (+1), і так, я знаю, що остання половина цитати, яка майже ніколи не згадується :-) Але, щоб повернутися до мого коментаря до цього (що відображено у прийнятій відповіді) , the answer to this question is almost always a resounding "YES !!". Я все ще вважаю, що краще спершу працювати і оптимізувати пізніше, але YMMV, кожен має свою думку, всі вони справедливі, і тільки ОП може реально відповісти на власне - суб'єктивне - питання.
Мауг каже, що повернемо Моніку

1
@AlexandreVaillancourt Продовжуйте читати статті Knuth (PDF, цитата надходить з правого боку сторінки з позначкою 268, сторінка 8 у читальнику PDF). "... він буде розумним уважно придивитися до критичного коду; але лише після того, як цей код буде визначений. Часто помилкою є апріорні судження про те, які частини програми є дійсно критичними, оскільки універсальний досвід програмісти, які користуються інструментами вимірювання, свідчать про те, що їхні інтуїтивні здогадки не вдається ". (наголос його)
8bittree

Відповіді:


26

Не читаючи нічого, крім назви: Так.

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

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

Fwiw: https://xkcd.com/1691/


3
Домовились. Спочатку змусьте його працювати правильно, бо неважливо, наскільки швидко він не працює. І завжди пам’ятайте, що найефективніші оптимізації не передбачають налаштування коду, вони передбачають пошук іншого, більш ефективного алгоритму.
Тодд Кнарр

10
Я хотів би зазначити, що перший рядок не відповідає дійсності, оскільки оптимізація завжди передчасна, а скоріше тому, що оптимізація не є передчасною, якщо ви знаєте, що вона вам потрібна, і в такому випадку ви б не питали про це. Отже, перший рядок вірний лише тому, що сам факт того, що ви ставите питання про те, чи оптимізація є передчасною, означає, що ви не впевнені, що вам потрібна оптимізація, що, за визначенням, робить її передчасною. Phew.
Йорг W Міттаг

@ JörgWMittag: погодився.
steffen

3

Я не знайомий із C ++, але загалом це залежить.

Вам не потрібно передчасно оптимізувати ізольовані алгоритми, де ви можете легко оптимізувати, коли справа доходить до цього.

Однак для отримання бажаних ключових показників ефективності вам потрібно отримати загальний дизайн програми.

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


3

Якщо вам доведеться запитати, то так. Передчасна оптимізація означає оптимізацію, перш ніж ви впевнені, що існує значна проблема ефективності.


1

ECS? Насправді я припускаю, що це може бути недоношеним, якщо так, щоб багато вдуматись у орієнтовану на дані сторону дизайну та орієнтувати різні повторення, оскільки це може вплинути на ваші дизайни інтерфейсу , а останнє дуже дорого змінити пізно в гра. Крім того, ECS просто вимагає багато роботи та продуманих передумов, і я думаю, що варто використати частину цього часу, щоб переконатися, що це не надасть вам горя продуктивності на рівні дизайну далі за лінією, враховуючи, як це буде в основі вашого весь моторошний двигун. Ця частина відблискує до мене:

unordered_map<string,[yada]>

Навіть при невеликих оптимізаціях рядків у вас є контейнер (рядки) змінного розміру всередині іншого контейнера змінного розміру (unorряд_maps). Насправді, невеликі струнні оптимізації можуть бути на насправді так шкідливо , як корисно в цьому випадку , якщо ваша таблиця дуже рідко, так як невелика оптимізація рядки означатиме , що кожен невикористаний індекс хеш - таблиці все одно буде використовувати більше пам'яті для оптимізації SS ( sizeof(string)буде бути набагато більшим) до точки, коли загальна накладна частина пам'яті вашої хеш-таблиці може коштувати дорожче, ніж все, що ви зберігаєте в ній, особливо якщо це простий компонент, як компонент позиції, крім того, щоб мати більше пропусків кешу з величезним кроком щоб перейти від одного запису в хеш-таблиці до іншого.

Я припускаю, що рядок - це якийсь ключ, як ідентифікатор компонента. Якщо це так, це вже робить речі значно дешевшими:

unordered_map<int,[yada]>

... якщо ви хочете отримати переваги від того, щоб мати зручні для користувача імена, якими можуть користуватися скриптери, наприклад, інтерновані рядки можуть дати вам найкраще з обох світів тут.

Це означає, що якщо ви можете зіставити рядок на досить низький діапазон щільно використовуваних індексів, то ви можете просто зробити це:

vector<[yada]> // the index and key become one and the same

Причина, яку я не вважаю такою передчасною, полягає в тому, що, знову ж таки, це може вплинути на ваш дизайн інтерфейсу. Сенс DOD не в тому, щоб намагатися створити найефективніші представлення даних, які можна уявити за допомогою одного ІМО за один раз (це, як правило, слід досягати ітеративно в міру необхідності), а думати про них достатньо, щоб розробити інтерфейси зверху для роботи з цим дані, які залишають вам достатньо місця для дихання для профілю та оптимізації без каскадних змін дизайну.

Як наївний приклад, програмне забезпечення для обробки відео, яке поєднує весь свій код з цим:

// Abstract pixel that could be concretely represented by
// RGB, BGR, RGBA, BGRA, 1-bit channels, 8-bit channels, 
// 16-bit channels, 32-bit channels, grayscale, monochrome, 
// etc. pixels.
class IPixel
{
public:
    virtual ~IPixel() {}
    ...
};

Не вдасться далеко дійти без потенційно епічного переписування, оскільки ідея абстрагування на рівні одного пікселя вже вкрай неефективна ( vptrсама по собі часто коштуватиме більше пам'яті, ніж весь піксель) порівняно з абстрагуванням на рівні зображення (що буде часто представляють мільйони пікселів). Тому заздалегідь покладіть достатньо продуманих ваших даних на представлення даних, щоб вам не довелося стикатися з таким сценарієм кошмару, і в ідеалі не більше, але тут я думаю, що варто подумати над цим матеріалом заздалегідь, оскільки ви не хочете будувати заплутайте двигун навколо свого ECS і виявіть, що саме ECS є вузьким місцем способами, які вимагають від вас змінити речі на рівні проектування.

Що стосується недоліків кеш-пам'яті ECS, то, на мою думку, розробники часто надто намагаються зробити свій кеш-пам'ять ECS. Він починає видавати занадто мало бабу для долара, щоб спробувати отримати доступ до всіх своїх компонентів ідеально суміжним способом, і часто передбачає копіювання та переміщення даних по всьому місцю. Зазвичай, достатньо добре, скажімо, просто радикси сортувати індекси компонентів до доступу до них, щоб ви отримували доступ до них таким чином, щоб ви хоча б не завантажували область пам'яті в кеш-рядок, а лише виселяли її, а потім завантажували все це знову в одному циклі, просто щоб отримати доступ до іншої частини тієї ж лінії кешу. І ECS не повинен забезпечувати дивовижну ефективність у всьому світі. Це не так, як система введення вигоди від цього стільки, скільки фізика чи система візуалізації, тому я рекомендую орієнтуватися на "добре" ефективність в усьому світі та "відмінна" саме там, де вам це справді потрібно. Що сказано, використанняunordered_mapі stringтут досить просто, щоб уникнути.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.