Как сделать профилирование и пул памяти для системы?

8

Я был заинтересован в профилировании и хранении пула управляемой памяти для каждой подсистемы, поэтому я мог получить статистику о том, сколько памяти использовалось для чего-то, например, звуков или графики. Тем не менее, что будет дизайн, который работает для этого? Я думал о том, чтобы использовать несколько распределителей и просто использовать один для каждой подсистемы, однако это привело бы к глобальным переменным для моих распределителей (или мне так кажется). Другой подход, который я видел / был предложен, состоит в том, чтобы просто перегрузить new и передать распределитель для параметра.

У меня был похожий вопрос по поводу переполнения стека здесь с наградой, однако, кажется, что, возможно, я был слишком расплывчатым или просто не хватает людей со знаниями в этой теме.

chadb
источник
Убрал мой ответ. Я вернулся и прочитал статьи, и пулы, используемые для отслеживания распределения по системе, не являются частью этих статей (хотя они и были основаны на нем). Если я смогу найти эти конкретные снова, я свяжу их вместо этого! Сожалею!
Джеймс
1
Посмотрите на это сообщение в блоге Иисуса де Сантос Гарсия. В нем он обсуждает отслеживание памяти по подсистеме и использование нескольких распределителей для различных требований к памяти.
7
Не зацикливайтесь на теоретических парадигмах. Если вам нужны функциональность и данные в глобальном масштабе, то в глобальных нет ничего плохого. Уже есть куча глобальных функций, таких как new / delete / malloc / free. Просто добавьте, что вам нужно, чтобы сделать работу.
Майк Земдер

Ответы:

1

Это определенно вопрос, который может показаться неопределенным для некоторых;)

Но я думаю, что знаю, откуда ты.

У вас есть миллион вариантов того, как вы можете реализовать это. Некоторые из этих вариантов должны вращаться вокруг целевых платформ и общих целей проектирования. Эти соображения разорвут любые связи, пока вы не почувствуете себя достаточно комфортно с различными затратами на реализацию, достаточными для того, чтобы в первую очередь вырастить дизайн из платформы и общие проблемы проектирования. Так что до тех пор, вот несколько способов, которые не будут стоить вам с точки зрения сложности (бремя управления) или в связи с удалением или изменениями, если вы передумаете ...

Если цель состоит в том, чтобы измерить и распределить, с возможностью использования пулов, то вам нужно сначала подумать о минимальном наборе пригодного для жизни кода, чтобы начать. Для объяснения, если вы неравнодушны к классам, вы можете создать один класс, let, обозначающий кучу, или вместо этого использовать набор функций, которые принимают дескриптор или имя кучи. Это действительно проблема семантики, если честно. Следующее решение новое или malloc; Я неравнодушен к malloc, потому что много раз я имел дело с низкоуровневыми конструкциями и в большинстве реализаций я знаю, что новые вызовы malloc, и мне не нужно беспокоиться о сложности перегрузки новых и беспокоиться об этом на всех платформах , Однако я много раз создавал системы или компоненты для перегрузки или подключения новых. И, конечно же, основная проблема или разница заключается в том, что «новое» Вы должны знать тип перед распределением, где значение 'malloc' не имеет значения, а с помощью malloc вы разрешаете тип после выделения. Все эти детали должны дать вам идею и некоторый контекст для принятия дизайнерских решений в этих типах вопросов :)

Так что я собираюсь выбрать class и malloc, потому что здесь легче объяснить, но в конце концов это не имеет значения. Внутренние элементы будут иметь незначительную материальную разницу по сравнению с остальной частью общей конструкции.

Таким образом, в этом предположении я знаю, что (или собираюсь предположить, что) я могу в конечном итоге получить 7-8 реальных экземпляров класса подсистемы и ожидать сотен тысяч вызовов для распределения и бесплатно. Поскольку большая часть моего любопытства и реальной тяги во всем этом, на самом деле, связана с размерами и профилем, я не хочу обременять производительность приложения мудрым. Для начала я мог бы решить оставить все это открытым и общедоступным, пока я его не прибью, пока я буду реализовывать его в остальной части приложения; структура сделает это хорошо. 'S_' показывает, какие переменные явно предназначены для статистики.

struct Mem
{
  int s_allocs;
  int s_frees;
  int s_peak;
  int s_current;
  void* heap; // if you wanted to go into having real actual separate heaps, else ignore
  void* alloc(int size);
  void free(void* p);

  Mem() {memset(this,0,szieof(Mem));}  // want this to be inlined with the call site constructor (a design decision example)
}

class MySubSystem
{
   Mem mem;
   ....  you get the idea
}

Это крайнелегкий по многим направлениям, и, возможно, хорошее место, чтобы начать воплощать в жизнь, где вы действительно хотели бы пойти с этим. И у вас сразу возникает проблема, откуда вы знаете размер освобожденного предмета. (Это было бы проблемой для решения практически любого подхода.) Так как это игровой форум, вы можете подумать о добавлении первых нескольких байтов с размером, иначе вам придется либо обернуть, либо запомнить другим способом. Чувствительность большинства разработчиков игр не должна быть слишком сильной против допинга, и это самый простой пример, учитывая, что я уже сделал стену текста. В основном это выглядит так: вы не хотите, если вы можете помочь разрушить внутреннее выравнивание, вы хотите знать, так как почти бесплатно, если размер согласован. Так что что-то простое, как "s_allocs ++; s_total + = size; uint64 * p = (uint64 *) malloc / calloc (size + = 8); * p = 0xDEADDAED00000000 | размер; return p + 1; "где выделения будут меньше 4 ГБ, а uint64 - это то, что компилятор считает 64-битным целым без знака, и где вы можете проверить значение sanity бесплатно.

Это все один из способов получить минимальный минимум при минимальных затратах, соответствующих требованиям. Это неКлассы распределения адресов, которые имеют виртуальные функции, если они находятся в области действия для профилирования или управления, так как вы не можете предвидеть размер используемой среды c ++ для тех, кто не перегружает или перехватывает новые, или если вы полагаетесь на конструктор в одном из странные способы, которые не могут быть обработаны какой-либо другой функцией 'init'. В противном случае класс является классом произвольного размещения и все равно, когда вы бросаете. Если вы неравнодушны к новому и нуждаетесь в присущей виртуальной таблице или семантике конструктора, то вы должны зацепить новое, но это целое «другое животное», которое вам нужно по-настоящему изучить, чтобы убедиться, что вы делаете то, что связано с новыми потребностями и должно было бы сигнализировать ваш код обрабатывает новый, к которому это относится. Но в остальном вышеприведенная концепция одинакова.

Что еще более важно это должно привести ваш мозг в действие, и, надеюсь, в соответствии с тем, что вам нужно и каковы ваши допуски, теперь, когда вы увидели за кулисами немного больше. Там нет мастера :)

Celess
источник
Если вы использовали шаблонные функции для выделения и освобождения, это не должно быть проблемой для определения размера, который должен быть освобожден (и выделен).
API-Beast
1
Цель состояла в том, чтобы показать основную проблему, чтобы помочь обеспечить основу для выбора какой-либо абстракции, а не для представления конкретной абстракции. У всего есть свои компромиссы. Знание размера необходимо не для освобождения, а для статистики.
Celess
1

Вам не нужно ничего реализовывать в вашей игре для этих данных. Такие инструменты, как Massif Valgrind, могут извлечь все необходимые данные из символов отладки. Вы можете просмотреть дампы массива в Massif Visualizer .

API-Beast
источник
4
Я предполагаю, что большинство графических игр не будут разрабатываться в системе, которая работает под управлением Valgrind, к сожалению.
Kylotan
1

Я настоятельно рекомендую не писать свой собственный распределитель памяти. Вам нужен стабильный, надежный и проверенный, с хорошими функциями отладки, такими как обнаружение повреждений, и, самое главное, с надежной статистикой. Это непростая задача и имеет много подводных камней. Есть отличные и простые в использовании, например:

Doug Lea Allocator

Он поставляется с концепцией пространств памяти, вы можете использовать один для каждой подсистемы. Он высоко оптимизирован и дает вам отличную статистику и информацию о времени выполнения.

Майк Земдер
источник