Comments 24
Оптимизации на уровне алгоритмов и структур данных (~30%)
Это в идеальном мире, когда хотя бы более-менее разумно сделано. В реальном - может быть и 3000% и более.
Меня всегда удивляло как разработчики умудряются размещать большой объем вычислений на относительно слабом железе, к каким трюкам и решениям прибегают, чтобы приложение работало бысто, это относится не только к игровым движкам
Nintendo Switch - Постоянная внутренняя флеш-память: 32 ГБ (64 ГБ в Nintendo Switch OLED)
Оперативная память - 4 ГБ (LPDDR4)
Это слабое железо?! Вот запихни это всё на БК-0010 с 64КБ памяти из них 32 КБ видеопамять!!! :D Вот что меня удивляло: ВОТ как ТУДА игры запихивали?! Причём не только "Клад", но и 3D игры, когда ты внутри авто и задача не впилиться в дерево! ;)
Там проблема больше в проце, который 1.1Ггц в турбо, но по факту 800-900Мгц в обычном режиме, и все время норовит частоты снизить. Как бы его не нагружали
Ошибаетесь) видеопамяти в БК было 16 кб, где каждый байт кодировал 4 пикселя) последние 16 кб там было ПЗУ с прошивкой и регистрами ввода-вввода)
Недавно попалось видео, где чувак собрал пентиум 3 + жефорс 4400. Запускал старые игры и показывал фпс.
Так вот там как раз наоборот - жуткая угловатая графика, которая к тому же не выдает 30 фпс (гта 3 например).
https://m.youtube.com/watch?v=bMZh0W3xFGY
Как мы в это вообще играли - не представляю. И как вообще такая убогая графика могла так тормозить. И это еще было пред топовое железо.
Так что, как итог, я бы не сказал, что программисты впихивают невпихуемое в слабое железо. Сейчас железо далеко не слабое.
столлы и частые смены контекста выполнения
И как же вы столлы определяли?
Их на самом деле несколько видов, чисто gpu-stall, cpu-gpu, cpu-cpu, memory, let-stall и io-stall. Это ситуация в потоке выполнения когда сpu/gpu ожидает завершения некоторого действия, будь то вычисления или ресурс. Ну как определяли - открывали pix и смотрели глазами, через какое-то время фиксов таких вещей нарабатывается опыт и уже по картинке снапшота выцепляешь проблемные колстеки, дальше разбираешься что мешает.
А что будет, если применить здесь нейронные сети?
Оффтоп конечно, через какое-то время я стал определять код на ревью от своих джунов и мидлов, который они скомуниздили у чатика. Поначалу отнекивались многие, тогда просил рассказать что код делает, увы люди не всегда даже понимают что им там написали ;( т.е. моя НС натренировалась видеть паттерны другой нс, что забавно конечно
зачем вообще на клиенте проверять данные, если они идут с сервака. и зачем в данных, вообще есть строки, которые нужны для экранирования.
как будто проблема вообще в существовании функции.
Зачем вам проверять что ее нужно экранировать? Чтобы потом снова пройтись и сделать это самое экранирование?
Выходит два прохода вместо одного и это изменение вроде не такое масштабное для архитектуры.
Кстати, хотелось бы спросить т.к. не знаю.
Вы сказали что бранч мешает компилятору сделать векторизацию. А потом ручками написали simd. Что значит *векторизация* тогда? Может имеется ввиду то как процессор выполняет инструкции, а не как компилятор их генерит. Надо глянуть асм.
Кстати, интересно как атрибут [[likely]]
повлиял бы на производительность. Если ли вообще смысл его применять. Я слышал что он просто игнорируется на многих архитектурах
Надо всегда думать за рамками текущей задачи, смотреть как она повлияет на общую картину. Если сделать исправления по месту то это усложнит логику работы и замедлит общее время выполнения плюс операции с конфигами это почти всегда копирование памяти, а это дорого, очень дорого для мобилок. Для случая, который описан в баге мы подобрали оптимальный размер блока проверки 256 байт для мобилок и 1к для пк, проверка возвращала место первого вхождения символа для изменения, далее таска уходила в воркер, который занимался уже изменениями во всем конфиге, наложением патча на конфиг уровня и его конвертом в формат движка. К моменту когда заканчивали проверки файлов и загрузку базовых текстур для левела, уже были подготовлены конфиги в формате движка и рендер начинал их грузить. Если все это делать сразу тл получаем лишние секунды работы, когда их можно избежать
Я не автор поста, но делал примерно похожие оптимизации для расчета вэйвформ аудио трэков. Компилятор умеет векторизовывать код автоматически, но делает это весьма консервативно - не всегда, не самые последние инструкции и не всегда самые оптимальные, но тем не менее делает. У меня в коде стоит выбор как обрабатывать данные я использую энум вида Vectorization { Auto, Manual } как раз подчеркнуть тот факт что если вы в коде интрисики руками не пишите то код все равно может содержать симд инструкции.
Вот эта разбивка обработки на 2 части это вообще классика любой симд оптимизации, забавно что иногда умные люди забывают про хвост и там потом УБ вылезает. Вторая классическая оптимизация это ручная развертка цикла, но ее в примере нету. Компиляторы стали хороши в этом плане и ручная развертка работает быстрее чем сделанная компилятором реже чем 10 лет назад. Вероятно ее попробовали сделать она ничего не дала и ее отменили т.к. код получается ещё более трудно читаемым и с ещё одним хвостом, а выхлопа нету.
Совсем похожий код я делал симд поиск строк / оптимизацию в таглибе что бы тэги в мпзшках искать очень очень быстро. Главная сложность ссе довольно сильно отличается от неона и один и тот же алгоритм надо писать 2 раза.
Если понимать, как работает векторизация, то можно "наивный" код довольно легко дотюнить до векторизуемого состояния. Получается короче интринсиков и совместимо с разными системами команд.
https://gcc.godbolt.org/z/jbrqGKxnx
(хвост проигнорирован для простоты)
Наверное, ваш "поиск строк" использует также довольно быструю операцию сравнения. Если так, то может ли он ещё и длину совпадения в байтах от начала сравниваемых областей выдавать? Мне нужно сделать быстрое сравнение областей памяти с выдачей длины в байтах совпадения от их начала. В этом деле нужна помощь.
которые присылали изменения и обновления в бинарном виде (экономия трафика) и для корректной обработки их необходимо было восстановить в текстовый вид, затем нормализовать до json'a, который уже надо было конвертнуть во внутренний формат, чтобы парсер уровня мог их прочитать.
Выглядит как проблема слишком большого количества уровней абстракции.
Насколько эффективнее было бы парсить уровень сразу из бинарных данных, присланных с сервера?
Интереснее вариант, когда изначально всё достаточно оптимально, но разрыв в производительности оригинального и целевого таргетов весьма существенный. Скажем, порт первого Doom под SNES (там ещё у автора не было оригинальных исходников и нормальной документации на чип в картридже, который давал хоть какую то производительность).
Что ж... забавно выяснить, что в научных вычислениях люди пришли примерно к тем же выводам относительно перфоманса и его улучшения что и в геймдеве, ну потому что никому не хочется неделю ждать окончания расчета.
Как засунуть слона в чемодан