w23 / xash3d-fwgs

Vulkan Ray Tracing fork of Xash3D FWGS engine. Intended to be merged into master at some point in the future.
160 stars 16 forks source link

profiler: track memory usage (#502) #575

Closed nilsonragee closed 2 months ago

nilsonragee commented 8 months ago

(copied & pasted from Issue #502)

nilsonragee commented 8 months ago

Not gonna lie, it took me a very long time to wrap my head around vk_devmem_t and vk_device_memory_t. I could not understand what the difference between them was until I read this comment:

https://github.com/w23/xash3d-fwgs/blob/258c3ec48e2da7ce1508b44c438c11f07c6882b5/ref/vk/vk_devmem.c#L52

Then I realized what that was for! Although, it cost me many hours...

nilsonragee commented 8 months ago

Here's a quick look of what I have done so far:

1. Console output on startup:

devmem_load

2. Console output on shutdown:

devmem_quit

3. Metrics before loading new level:

devmem_enter_1_hl

devmem_enter_1_console

4. Metrics after loading new level:

devmem_exit_1_hl

devmem_exit_1_console

5. Metrics after re-entering old level:

devmem_return_1_hl

devmem_return_1_console

I really hope I did not mess things up and all counts correctly.

nilsonragee commented 8 months ago

A review would be great 👀

nilsonragee commented 8 months ago

Things done:

Things left to do:

Screenshots:

  1. Now we can see what kind of usage type allocation is made for in debug prints:

devmem2_usage

  1. r_speeds have metrics of each usage type, including overall stats:

devmem2_table_devmem

  1. We can use filters to get only the metrics we want. For example, we can filter only allocation sizes:

devmem2_table_allocated

  1. We can also filter things by usage type. For example, let's get only overall stats:

devmem2_table_all

  1. Now, only buffer stats:

devmem2_table_buffer

  1. And lastly, image stats:

devmem2_table_image

w23 commented 8 months ago

Меня абсолютно ничего не уведомило об этом PR, нашёл его сейчас случайно. Посмотрю в лучшем случае моим вечером сегодня, но пока не могу пообещать.

nilsonragee commented 8 months ago

Меня абсолютно ничего не уведомило об этом PR, нашёл его сейчас случайно.

Ничего страшного, все заняты делом, я все понимаю.

Посмотрю в лучшем случае моим вечером сегодня, но пока не могу пообещать.

Посидев еще подольше и добавив еще коммитов, я считаю, что тут все в порядке, косяков не должно быть. Скорее жду какие-то поправки/предложения. Но, конечно, ничего не исключено)

nilsonragee commented 8 months ago

Things done:

Things left to do:

Screenshots:

  1. All devmem metrics:

align_table_devmem

  1. Newly added alignment holes metrics:

align_table_align

  1. Improved VK_DevMemFree debug print:

align_table_free

w23 commented 8 months ago

(я не проверил ещё, что alignment holes правильно считается)

w23 commented 8 months ago

@nilsoncore пинж

nilsonragee commented 8 months ago

Стрим посмотрел. Был долгое время инактив т.к. были всякие дела.

На некоторые вопросы отвечу отдельно тут, т.к. они более общие:

  1. Q: _total - это пик или максимальное значение? A: Это максимальное значение. По общим максимальным показателям я планировал замерять общий объем проходимых данных в течение игры, сколько по итогу за сессию выделяется / освобождается такой-то памяти и т.д. Метрика, наверно, не такая полезная, потому что хватает один раз пробежаться и увидеть эти числа, т.к. значения от сессии к сессии не меняются и, в любом случае, можно высчитать эти значения самому, добавлял скорее для удобства / теста. Пики в этом плане гораздо лучше и несут полезную информацию. Думаю можно удалить _total и добавить _peak или _max.
  2. Q: Почему код в квейковском стиле с пробелами? Используешь автоформатирование? A: Наверно, просто потому, что оригинал использует такой стиль, Xash (вроде как) тоже придерживается этого стиля, так как это прописано в CONTRIBUTING.md, ну и соответственно я тоже решил. Плюс он мне просто понравился, решил попробовать, и читабельность в некотором плане действительно улучшается, хоть и не всегда. Я понимаю, что большинство vk-шных модулей имеют стандартный стиль с camelCase-ом, и по большей части я стараюсь не трогать то, что было до меня, но в данном случае была изменена / добавлена значительная часть кода, и уже изначальный код выбивался из колеи с новым, поэтому решил ручками подправить остатки. Форматтер не использовал. Если такое не нравится, могу придерживаться уже заданного стиля в файле. Тогда скорее вопрос что с этими разнобойными стилями делать, когда это все в конечном счете пойдет в апстрим.
  3. Q: Почему заменил тобой добавленную функцию get_filename_from_filepath на COM_FileWithoutPath? A: Из цели не плодить лишний код, который уже есть в движке. Да, я слышал на стриме, что COM-овская функция очень неоптимизированная и бегает по строчке 3 раза. Но, мне кажется, это уже тогда надо в апстрим отправить, так как функция движка, а мы, вроде как, стараемся движок не трогать. Ну или заменить у нас и потом разобраться и объяснить, когда это все отправится в апстрим целиком.
  4. Q: Зачем нагородил VkPhysicalDeviceMemoryProperties properties = vk_core.physical_device.memory_properties2.memoryProperties;? A: Просто так проще читать (лично для меня). Очень неудобно читать целую строчку кода обращения к 3+ вложенным полям структур. Какой-то оптимизации я не придерживался, думаю компилятор это все сократит в релизной версии, а на дебаг сборке не сильно скажется, всего несколько мест таких.
  5. Q: Что за функции VK_MemoryPropertyFlags_String и VK_MemoryAllocateFlags_String? Зачем им что-то возвращать? A: Вообще это просто вспомогательные функции, главной идеей которых было упрощение громоздкого чанка кода формата %c%c%c... и подачей туда этих флагов через varargs до выделения небольшого массива символов со стека и подачей этого всего через простой формат %s. Опять же, не столько какая-то оптимизация, сколько повышение читабельности и простоты кода. С точки зрения производительности посимвольный вывод может даже и получше будет, только весь этот код будет копипастой одного и того же, при чем большим куском. Хотелось бы как-то вынести все это в отдельную функцию, а лучше в какой-нибудь файл vk_flags.{h,c}, который бы содержал подобные функции форматирования под используемые флаги, и подключить его к основному заголовку, чтоб везде доступен был, если надо. Про PRI_VKMEMBITS не в курсе, что это такое не видел пока. Функции возвращают количество битов (флагов), которые проставлены (активны) в этих самах флагах. Планировал как задел на будущее, но пока сам применение не нашел. Может быть, перемудрил и это действительно лишнее.
w23 commented 7 months ago

Стрим посмотрел. Был долгое время инактив т.к. были всякие дела.

Я сам в общем пропадаю, трудная неделя (две три месяц жизнь).

2. **Q: Почему код в квейковском стиле с пробелами? Используешь автоформатирование?**
   A: Наверно, просто потому, что оригинал использует такой стиль, Xash (вроде как) тоже придерживается этого стиля, так как это прописано в `CONTRIBUTING.md`, ну и соответственно я тоже решил. Плюс он мне просто понравился, решил попробовать, и читабельность в некотором плане действительно улучшается, хоть и не всегда. Я понимаю, что большинство `vk`-шных модулей имеют стандартный стиль с `camelCase`-ом, и по большей части я стараюсь не трогать то, что было до меня, но в данном случае была изменена / добавлена значительная часть кода, и уже изначальный код выбивался из колеи с новым, поэтому решил ручками подправить остатки. Форматтер не использовал. Если такое не нравится, могу придерживаться уже заданного стиля в файле. Тогда скорее вопрос что с этими разнобойными стилями делать, когда это все в конечном счете пойдет в апстрим.

Тут как бы такое дело :sweat_smile:. Я сам не очень понимаю, в каком стиле хочу держать код. В идеале он должен быть такой же, как и в остальном движке, но я постоянно срываюсь. Получается неконсистентно. План перед мержом его переформатировать в движковый. Возможно, имеет смысл прикрутить clang-format тот же (если он на движковый настраивается) чуть раньше. Не думал пока про это. А пока лучше просто существующее не трогать с целью только форматирования.

5. **Q: Что за функции `VK_MemoryPropertyFlags_String` и `VK_MemoryAllocateFlags_String`? Зачем им что-то возвращать?**
   A: Вообще это просто вспомогательные функции, главной идеей которых было упрощение громоздкого чанка кода формата `%c%c%c...` и подачей туда этих флагов через `varargs` до выделения небольшого массива символов со стека и подачей этого всего через простой формат `%s`. Опять же, не столько какая-то оптимизация, сколько повышение читабельности и простоты кода. С точки зрения производительности посимвольный вывод может даже и получше будет, только весь этот код будет копипастой одного и того же, при чем большим куском. Хотелось бы как-то вынести все это в отдельную функцию, а лучше в какой-нибудь файл `vk_flags.{h,c}`, который бы содержал подобные функции форматирования под используемые флаги, и подключить его к основному заголовку, чтоб везде доступен был, если надо.

Моё мнение, что эти функции и читаются хуже, и используются всего пару раз. И аргумент им передаётся неудобно (надо аллоцировать заранее, не вставишь аргументом напрямую. Я по ним предлагаю либо избавиться, либо переделать сигнатуру на возврат внутреннего статичного буфера.

   Про `PRI_VKMEMBITS` не в курсе, что это такое не видел пока.

Это я придумал в комментарии, по аналогии с PRI64u и друзьями. См., например, https://cplusplus.com/reference/cinttypes/

   Функции возвращают количество битов (флагов), которые проставлены (активны) в этих самах флагах. Планировал как задел на будущее, но пока сам применение не нашел. Может быть, перемудрил и это действительно лишнее.

Их точно можно причесать. И счётчик там флагов не нужен, и ставить символы можно сильно проще через тернарный оператор

w23 commented 7 months ago

@nilsoncore Там ещё несколько комментариев-пожеланием остаются валидны и не адресованы.

w23 commented 7 months ago

@nilsoncore pingity ping :)

w23 commented 7 months ago

@nilsoncore мне эта штуковина может быть скоро нужна. Если у тебя нет времени, не возражаешь, если я сам её допинаю в ближайшие пару недель, основываясь на твоей работе тут?

nilsonragee commented 6 months ago

@w23 и снова здравствуйте, я жив! К сожалению, пришлось выпасть из программирования в реал лайф по разным обстоятельствам, но не суть. В ближайшие дни еще раз пересмотрю что я там накоммитил и сильно ли что-то изменилось за это время.

Помню, думал тогда над тем как реализовать учет RAM памяти, но так и не понял что с этим делать, поэтому хотел спросить у тебя и подискутировать.

@nilsoncore мне эта штуковина может быть скоро нужна. Если у тебя нет времени, не возражаешь, если я сам её допинаю в ближайшие пару недель, основываясь на твоей работе тут?

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

w23 commented 6 months ago

@w23 и снова здравствуйте, я жив! К сожалению, пришлось выпасть из программирования в реал лайф по разным обстоятельствам, но не суть. В ближайшие дни еще раз пересмотрю что я там накоммитил и сильно ли что-то изменилось за это время.

Норм. Спасибо!

Помню, думал тогда над тем как реализовать учет RAM памяти, но так и не понял что с этим делать, поэтому хотел спросить у тебя и подискутировать.

Можно обсудить, да. Если коротко: нужно будет вообще все-все вызовы Mem_Malloc() в нашем рендере превратить во что-то отдельное (макрос или функцию), передающее "контекст" аллокации: модуль, локацию (имя файла+строку+функцию), printf-like пометку к аллокации (например, имя модели). Это можно делать итеративно. Начать с простого -- добавить по аналогии с логами enum для всех известных модулей, и передавать его руками. В недрах трекалки мы просто имеем табличку со счётчиком аллокаций для каждого модуля. Более сложные детали (локации, кастомную инфу) можно будет добавлять потом по мере надобности. С ходу я пока не знаю, на каких структурах данных лучше такую инфу хранить.

Можно трекать утечки.

Дополнительно может иметь смысл заметную часть предаллоцированных статичных буферов заменить на одноразовую аллокацию при инициализации. Почему это полезно:

@nilsoncore мне эта штуковина может быть скоро нужна. Если у тебя нет времени, не возражаешь, если я сам её допинаю в ближайшие пару недель, основываясь на твоей работе тут?

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

Пока потребность чуть сдвинулась в будущее куда-то.

nilsonragee commented 5 months ago

Так, ответил на комментарии ревью, которые еще висят активными. Они все Outdated, т.к. код уже поменялся, плюс я скинул ссылки на код, чтобы можно было эти изменения посмотреть.

Касательно PRI_VKMEMBITS: Охх, зря я туда полез... Долго не мог понять как именно это должно было работать, поэтому как-то решил это оставить и прогресс не шел.

Это я придумал в комментарии, по аналогии с PRI64u и друзьями. См., например, https://cplusplus.com/reference/cinttypes/

Вот эта наводка была очень полезной. По-началу, правда, я не понял смысла, т.к. мы сгенерируем формат, а аргументы потом нужно влепить вручную, так еще и неизвестно сколько этих аргументов нужно. Но потом до меня допёрло, можно так же и аргументы всунуть через макрос. Перед этим я придумал еще один подход, который создает нужную переменную через макрос. В общем, напишу варианты, а там уже можно выбрать на вкус и цвет:

  1. Метод "Создания переменной": объявляем строчную переменную через макрос и напрямую записываем в нее символы (да, создавать переменные через макрос плохая идея).
// Creates a new stack-based string ( char[N] ) type variable to shortly represent value of `VkMemoryPropertyFlags`.
#define VKMEMPROPFLAGS_STRVAR( variable, property_flags ) \
    char variable[6]; \
    variable[0] = ( property_flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT     ) ? 'D' : '-'; \
    variable[1] = ( property_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT     ) ? 'V' : '-'; \
    variable[2] = ( property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT    ) ? 'C' : '-'; \
    variable[3] = ( property_flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT      ) ? '$' : '-'; \
    variable[4] = ( property_flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ) ? 'L' : '-'; \
    variable[5] = '\0';

...

if ( g_devmem.verbose ) { 
    VKMEMALLOCFLAGS_STRVAR( allocate_flags_str, allocate_flags );
    gEngine.Con_Reportf( "  ^3->^7 ^6AllocateDeviceMemory:^7 { size: %llu, memoryTypeBits: 0x%x, allocate_flags: %s => typeIndex: %d }\n",
        mai.allocationSize, req.memoryTypeBits, allocate_flags_str, mai.memoryTypeIndex );
}
  1. Метод "Подсовывания": суем между строчными литералами нужный макрос, который хранит в себе нужный формат, а потом в аргументах тоже суем макрос, который под заданный нами через макрос формат "подсовывает" нужное количество аргументов.
// Format for printf-like functions to represent bits of `VkMemoryPropertyFlags`.
#define PRI_VKMEMPROPFLAGS_FMT "%c%c%c%c%c"

// Inline arguments for `PRI_VKMEMPROPFLAGS_FMT` format macro.
#define PRI_VKMEMPROPFLAGS_ARG( flags ) \
    ( flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT     ) ? 'D' : '-', \
    ( flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT     ) ? 'V' : '-', \
    ( flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT    ) ? 'C' : '-', \
    ( flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT      ) ? '$' : '-', \
    ( flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ) ? 'L' : '-'

...

if ( g_devmem.verbose ) { 
    gEngine.Con_Reportf( "  ^3->^7 ^6AllocateDeviceMemory:^7 { size: %llu, memoryTypeBits: 0x%x, allocate_flags: " PRI_VKMEMALLOCFLAGS_FMT " => typeIndex: %d }\n",
        mai.allocationSize, req.memoryTypeBits, PRI_VKMEMALLOCFLAGS_ARG( allocate_flags ), mai.memoryTypeIndex );
}

Когда до меня наконец допёрло что ты имел в виду, то да, я согласен, 2-ое смотрится и проще, и понятнее.

Вообще, можно наверно и какой-то общий макрос сделать, в который можно передавать нужный тип, и он уже по нему будет выбирать нужный формат... Но не знаю как это можно сделать через одни макросы, мне кажется либо придется городить какую-то огроменную структуру макросов, либо ставить if-ы/switch-и и проверять это все в рантайме.

nilsonragee commented 5 months ago

Касательно ситуации с огромным макросом REGISTER_STATS_METRICS, который было предложено оформить через X-макросы:

Думаю, лучше сразу вставить код сюда, чтобы было видно и не искать лишний раз:

// Register single stats variable.
#define REGISTER_STATS_METRIC( var, metric_name, var_name, metric_type ) \
    R_SpeedsRegisterMetric( &(var), MODULE_NAME, #metric_name, metric_type, /*reset*/ false, #var_name, __FILE__, __LINE__ );

// NOTE(nilsoncore): I know, this is a mess... Sorry.
// It could have been avoided by having short `VK_DevMemUsageTypes` enum names,
// but I have done it this way because I want those enum names to be as descriptive as possible.
// This basically replaces those enum names with ones provided by suffixes, which are just their endings.
//
//                       | var                              | metric_name                            | var_name                                              | metric_type        |
//                       | -------------------------------- | -------------------------------------- | ----------------------------------------------------- | ------------------ |
#define REGISTER_STATS_METRICS( usage_type, usage_suffix ) { \
    vk_devmem_allocation_stats_t *const stats = &g_devmem.stats[usage_type]; \
    REGISTER_STATS_METRIC( stats->current.allocations,       current_allocations##usage_suffix,       g_devmem.stats[usage_suffix].current.allocations,       kSpeedsMetricCount ); \
    REGISTER_STATS_METRIC( stats->current.allocated,         current_allocated##usage_suffix,         g_devmem.stats[usage_suffix].current.allocated,         kSpeedsMetricBytes ); \
    REGISTER_STATS_METRIC( stats->current.align_holes,       current_align_holes##usage_suffix,       g_devmem.stats[usage_suffix].current.align_holes,       kSpeedsMetricCount ); \
    REGISTER_STATS_METRIC( stats->current.align_holes_size,  current_align_holes_size##usage_suffix,  g_devmem.stats[usage_suffix].current.align_holes_size,  kSpeedsMetricBytes ); \
    REGISTER_STATS_METRIC( stats->peak.allocations,          peak_allocations##usage_suffix,          g_devmem.stats[usage_suffix].peak.allocations,          kSpeedsMetricCount ); \
    REGISTER_STATS_METRIC( stats->peak.allocated,            peak_allocated##usage_suffix,            g_devmem.stats[usage_suffix].peak.allocated,            kSpeedsMetricBytes ); \
    REGISTER_STATS_METRIC( stats->peak.align_holes,          peak_align_holes##usage_suffix,          g_devmem.stats[usage_suffix].peak.align_holes,          kSpeedsMetricCount ); \
    REGISTER_STATS_METRIC( stats->peak.align_holes_size,     peak_align_holes_size##usage_suffix,     g_devmem.stats[usage_suffix].peak.align_holes_size,     kSpeedsMetricBytes ); \
    REGISTER_STATS_METRIC( stats->peak.align_hole_size,      peak_align_hole_size##usage_suffix,      g_devmem.stats[usage_suffix].peak.align_hole_size,      kSpeedsMetricBytes ); \
}

qboolean VK_DevMemInit( void ) {
    g_devmem.verbose = !!gEngine.Sys_CheckParm( "-vkdebugmem" );

    // Register standalone metrics.
    R_SPEEDS_METRIC( g_devmem.alloc_slots_count, "allocated_slots", kSpeedsMetricCount );
    R_SPEEDS_METRIC( g_devmem.device_allocated, "device_allocated", kSpeedsMetricBytes );

    // Register stats metrics for each usage type.
    REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_ALL,    _ALL );
    REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_BUFFER, _BUFFER );
    REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_IMAGE,  _IMAGE );

    return true;
}

Тут ситуация немного запутанная. Трюк здесь в том, что имена переменных в коде и в статистике записаны по-разному:

Из-за этого имена переменных и метрик разные, поэтому мы не можем их просто так засунуть в R_SPEEDS_METRIC( ... ). Но это ещё не всё.

2-ой трюк заключается в том, что в коде используются полные названия значений enumVK_DevMemUsageTypes, а в метриках их сокращенные версии - _ALL, _BUFFER, _IMAGE - для того, чтобы не растягивать и без того очень длинные названия переменных в самих метриках. Также стоит упомянуть, что эти сокращенные суффиксы добавляются к окончанию названий метрик.

В итоге, как все это оформить красиво и не громоздко - я не знаю, постарался как мог. Если есть видение того как все это причесать, то лучше написать сразу примером; у меня осознание макросов заканчивается где-то на 1-ой глубине вложенности...

nilsonragee commented 5 months ago

Переходя от проблем прошлого к проблемам будущего: учёт RAM памяти.

Помимо ранее названной функции Mem_Malloc() и ей подобных, которые фактически является макросами обращения к движку:

https://github.com/w23/xash3d-fwgs/blob/80b524d643f795dad26e59828ac4137ed9eff18a/ref/vk/vk_common.h#L13-L19

есть ещё такой товарищ, как alolcator.{h,c}. Кто он такой и зачем он я не знаю, но если посмотреть что там у него, то видно, что он самостоятельный и в движок не ходит:

https://github.com/w23/xash3d-fwgs/blob/80b524d643f795dad26e59828ac4137ed9eff18a/ref/vk/alolcator.c#L2-L6

Дальше немного расследования - и мне свериться, правильно ли я все понял, и знающим память освежить.

Если Mem_Malloc() вызывают практически все, то у alolcator-а не густо. У него есть 3 основные функции аллокации (и мои предположения по принципу использования):

  1. aloPoolAllocate() - выделяет чанк памяти;
  2. aloRingAlloc() - выделяет "кольцо", которое будет с интервалом стираться и перезаписываться;
  3. aloIntPoolAlloc() - выделяет чанк, который, видимо, заточен именно под int-ы.

По частоте использования выходит следующее:

  1. Mem_Malloc() - 46 вызовов в 19 файлах.

xash_MemMalloc_SearchResults

  1. aloPoolAllocate() - 4 вызова в 3 файлах (1 комментарий).

xash_aloPoolAllocate_SearchResults

  1. aloRingAlloc() - 1 вызов в 1 файле.

xash_aloRingAlloc_SearchResults

  1. aloIntPoolAlloc() - 1 вызов в 1 файле.

xash_aloIntPoolAlloc_SearchResults

Возникают вопросы:

  1. Оставить alolcator-у самостоятельность или перенаправлять вызовы в движок, как у Mem_Malloc()?
  2. Как считать вызовы Mem_Malloc() и alolcator-а - вместе или раздельно?

Помимо этого есть вопросы о том, как организовать метрики - какие данные мы хотим видеть? Я себе представляю это так же, как с модулем devmem - делаем название, к примеру, cpumem, или просто ram, и уже к этому "модулю" добавляем метрики. Можно взять уже те, что есть, т.к. и там, и там память:

https://github.com/nilsoncore/xash3d-fwgs/blob/79e0e520611965c4fde0cd7212d1164b7dd2cfce/ref/vk/vk_devmem.c#L23-L40

GitHub код из форка не показывает, поэтому вставлю так:

typedef struct vk_devmem_allocation_stats_s {
    // Metrics updated on every allocation and deallocation.
    struct {
        int allocations;          // Current number of active (not freed) allocations.
        int allocated;            // Current size of allocated memory.
        int align_holes;          // Current number of alignment holes in active (not freed) allocations.
        int align_holes_size;     // Current size of alignment holes in active (not freed) allocations.
    } current;

    // Metrics updated whenever new highest value is registered.
    struct {
        int allocations;          // Highest number of allocations made.
        int allocated;            // Largest size of allocated memory. 
        int align_holes;          // Highest number of alignment holes made.
        int align_holes_size;     // Largest size of alignment holes made. 
        int align_hole_size;      // Largest size of the largest alignment hole made.
    } peak;
} vk_devmem_allocation_stats_t;
nilsonragee commented 5 months ago

@w23 пинж 👀

w23 commented 5 months ago

@w23 пинж 👀

я немного тут придавлен, отвечу развёрнуто вряд ли сегодня.

неразвёрнуто:

1. Оставить `alolcator`-у самостоятельность или перенаправлять вызовы в движок, как у `Mem_Malloc()`?

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

2. Как считать вызовы `Mem_Malloc()` и `alolcator`-а - вместе или раздельно?

Раздельно. Alolcator-выделения должны трекаться очень контекстно-специфично, и не внутри самого алолкатора.

Помимо этого есть вопросы о том, как организовать метрики - какие данные мы хотим видеть? Я себе представляю это так же, как с модулем devmem - делаем название, к примеру, cpumem, или просто ram, и уже к этому "модулю" добавляем метрики.

Вот про это мне бы репу почесать часок-другой. На выхах очень постараюсь.

nilsonragee commented 5 months ago

@w23 пинж. (на всякий)

Кратко о том, что сделал:

  1. Добавил mapped в вывод.
  2. Вернул !!, где оно было.
  3. Флаги теперь выводятся через PRI_xxxFLAGS_FMT и PRI_xxxFLAGS_ARG( ... ).
  4. alignment_hole теперь напрямую берется из alo_block_t, который возвращается при аллокации.
  5. В сообщении об ошибке, когда слотов для аллокаций не остается, теперь пишется сколько их вообще было.
  6. В сообщениях об аллокации/освобождении памяти теперь пишется более читаемый размер - N bytes, N Kb, N Mb и т.д. Не отформатированное "сырое" значение так же выводится в под-сообщении "-> Allocated: ...", чтобы видеть конкретное значение.
  7. Добавлена метрика пикового значения размера единой аллокации памяти.

Несмотря на то, что alignment_hole теперь берется напрямую из блока alolcator-а, статистика от этого особо не поменялась. Либо вышло так, что мне повезло, либо это фундаментально то же самое. На c1a0d как было 332 дырки на 166 Кб, так и осталось. Надеюсь это не я накосячил опять. Снизу скрин после изменений:

image

nilsonragee commented 5 months ago

И еще вопрос: это же не страшно, что моя ветка форка давно не обновлялась?

image

Обновить я не могу, т.к. он просит отменить все мои коммиты, a.k.a. слить все мои труды:

image

Плюс сейчас висит конфликт с файлом vk_devmem.c, в который недавно были внесены изменения уже после моего форка. Мне вручную коммитами добавить это к себе или просто нужно будет тут выбрать, или что? Я в таком не шарю, опыта не было.

0x4E69676874466F78 commented 5 months ago

Плюс сейчас висит конфликт с файлом vk_devmem.c, в который недавно были внесены изменения уже после моего форка. Мне вручную коммитами добавить это к себе или просто нужно будет тут выбрать, или что? Я в таком не шарю, опыта не было.

Это уже через консоль надо. По идее нужно влить себе изменения из апстрима и смержить/ребейзнуть убрав вручную кофнликт. https://stackoverflow.com/a/7244456

w23 commented 5 months ago

Тут прямо чуть-чуть осталось:

  1. Смержиться со свежим вулканом.
  2. Спрятать функцию, которая снаружи не пользуется никем.
nilsonragee commented 2 months ago

@w23 Пинж.

В текущем состоянии PR готов к мержу, но без последнего пунктика про CPU/RAM память. Думаю, если что отдельно можно добавить другим PR, а то этот уже как-то растянулся...