Size: a a a

2020 August 13

m

magras in pro.cxx
Alexander Zaitsev
есть некий сервис на С++, который состоит из множества частей. Хотелось бы понимать в разные моменты времени, какие части приложения сколько выжрали оперативной памяти. То есть организовать достаточно детализированный профайлинг памяти для приложения.

Сейчас регулярно снимается стастика с аллокатора (jemalloc), но понятное дело, что это говорит только о ситуации для всего приложения.

Есть идеи, как подобное организовать?

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

Почему не используются готовые утилиты профайлинга - они не дают нужной точности.

Если важно - С++14
Для винды я когда-то давно писал свою тулзу, которая инжектилась в любой запущенный процесс, хукала стандартные функции аллокации/деаллокации и пересылала лог операций со стэктрейсами в другой процесс. Оверхед был заметный, интерфейс - ужасный, и у меня не было времени разобраться почему не удавалось выгрузить мою либу из процесса. Но если интересно могу поискать сырцы.
источник

A

Alex in pro.cxx
Alexander Zaitsev
Также есть вариант каждую подсистему заставить саму мочь подсчитать занятую память. Аля дергаешь метод GetMemoryConsumption() у каждой подсистемы, а она уже пошла по всем своим контейнерам это дело считать.

Но выглядит отвратительно, конечно же
А чем вы считаете аллоцированный контейнерами объём памяти? Я уже давно мечтаю написать аллокатор, который считал бы всю память, выделенную каждым конкретным экземпляром контейнера, но для этого аллокатор должен быть stateful, и это нормально не поддерживается даже в С++17, где аллокаторы были доработаны. В общем, я не смог (делал уже два подхода), но очень хочу.
источник

AP

Alexander Potapov in pro.cxx
Не юзать std, а брать другую имплементацию
источник

TS

Timur Safin in pro.cxx
Alexander Zaitsev
есть некий сервис на С++, который состоит из множества частей. Хотелось бы понимать в разные моменты времени, какие части приложения сколько выжрали оперативной памяти. То есть организовать достаточно детализированный профайлинг памяти для приложения.

Сейчас регулярно снимается стастика с аллокатора (jemalloc), но понятное дело, что это говорит только о ситуации для всего приложения.

Есть идеи, как подобное организовать?

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

Почему не используются готовые утилиты профайлинга - они не дают нужной точности.

Если важно - С++14
в Windows DDK, например, драйвера и подсистемы использовали разные теги в аллокациях для таких целей https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exallocatepoolwithtag
источник

AT

Andrew Titov in pro.cxx
Till Schneider
народ, а можно ссылку на стандарт, где сказано, что в шаблоннах можно обращаться к private subclass
https://ideone.com/2V11CF
Кажется, нашёл: https://eel.is/c++draft/class.qual#1.3
источник

ИI

И Ivan in pro.cxx
Alex
А чем вы считаете аллоцированный контейнерами объём памяти? Я уже давно мечтаю написать аллокатор, который считал бы всю память, выделенную каждым конкретным экземпляром контейнера, но для этого аллокатор должен быть stateful, и это нормально не поддерживается даже в С++17, где аллокаторы были доработаны. В общем, я не смог (делал уже два подхода), но очень хочу.
Можно написать аллокатор в 2 части. Одна часть - stateless, которая просто в лог пишет нужную информацию. Вторая часть - просто скрипт, который пройдет, считает лог и подсчитает что нужно.

Потому что какая разница - считать статистику сразу или чуть попозже
источник

A

Alex in pro.cxx
stateless абсолютно бесполезно, потому что информация о том, какой экземпляр контейнера выделил эту память - это тоже state
источник

ИI

И Ivan in pro.cxx
А, ну да, об этом не подумал. Хотя можно например, извлекать указатель на этот контейнер, а сопостовление указатель-имя производить позже
источник

A

Alex in pro.cxx
Вот так, наверное, можно. Но мне интересно другое: везде написано, что в С++17 pmr аллокаторы должны уметь хранить состояние, но по факту я не увидел никаких улучшений по сравнению со старым АПИ. Например, чтобы это работало, даже в простом варианте с указателями, экземпляр аллокатора должен перемещаться при перемещении контейнера и не теряться. А он, насколько я помню, пересоздаётся на каждый чих. Поэтому нет, ни в каком виде сохранить состояние у меня не получилось, оно просто теряется. Указатель на контейнер - такое же состояние, как и всё остальное, если бы я мог хранить его, я бы мог сразу и учёт памяти вести.
источник

ИI

И Ivan in pro.cxx
А разве нельзя его извне получить? Из стектрейса там. По сути, метод объекта - это обычная функция, где первым параметром передается указатель на объект.
источник

m

magras in pro.cxx
Alex
Вот так, наверное, можно. Но мне интересно другое: везде написано, что в С++17 pmr аллокаторы должны уметь хранить состояние, но по факту я не увидел никаких улучшений по сравнению со старым АПИ. Например, чтобы это работало, даже в простом варианте с указателями, экземпляр аллокатора должен перемещаться при перемещении контейнера и не теряться. А он, насколько я помню, пересоздаётся на каждый чих. Поэтому нет, ни в каком виде сохранить состояние у меня не получилось, оно просто теряется. Указатель на контейнер - такое же состояние, как и всё остальное, если бы я мог хранить его, я бы мог сразу и учёт памяти вести.
Естественно он будет пересоздаваться при каждом rebind. Но при этом должен вызываться конструктор "копирования" или "перемещения" (в кавычках так так тип исходного аллокатора может отличаться). А дальше надо смотреть на правила propogation.

Я думаю проблема скорее в том чтобы определить что такое "память выделенная контенером". Если я сделал swap двух векторов что должно произойти со статистикой?
источник

A

Alex in pro.cxx
Ничего не должно произойти. Я просто хочу вести учёт в size_t члене данных аллокатора. При выделении делаю += выделенное количество байт, при освобождении - -=. Насчёт свапа - по-хорошему, контейнер должен свапнуть всё, то есть и инстансы аллокаторов тоже. Но мой код не свапает контейнеры, поэтому можно пережить, если это не будет работать как должно.
источник

AK

Alexey Kuznetsov in pro.cxx
magras
Естественно он будет пересоздаваться при каждом rebind. Но при этом должен вызываться конструктор "копирования" или "перемещения" (в кавычках так так тип исходного аллокатора может отличаться). А дальше надо смотреть на правила propogation.

Я думаю проблема скорее в том чтобы определить что такое "память выделенная контенером". Если я сделал swap двух векторов что должно произойти со статистикой?
Да помимо свопа еще мув оператор тоже очень неясен. Это перемещение/своп значений в контейнере? или перемещение/своп контейнеров? Но обычно трекать конкретный контейнер и не нужно, не очень полезная информация. Часто надо понимать что у меня сервис А жрет 40 мб а сервис Б 80 и этого впринципе достаточно. Вопрос как сагрегировать эту инфу. Если верхние вызовы аллокаций всегда происходят внутри вызовов сервиса, то можно группировать по коллстекам и получить какую то сводку. Если нет, то кроме как руками тегировать память во всех местах где происходит аллокация не вижу способа
источник

A

Alex in pro.cxx
Alexey Kuznetsov
Да помимо свопа еще мув оператор тоже очень неясен. Это перемещение/своп значений в контейнере? или перемещение/своп контейнеров? Но обычно трекать конкретный контейнер и не нужно, не очень полезная информация. Часто надо понимать что у меня сервис А жрет 40 мб а сервис Б 80 и этого впринципе достаточно. Вопрос как сагрегировать эту инфу. Если верхние вызовы аллокаций всегда происходят внутри вызовов сервиса, то можно группировать по коллстекам и получить какую то сводку. Если нет, то кроме как руками тегировать память во всех местах где происходит аллокация не вижу способа
У нас с вами просто разные задачи - вы хотите трекать аллокации отовсюду и вам нужно разобраться в этом хаосе, а у меня конкретные контейнеры, за которыми нужно следить (их 2-3-5 штук).
источник

AZ

Alexander Zaitsev in pro.cxx
Alex
У нас с вами просто разные задачи - вы хотите трекать аллокации отовсюду и вам нужно разобраться в этом хаосе, а у меня конкретные контейнеры, за которыми нужно следить (их 2-3-5 штук).
обьекты контейнеров или классы контейнеров?
источник

A

Alex in pro.cxx
объекты
источник

AK

Alexey Kuznetsov in pro.cxx
vec.capacity()
недостаточно?
источник

A

Alex in pro.cxx
ну-у... Вы же понимаете, что с вектором проблемы нет, можно capacity умножить на sizeof(T). Проблемы с map, multimap, unordered_set и подобными
источник

A

Alex in pro.cxx
у которых непонятно, сколько места отожрали служебные данные в нодах
источник

НИ

Никита Иванов... in pro.cxx
sizeof(std::unordered_map<K, T>::node_type)
источник