Лидеры
Популярный контент
Показан контент с высокой репутацией 05.09.2022 в Комментарии блога
-
2 баллаДля теста видеобуферов набросал максимально упрощенный рендерер для майноськи. Без поддержки изображений, прозрачности и транзиций - оставил лишь суровые прямоугольники и цветной текст: Плюсы: расход RAM упал до 25% на полностью инициализированную систему с загруженными (но не отрисованными) иконками. Для слабых машин это очень хороший показатель, и освободившиеся ресурсы можно было бы направить на прикладной многозадачный софт. Минусы: оно лагает сильнее, чем софтверное решение с графоном!11 Но, будем честны, я натягиваю сову на глобус. Концептуально фича крайне сочная, API удобное и не ломает старые проекты, написанные под прямую работу с GPU. Думаю, она будет идеальным решением для узкозадачных юишных софтин типа мониторилок реакторов, кнопочных контроллеров для умного дома, текстовых чатов или рисовалок - иными словами, для всего, что могло слегка подлагивать из-за прямой отрисовки. И если раньше надо было извращаться с порядком операций, экономя каждый тик, то теперь можно кодить гораздо комфортнее. Хотя мне все равно чуточку обидно. Но лишь чуточку.
-
1 баллВ том и дело, что они оверхед этот не имитируют. Там нет никаких преобразований, упаковок и распаковок. Эти функции напрямую работают со стэком значений, не трансформируя что-либо. Слоёв абстракции сильно меньше. Только методы компонентов — из-за общности интерфейса: как со стороны луа, который позволяет передать любые значения и получить любые значения при вызове любого метода любого компонента, так и со стороны скалы, где трансформируются значения, — влекут за собой проход сквозь кучу обёрток, которые сильно роняют производительность. И только их оверхед я считаю существенным. Я вставил дебаг-принты в оцелота в том месте, где изменяется значение оставшегося бюджета вызовов. Каждый get занял 4.656612875245797×10-10 единиц. Это как раз 2-31. Даже миллиард таких вызовов не могут израсходовать бюджет настолько, чтобы компьютер прилёг на один тик. Бюджет — это же просто чиселка, которая уменьшается при каждом прямом вызове и регенится после каждого yield. Какой-либо эффект оно оказывает, только если уменьшается до нуля. При этом во время работы 16к вызовов ниже 1.499999 он даже не опускался. Однако потребление процессорного времени во время прокрутки цикла с 16к гетами стопроцентное.
-
1 баллЯ и не утверждал обратного, это уже какая-то нездоровая полемика. Проясню: 1) Я продемонстрировал, что комп умирает на несколько сек при обращении к gpu.get, предположив, что обращение к ненулевому буферу ни разу не бесплатное 2) Ты сообщил, что доминирует некий оверхед, а расход бюджета при обращении к ненулевому буферу должен быть 2-31 3) Я ответил, что значение в 2-31 слишком мало, и бюджета после 16к вызовов должно оставаться с запасом, и проблема явно в другом месте 4) Ты пояснил, что имел в виду под оверхедом, упомянув нативные либы, интерфейс Lua <> Scala и сам бюджет вызовов 5) Я не согласился, приведя пример с 16к вызовами unicode и computer, имитирующими оверхед без расхода бюджета, и работающий незаметно с точки зрения производительности. Поскольку из примера был исключен лишь расход бюджета, а работа нативных либ и прокидывания данных через Lua <> Scala сохранены, я сделал вывод, что к тормозам приводит именно бюджет Разве это не подтверждает тезис о том, что gpu.get кушает сильно больше 2-31 бюджета? Может быть, каждый вызов прямого метода компонента расходует некое константное кол-во бюджета в дополнение к прописанному в @Callback значению?
-
1 баллunicode.sub и computer.uptime — это не методы компонентов, а функции, которые практически напрямую дёргают методы луа и потому несравнимо дешевле. Сравнение нечестное. Проверил в оцелоте: 16к вызовов gpu.get заняли 0.80 секунд (avg 50 μs / call), а столько же computer.uptime — 0.04 (avg 2.5 μs / call). Такое же число вызовов методов других компонентов также занимают около 0.8 секунд. Потребление бюджета вызовов при этом остаётся околонулевое.
-
1 баллЯ тоже как раз про него и говорил. И по-прежнему не соглашусь. Заменяешь тело функции throttle из примера выше на любой код уровня Lua ↔ Scala типа unicode.sub("abcdef", 1, 2) или computer.uptime(), вызываешь его 160 * 50 * 2 раз перед выводом графики на экран через bitblt - и ничего не изменится. С позиции наблюдателя никаких микро-задержек не будет, bitblt отработает так же, как и без искусственного замедления, потому что, как ты сам подметил, bitblt скушает в сотни (если не тысячи) раз больше бюджета. А теперь вставляем 16к вызовов gpu.get на ненулевой буфер и наслаждаемся мертвым компом. Поэтому смею предположить, что реальный бюджет обращения GPU к ненулевому буферу сильно значимее 2-32, и практический эксперимент это подтверждает Чекнул, ловлю рантаймовую оплеуху. В кубаче работает, так что фиг с ним
-
1 баллЧестно говоря, не очень понял, что имеется в виду. Поэтому на всякий случай проясню, что имел в виду я. Если замена in-Lua буферов на VRAM привнесла задержки на порядок, то виноват, скорее всего, некто из следующих элементов: Lua. Нативные либы собраны с -O0.... и заметно тормозны. Сюда же пойдёт хук для TLWY. Оверхед из-за интерфейса Lua ↔ Scala (об этом ниже). Бюджет вызовов, который могут потреблять прямые вызовы get на ненулевой буфер. Каждый прямой вызов, даже если он бесплатный (а он должен быть практически бесплатным, если активен ненулевой буфер), проходит через слой Lua ↔ Scala. Это значит запаковать аргументы, проверить их, передать в сишную функцию от JNLua, которая для каждого аргумента создаст жвм-объект, найти колбэк по адресу компонента и имени метода, сожрать 2-32 единиц бюджета, произвести диспатч в колбэк, внутри него обработать вызов, потом принять результаты, их нормализовать в поддерживаемые JNLua, отдать в нативную сишную функцию от JNLua, которая каждый принятый жвм-объект преобразует обратно в луа-значения и вернёт их, потом полученные значения запаковать, проверить, распаковать и вернуть. Я надеюсь, что даже при таком длинном описании на деле это займёт не особо длительное время (думаю, порядка сотни микросекунд; источник оценки — потолок), однако если произвести 16 тысяч таких вызовов, то оверхед может стать достаточно существенным. Именно про этот оверхед я и говорил. Я предполагаю, что софтверное склеивание тормозит из-за него. Если гадать ещё безбашеннее, то можно сказать, что хук для TLWY вообще практически бесплатен на фоне него. Аргумент против этой гипотезы: ожидаемая задержка (0.5–1.5 секунд) от полученной (3 секунды) отличается разительно. А bitblt действительно пожирает очень много единиц бюджета вызовов. Если точнее, то для копирования из буфера 160×50 на основной гпу третьего уровня сожрёт 1.5 единиц бюджета (то есть практически точно положит комп на тик). Если копировать из буфера, площадь которого больше максимального основного разрешения соответствующего уровня, комп вообще будет спать несколько тиков. P. S. В довольно древней версии оцелота есть гпу-буферы в том виде, в каком они оказались в OC 1.7.6, и график бюджета вызовов. Можно протестить прогу там.
-
1 баллРазве это не смехотворно малая величина? В таком случае от бюджета серверной стойки в полной комплектации в 1.4 единицы должно оставаться 1.4 - 160 pix * 50 pix * (2 setActiveBuffer + 2 get) * 2-31, то есть 1.3999850988387 Хорошо, предположим, остаток полностью съедают вызовы функций. Пишем для теста любую функцию-заглушку и вызываем её примерно такое же кол-во раз, что и при группировке схожих пикселей: local function throttle() local a = 123 local b = a + 456 local c = a + b ^ a end function screen.update() for i = 1, 160 * 50 * (2 + 2) do throttle() end componentInvoke(GPUAddress, "bitblc", 0) end И... оно работает с той же скоростью, что и в первом примере. То есть на глаз разница не видна, хотя технически она, конечно, есть. Поэтому, имхо, расход бюджета сильно-сильно больше, а хук на вызовы особой роли не играет. Жаль только, что нет фичи вывода значения бюджета через debug.getCallBudgetValue, чтобы знать наверняка Хорошая идея. Закодил, чекнул, скорость действительно чуть возросла, но осталась в пределах ~1 кадра в 3 сек. Вообще мы осознанно убрали bitblc в угоду самописному решению, которое явно проигрывает, так что копать дальше в этом направлении смысла мало. Плюс у нас происходит дублирование вызовов setBackground/setForeground: первый раз во время отрисовки основной графики в буфер, а затем второй раз, но уже в сгруппированном по цветам виде при выводе на экран. Бедная видяшечка, на тайваньских майнинг-фермах и то живется легче (9
-
1 баллВозможно, не бюджет расходуется дико (насколько я понял, каждый прямой вызов в побочный буфер потребляет 2-31 единиц бюджета), а оверхед просто от вызовов доминирует. Кроме того, там можно выделять не два буфера по 160×50, а один на 160×100, например: число вызовов setActiveBuffer вдвое станет меньше. Хотя с таким оверхедом, видимо, не особо это поможет...
-
1 баллИдея занятная, но тормозит люто. Подправил либу, после склейки дело дошло до рендеринга лишь спустя ~5 сек, то есть комп фактически виснет на процессе поиска пикселей со схожими цветами на тоннах вызовов setActiveBuffer/get. У меня вообще зародилось смутное подозрение, что все операции над буферами ни разу не zero cost даже с поправкой на искусственный троттлинг хука вызовов в machine.lua. И ладно бы вывод на экран - сам процесс рисования в буфер через setBackground/setForeground/set явно кушает бюджет. Как говорится, численно доказать не могу, но эмпирически чувствую
-
1 баллК слову, насколько сильно будет тормозить решение, которое перенесёт массивы-буферы из луа в vram, но склеивание операций и рендер будет проводить всё так же в луа, не используя bitblt?
-
1 баллБаги, которые появились в 1.7.6: сломаный брайль, сломаная опенось, сломанная версия — пофиксили в спешном темпе и выпустили 1.7.7.
Эта таблица лидеров рассчитана в Москва/GMT+03:00
