Как стать автором
Обновить

Комментарии 21

Расскажете о своем опыте работы с алокаторами?

как нет-то :D

  • в прямом смысле замедляет работу программы в соотношении примерно 1 к 1

  • рост фрагментации памяти не должен превышать 2% в час

может мы обидели кого-то зря (ц)

но фразы "примерно 1 к 1" и "2% в час" - это откровенный бред! и дальше можно уже не читать...

но автора спасает фраза "TC-аллокатор переносит работу с памятью на уровень отдельного потока, предоставляя каждому собственный пул памяти. Помимо избавления от системного new/malloc, он также снижает затраты на синхронизацию", и тут уже можно что-то сказать по Теме.

короче, дальше опять будут ссылки. они позволят вам САМОСТОЯТЕЛЬНО запустить код и убедиться в ВОТ ТАКОМ росте производительности... но если это обидно, то ссылки можно не открывать ;)

итак.

первое. ders::mem_pool - это thread-local allocator, который еще в 2009 году добился 339.5 кратного роста производительности https://ders.by/cpp/mtprog/mtprog.html#3.1.1

второе. ders::off_pool - это использующий СМЕЩЕНИЯ thread-local allocator, позволивший реализовать хеш-таблицу с транзакциями с тридцатикратным ростом производительности! и это прямо сегодня, на современных платформах https://ders.by/cpp/memdb/memdb.html#5.2

ЗЫ уверен, вы понимаете, что мои 339.5 и 30 раз - это не голословные "примерно 1 к 1" и "2% в час" автора ;))

В смысле каждый процент фрагментации примерно на столько же замедляет весь билд. Проверено нв десятке шипнутых игр и сотнях разных конфигов 10% - минус пять фпс в релизе. Извините конкретно Вашей реализации в играх не было, я не могу тут ничего ответить. Возможно мы действительно что-то упустили, тлсф как-то попривычнее будет.

не хватает примеров где полёт буллет на какойто реализации или система частиц отьест 5 фпс

тоесть буллет прилетела и проигрались частички плюс дождик на локации минус 15 фпс, если еще рядом костер поставить ну допустим тоже на частичках

по задачке буллет у меня так получилось,

Скрытый текст
if(flyBullet)//trigger
{   
  // printf("%f\n",Distance);//debug
  vec3 offsetbullet = Normalize(Subv3(Obj2[pickedID].pos,Obj1.pos));
  offsetbullet=Mulv3c(offsetbullet, 1.0f);
  if( Distance(Obj2[pickedID].pos,Obj1.pos)) { //distance for exit fly
        SetPosRotScale(&Obj1);
        flyBullet=false;//exittriggerResumePosition
  }
  else if (Distance(Obj2[pickedID].pos,Obj1.pos)) //distance for fly
        SetPosRotScale(&Obj1);//fly         
}

это без библитеки и коллайдеров

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

тогда поидее проблема с памятью появляется только когда сцена меняется, типо надо прогрузить другую сцену

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

Прочитал, очень интересно. Про часть аллокаторов знал из курса по операционным системам, часть увидел впервые. И ещё очень понравилась привязка к реальным играми и цифрам - понятно, что цифры очень сильно зависят от конкретного применения, но порядок эффекта тоже полезно знать.

А то, например, я когда-то слышал про аллокатор с размерами как числа Фибоначчи, но не задумывался над тем, что он может быть лучше аллокатора с размерами по степеням двойки.

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

Статья безусловно интересная, но с примерами какая-то беда (нейронка генерила?)
Пример:

class StackAllocator {
public:
    StackAllocator(size_t size) {
        ...
        this->size = size;
    }
    ...
      
    void* allocate(size_t size) {
        if (top + size <= (char*)memory + this->size) {
            ...
        }
        return nullptr; // Нет памяти
    }

    void deallocate(void* ptr) {
        assert(ptr == top);
        top = (char*)top - sizeof(ptr); // Освобождение
    }
    ...

private:
    void* memory;
    void* top;
};
  • Член size не объявлен

  • В deallocate внезапно используем sizeof. Наверно всё таки нужна история аллокаций?

  • Указатели зачем-то void*, а потом касты везде насыпаны

    Также не раскрыта тема использования без отстрела ног: когда вызывать деструкторы? Как подружить с контейнерами?

Мдя, недосмострел, спасибо. Надо поправить, примеры из корпвики все, чисто для понимания

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

В далёком 2006 мне надо было портировать очередную жей2эме игру на платформу где использовался с++. Все контора этим занималась - пост продакшн на мобилках тех времён. Не помню точно какая возможно это был Соник. Так вот на большинстве телефонов все работало норм, но была платформа где было медленно. Я залогировал (построил гистограмму) всех аллокаций, ну к моему счастью 95% были блоки на 12 байт. Ничего не зная про все эти типы аллокаторов я просто совместил блочный и фри лист, додуматься до этого не много ума надо. Метаданные (связный список свободных блоков) был размещен в самих блоках одинакового размера. Я сделал список на массиве и по сути указатель на следующий блок это индекс в массиве. Т.е. был большой массив блоков по 12 байт, когда блоки свободны они хранили индекс следующего блока, а когда заняты какие-то данные.

Померял сколько нужно блоков, ну как померял увеличивал размер пула по фибоначи пока не перестало крашится потом увеличил ещё разок на всякий случай и успокоился. Игра стала летать. Т.к. я заранее сделал размер пула точно больше чем нужно блоков, то даже выкинул проверку на нет блоков.

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

все эти аллокаторы нужны либо в играх либо в трэйдинге... Короче в обычной жизни даже стандартного аллокатора хватает

увы, но нет:

  1. thread-local allocator полезен всем многопоточным приложениям. точно так же, как однопоточным не нужен std::shared_ptr с его атомиками.

  2. а в однопоточных числодробилках mem_pool существенно увеличивает скорость и заметно уменьшает расход памяти. например, возьмите https://ders.by/cmpr/cpt/cpt.html и уберите вызов mp_set_memory_functions().

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

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

Я не видел успешных число дробилок которые чё то динамически аллоцируют посреди рассчетов в таких количествах когда нужно думать об аллокаторах

вы что-нибудь слышали о GMP?
https://en.wikipedia.org/wiki/GNU_Multiple_Precision_Arithmetic_Library

GMP для отдельного класса вычислений произвольной точности. И то, подозреваю, в основном для «наколеночного» исполнения.

Если нужно «дробить числа» максимально быстро, переходят к фиксированной точности (пусть и большой) и аллокации не используют, как мне кажется.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории