Заставьте 2 нестатических поля (которые являются динамическими массивами) использовать память рядом друг с другом
Позволять B1
а также B2
быть классами хранения динамического размера.
(например B1~std::vector<char>
B2~std::vector<float>
)
В C++11, если я кодирую B1
а также B2
"s move
а также copy
функция (правило пяти), класс C
который содержит их как поля, будет автоматически копироваться / перемещаться по умолчанию.
class C{
B1 b1; B2 b2;
};
Это работает очень хорошо.
проблема
Сегодня я получил результат профиля + провёл тест на производительность.
Основная цель: я должен сделать b1
а также b2
того же экземпляра C
выделить память рядом друг с другом:-
b1[0] b1[1] ... b1[b1.size-1] (minimum gap) b2[0] b2[1] ... b2[b2.size-1]
Если я смогу, я получу повышение производительности на 10-20% для всей программы.
Мое плохое решение
Я могу использовать пользовательский распределитель, как это (псевдокод):
class C{
B1 b1;
B2 b2;
Allocator* allo_; // can be heap allocator
public: void reserve(int size){
//old : b1.reserve(size); b2.reserve(size); .... so easy
//new :-
B1 b1Next; B2 b2Next;
int nb1=b1Next.howMuchIWant(size);
int nb2=b2Next.howMuchIWant(size);
//^ request amount of bytes needed if capacity="size"
void* vPtr=allo_->allocate(nb1+nb2);
b1Next.setMemory(vPtr);
b2Next.setMemory(vPtr + nb1); //add "vPtr" by "nb1" bytes
b1Next=b1; //copy assignment (not move memory)
b2Next=b2; //copy assignment (not move memory)
b1=std::move(b1Next); //move memory
b2=std::move(b2Next); //move memory
//clean up previous "vPtr" (not shown)
}
};
Это работает, но код становится намного сложнее отлаживать / поддерживать. Не говоря уже о C
Перемещаем и копируем.
В старой версии все copy
/ move
беспорядок появляются только в B1
а также B2
,
Теперь, беспорядок появляется в каждом классе, который использует структуру данных, как B1
а также B2
непосредственно.
Вопрос
Какая техника C++ / дизайн-паттерн / идиома может помочь?
Чтобы ответить, никакого исполняемого кода не требуется. Псевдокод или просто концепция достаточно.
Я так сожалею, что не предоставил MCVE.
Пользовательский распределитель и управление массивами - вещи, которые действительно трудно минимизировать.
1 ответ
Одна возможность улучшить локальность данных исходит от struct
из vector
с vector
из struct
s. Вместо
struct S
{
std::vector<char> c;
std::vector<int> i;
};
S data;
использовать
struct S
{
char c;
int i;
};
std::vector<S> data;
Таким образом, данные всегда хранятся вместе, и вам не нужно возиться с пользовательскими распределителями. Применимо ли это в вашей ситуации, прежде всего, зависит от двух условий:
- Нужно ли иметь все
char
(или жеint
) смежный? Например, потому что API вызывается регулярно, что требуетvector
соответствующего типа. - Количество сохраненных
char
а такжеint
равно (хотя бы почти равно)?