Как уже указывалось, вектор был в целом смежным до C ++ 11 и теперь гарантирован как таковой с помощью нового метода data
, который фактически возвращает прямой указатель на используемый им внутренний массив.Вот ваша стандартная цитата ISO C ++:
23.2.6 vector шаблона класса [vector]
[...] Элементы вектора хранятся непрерывно, что означает, что если vвектор, где T - это какой-то тип, отличный от bool
, тогда он подчиняется тождеству &v[n] == &v[0] + n
для всех 0 <= n < v.size()
.
Тем не менее, я хотел перейти в основном из-за того, как выВы тестируете и используете "DOD":
Итак, хотя DOD работал быстрее в отладке, чем в ООП, в выпуске это была другая история.
Такого рода предложение нене имеет большого смысла, потому что DOD не является синонимом использования SoAs для всего, особенно если это приводит к снижению производительности.
Дизайн, ориентированный на данные, - это просто обобщенный подход к проектированию, в котором вы рассматриваете, как хранить и эффективнополучить доступ к данным заранее.Это становится одной из первых вещей, которые необходимо учитывать при подходе к проектам с использованием этого мышления.Противоположность начинается, скажем, с проектирования архитектуры, пытающейся выяснить все функциональные возможности, которые она должна предоставлять, вместе с объектами и абстракциями, а также с чистыми интерфейсами и т. Д., И затем оставляя данные в качестве подробностей реализации, которые будут заполнены позже.DOD начинался с данных как фундаментальной вещи, которую нужно учитывать на стадии проектирования, а не как детали реализации, которую нужно заполнить в качестве запоздалой мысли.Это полезно в критических для производительности случаях, когда производительность является фундаментальным требованием уровня проектирования, требуемым заказчиками, а не просто роскошью реализации.
В некоторых случаях эффективное представление структур данных фактически приводит к новым функциям, в некоторой степенипозволяя сами данные для разработки программного обеспеченияGit является примером такого программного обеспечения, где его функции фактически вращаются вокруг структуры данных набора изменений в некоторой степени, где его эффективность фактически приводит к появлению новых функций.В этих случаях функции программного обеспечения и дизайн конечного пользователя фактически развивается из его эффективности, открывая новые двери, потому что эффективность позволяет делать вещи, скажем, в интерактивном режиме, которые ранее считались слишком дорогими в вычислительном отношении, чтобы делать их в любом разумном количестве.время.Другим примером является ZBrush, который изменил мою индустрию VFX, позволив людям сделать вещи, которые люди считали невозможными пару десятилетий назад, например, интерактивно лепить 20 миллионов полигональных сеток с помощью скульптурной кисти для создания моделей, столь детализированных, каких еще никто не видел в конце 90-хи в начале 2000-х годов.Другой способ - это трассировка воксельных конусов, которая позволяет играм, даже написанным на Playstation, иметь непрямое освещение с рассеянным отражением;что-то, что люди все еще думают, что для рендеринга одного кадра без таких ориентированных на данные методов требуется минуты или часы, а не 60+ кадров в секунду.Поэтому иногда эффективный подход DOD на самом деле дает новые функции в программном обеспечении, которые раньше считали невозможными, потому что он преодолевает аналоговый звуковой барьер.
Менталитет DOD все еще может привести к разработке, которая использует представление AoS, еслиэто считается более эффективным.AoS часто превосходил бы в тех случаях, когда вам нужен, например, произвольный доступ, и все или большинство чередующихся полей являются горячими, и к ним часто обращаются и / или изменяют вместе.
Кроме того, это только мое мнение об этом, но, по моему мнению, DOD не должен заранее добиваться наиболее эффективного представления данных.Для этого нужно заранее разработать наиболее эффективные интерфейсы, чтобы оставить достаточную передышку для оптимизации по мере необходимости.Примером программного обеспечения, которому, по-видимому, не хватает предвидения, которое обеспечило бы мышление DOD, могло бы быть программное обеспечение для композитинга видео, которое представляет такие данные:
class IPixel
{
public:
virtual ~IPixel() {}
...
};
Один лишь взгляд на приведенный выше код может показать, что существует значительный недостаток предвидения в том, как спроектировать вещи для эффективного представления и доступа к данным.Для начала, если учесть 32-битный пиксель RGBA, стоимость виртуального указателя с учетом размера и выравнивания 64-битного указателя будет четырехкратным размером одного пикселя (64-битный vptr + 32-пиксельные данные + 32-битные отступы для выравнивания vptr).Поэтому любой, кто применяет мышление DOD, обычно избегает таких конструкций интерфейса, как чума.Тем не менее, они могут получить выгоду от абстракции, например, возможность использовать один и тот же код для изображений с различными форматами пикселей.Но в этом случае я бы ожидал:
class IImage
{
public:
virtual ~IImage() {}
...
};
..., который упрощает накладные расходы vptr, виртуальную диспетчеризацию, возможную потерю смежности и т. Д. До уровня всего изображения (возможно, миллионов)пикселей), а не что-то оплачиваемое за пиксель.
Как правило, образ мышления DOD имеет тенденцию приводить к более грубым, а не гранулированным, интерфейсам (интерфейсам для целых контейнеров, как в случае интерфейса изображения, представляющего контейнерпикселей, а иногда и контейнеров контейнеров).Основная причина в том, что у вас не так много возможностей для централизованной оптимизации, если у вас есть кодовая база, подобная этой:
Потому что теперь, скажем, выхочу многопоточность обработки множества шаров одновременно везде.Вы не можете без переписывания всей кодовой базы, используя шары по отдельности.В качестве другого примера допустим, что вы хотите изменить представление шара с AoS на SoA.Для этого потребуется переписать Ball
, чтобы он стал Balls
вместе со всей кодовой базой, используя прежний дизайн Ball
.Аналогичная вещь, если вы хотите обрабатывать шары на GPU.Поэтому, как правило, мышление DOD предпочитает более грубый дизайн, такой как Balls
:
Во втором случае вы можете применить все оптимизациивам когда-либо нужно обрабатывать шары параллельно, представлять их с помощью SoAs и т. д. - все, что вы хотите, без переписывания кодовой базы.Но, тем не менее, реализация Balls
может по-прежнему в частном порядке хранить каждого отдельного Ball
с использованием AoS:
class Balls
{
public:
...
private:
struct Ball
{
...
};
vector<Ball> balls;
};
... или нет.На данный момент это не так важно, потому что вы можете изменять частную реализацию Balls
, как вам угодно, без влияния на остальную часть кода.
Наконец, для вашего теста, что делаетэто делать?По сути, он проходит по цепочке поплавков одинарной точности и добавляет к ним 5
.В этом случае не имеет значения, сохраняете ли вы один массив чисел с плавающей точкой или тысячу.Если вы храните больше массивов, то это неизбежно приводит к дополнительным издержкам, которые не приносят никакой пользы, если все, что вы собираетесь делать, - это циклически обходить все числа с плавающей запятой и добавлять к ним 5.
Чтобы использовать представление SoA,Вы не можете просто написать код, который делает одно и то же для всех полей.SoAs обычно преуспевают в последовательном доступе к нетривиальным размерам ввода, когда вам действительно нужно сделать что-то другое с каждым полем, например преобразовать каждое поле данных x / y / z, используя матрицу преобразования с эффективными инструкциями SIMD (написанными от руки или сгенерированнымиваш оптимизатор) превращая 4+ шарика одновременно, а не просто добавляя 5
к куче поплавков.Они особенно хороши, когда не все поля горячие, как физическая система, которая не интересуется спрайтовым полем частицы (которое было бы расточительно загружать в строку кэша только для того, чтобы не использовать ее).Таким образом, чтобы проверить различия между представителем SoA и AoS, вам нужен достаточно реальный эталонный тест, чтобы увидеть практические различия.