Fingercomp
-
Публикации
1 629 -
Зарегистрирован
-
Посещение
-
Победитель дней
283
Комментарии блога, опубликованные пользователем Fingercomp
-
-
42 минуты назад, ECS сказал:16к вызовами unicode и computer, имитирующими оверхед без расхода бюджета
В том и дело, что они оверхед этот не имитируют. Там нет никаких преобразований, упаковок и распаковок. Эти функции напрямую работают со стэком значений, не трансформируя что-либо. Слоёв абстракции сильно меньше.
Только методы компонентов — из-за общности интерфейса: как со стороны луа, который позволяет передать любые значения и получить любые значения при вызове любого метода любого компонента, так и со стороны скалы, где трансформируются значения, — влекут за собой проход сквозь кучу обёрток, которые сильно роняют производительность. И только их оверхед я считаю существенным.
47 минут назад, ECS сказал:Разве это не подтверждает тезис о том, что gpu.get кушает сильно больше 2-31 бюджета?
Я вставил дебаг-принты в оцелота в том месте, где изменяется значение оставшегося бюджета вызовов. Каждый get занял 4.656612875245797×10-10 единиц. Это как раз 2-31. Даже миллиард таких вызовов не могут израсходовать бюджет настолько, чтобы компьютер прилёг на один тик. Бюджет — это же просто чиселка, которая уменьшается при каждом прямом вызове и регенится после каждого yield. Какой-либо эффект оно оказывает, только если уменьшается до нуля. При этом во время работы 16к вызовов ниже 1.499999 он даже не опускался.
Однако потребление процессорного времени во время прокрутки цикла с 16к гетами стопроцентное.
-
1
-
-
15 часов назад, ECS сказал:Я тоже как раз про него и говорил. И по-прежнему не соглашусь. Заменяешь тело функции throttle из примера выше на любой код уровня Lua ↔ Scala типа unicode.sub("abcdef", 1, 2) или computer.uptime(), вызываешь его 160 * 50 * 2 раз перед выводом графики на экран через bitblt - и ничего не изменится.
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
-
-
1 час назад, ECS сказал:И... оно работает с той же скоростью, что и в первом примере. То есть на глаз разница не видна, хотя технически она, конечно, есть. Поэтому, имхо, расход бюджета сильно-сильно больше, а хук на вызовы особой роли не играет.
Честно говоря, не очень понял, что имеется в виду. Поэтому на всякий случай проясню, что имел в виду я.
Если замена 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
-
14 минуты назад, ECS сказал:Идея занятная, но тормозит люто. Подправил либу, после склейки дело дошло до рендеринга лишь спустя ~5 сек, то есть комп фактически виснет на процессе поиска пикселей со схожими цветами на тоннах вызовов setActiveBuffer/get. У меня вообще зародилось смутное подозрение, что все операции над буферами ни разу не zero cost даже с поправкой на искусственный троттлинг хука вызовов в machine.lua. И ладно бы вывод на экран - сам процесс рисования в буфер через setBackground/setForeground/set явно кушает бюджет. Как говорится, численно доказать не могу, но эмпирически чувствую
Возможно, не бюджет расходуется дико (насколько я понял, каждый прямой вызов в побочный буфер потребляет 2-31 единиц бюджета), а оверхед просто от вызовов доминирует. Кроме того, там можно выделять не два буфера по 160×50, а один на 160×100, например: число вызовов setActiveBuffer вдвое станет меньше. Хотя с таким оверхедом, видимо, не особо это поможет...
-
1
-
-
12 часа назад, ECS сказал:Плюсы: расход RAM упал до 25% на полностью инициализированную систему с загруженными (но не отрисованными) иконками. Для слабых машин это очень хороший показатель, и освободившиеся ресурсы можно было бы направить на прикладной многозадачный софт.
Минусы: оно лагает сильнее, чем софтверное решение с графоном!11
К слову, насколько сильно будет тормозить решение, которое перенесёт массивы-буферы из луа в vram, но склеивание операций и рендер будет проводить всё так же в луа, не используя bitblt?
-
1
-
-
Баги, которые появились в 1.7.6: сломаный брайль, сломаная опенось, сломанная версия — пофиксили в спешном темпе и выпустили 1.7.7.
-
1
-
-
7 минут назад, ProgramCrafter сказал:Пролистал RFC7230. Как ни странно, не нашёл там указаний на то, что после отправки сообщения сервер не может по тому же соединению отправлять ещё бессмысленный мусор. А если Content-Length меньше длины полученных данных, то не указано, корректный это заголовок или нет.
Хм. Действительно, в RFC7230 валидный Content-Length — любое целочисленное неотрицательное значение. Попытался найти, почему я решил, что нельзя слать больше, чем в Content-Length, и обнаружил следующее в устаревшей версии стандарта:
ЦитатаWhen a Content-Length is given in a message where a message-body is allowed, its field value MUST exactly match the number of OCTETs in the message-body. HTTP/1.1 user agents MUST notify the user when an invalid length is received and detected.
— RFC2616: “Hypertext Transfer Protocol -- HTTP/1.1”, §4.4, стр. 34
Что, в принципе, объясняет мою уверенность. В таком случае, действительно, стоит ориентироваться на Content-Length. Статью исправлю соответствующе. Спасибо за замечания.
-
2
-
-
20 минут назад, ProgramCrafter сказал:Претензия к пункту 3.3. Программа читает столько данных, сколько может - если сервер укажет маленький Content-Length и отправит гигабайт данных, программа всё это будет читать.
Потрясающее замечание. Отвечу развёрнуто с удовольствием.
Если посмотреть на код, то можно заметить, что я эту проблему опознал и в случае несоответствия в меньшую сторону я решил хедер игнорировать (собственно, поэтому в сравнении там оператор >=). К сожалению, когда код я стал комментировать, про это совершенно забыл — и без этого коммента бы, наверное, и не вспомнил.
Претензия имеет силу, если мы обратимся к стандарту. Юзер-агент должен в случае получения невалидного хедера Content-Length просигналить об ошибке и выбросить полученные данные:
Цитата4. If a message is received without Transfer-Encoding and with either multiple Content-Length header fields having differing field-values or a single Content-Length header field having an invalid value, then the message framing is invalid and the recipient MUST treat it as an unrecoverable error. If this is a request message, the server MUST respond with a 400 (Bad Request) status code and then close the connection. If this is a response message received by a proxy, the proxy MUST close the connection to the server, discard the received response, and send a 502 (Bad Gateway) response to the client. If this is a response message received by a user agent, the user agent MUST close the connection to the server and discard the received response.— RFC7230: “Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing”, §3.3.3, стр. 32–33
Более того, когда писал код, специально стандарт вычитывал именно поэтому. Почему же тогда в статье я решил игнорировать его предписания, притом намеренно? Для простоты. Чтобы не вдаваться в детали HTTP, не рассказывать про Transfer-Encoding и не требовать реализации алгоритма из цитированного стандарта.
Чтобы быть предельно педантным, нужно сначала проверить, не стоит ли Transfer-Encoding (потому что иначе длина неизвестна), потом убедиться, что все Content-Length имеют одно и то же значение (это тоже в статье я не освещал, но требуется стандартом), а затем читать данное число байт: если фактически пришло меньше или больше, ответ отбросить и вернуть ошибку.
Или же подойти с прагматической стороны, учесть, что по соединению из OC мы можем отправить ровно один HTTP-запрос и забить на эту сложность. Возможно, стоит проверить, что Content-Length все имеют согласованное значение и являются интами, чтобы быть уверенным в ожидаемой длине. Самое главное, что требуется от того кода: убедиться, что соединение не порвалось посередине ответа.
Поэтому, хотя всех тонкостей HTTP я действительно не знаю, я бы не спешил декрементить счётчик. :P
-
1
-
1
-
-
@eu_tomat можешь, пожалуйста, в статьях пофиксить \n, слетевшие после обновлений форума несколько лет назад? Кинул человеку статью эту почитать, а тут всё слилось в однострочники.
-
OpenOS. От дуба до Мастера. Часть первая. [|··]
Блог пользователя: Fingercomp
1 час назад, rootmaster сказал:ну так эти компоненты реализуются модом, а не openOS, а openOS написана на чистом lua
Специально самые древние посты ищешь, чтоб понекропостить?
-
1
-
1
-
-
3 часа назад, Asior сказал:На 1.7.10 частоту можно до 64000 поднять, скорость ленты соотвественно в 2 раза повышать. Качество улучшается но объем минут уменьшается
Вернее, 65536. Там по умолчанию частота дискретизации — 32768.
-
16 часов назад, Bumer_32 сказал:А из за чего может возникать проблема с помехами? Нету способа её исправить?
DFPWM сам по себе уже есть довольно шумный кодек, вообще говоря. (Зато 1 бит на сэмпл — пожато добротно.) Если проигрывать намерение на версиях MC 1.8 и выше, то нужно конвертировать в формат DFPWM1a: в конвертере галочка для этого есть. На 1.7.10, обратно, галку проставлять не надо. Можно увеличить частоту дискретизации в 1/4 ≤ n ≤ 2 раз (на новом кодеке, например, 96000 выставить); на плеере потом нужно скорость соответственно установить. Будет не сильно, но лучше. Но и места больше займёт.
Проигрываемое там через LP filter прогоняется, поэтому высокочастотное послушать не удастся.
-
В 15.06.2021 в 16:23, ECS сказал:плата не позволяет асинхронно воспроизводить новые звуки до тех пор, пока предыдущий sound.process() не завершён
Так и есть, насколько могу понять. Можно не рисовать сразу на полсекунды задержку, а каждый тик синхронизироваться, например. Но с задержкой в 50 ms адекватно играть на пианинке (ну, лично мне) невозможно.
Если сделать интерфейс вроде трекера, то можно посылать на звуковую карточку уже готовые аудиокуски, а с миди-клавиатуры ввод принимать, чтобы сориентироваться, какую ноту дальше написать или понять, норм аккорд подобрал или не очень. Тогда можно смириться с задержкой.
У меня на синезубых наушниках примерно такая же ситуация и получается, поэтому мелодию мышкой накликиваю просто.
Или таки ставить несколько звуковых карт, да.
-
29 минут назад, Mihis сказал:Я так понимаю, что TLS присутствует только для запросов (https://)?
Если да, то как можно передавать поток, чтобы он оставался защищенным без использования Data Card?
В OC встроен TLS только для HTTPS-запросов. Если надо кастомный TCP-сокет, обёрнутый в TLS, то надо самому имплементить TLS-протокол. Без дата-карты 3 уровня будет сложно: придётся делать криптографические примитивы на Lua.
-
1
-
-
35 минут назад, hohserg сказал:Нет, там ошибка или опечатка, будет 1.167
Опечатка. Поправил. Спасибо.
-
3 часа назад, ov3rwrite сказал:Не читал комменты выше но вообще-то есть обертка для всего этого.Почитайте https://ocdoc.cil.li/api:internet.Полезные там только 2 функции и это internet.open() и internet.request().
Вообще, из наличия в статье пятого пункта уже следует, что с обёртками я знаком и в путешествии к докам не нуждаюсь. Поэтому буду считать, что этот комментарий не ко мне обращён. Тем не менее, обе функции бесполезны, кроме примитивных случаев.
internet.request не ждёт соединения с сервером. Хотя она прокидывает ошибки через error, этого недостаточно. См. 3.2–3.4 про то, как правильно послать запрос и получить ответ. А с таким кодом смысла в использовании обёртки ноль.
internet.open кладёт оригинальный сокет в приватные свойства. Заставляет программиста постоянно и без причины дёргать :read() и не даёт воспользоваться сигналом internet_ready. Поэтому не только бесполезен, но и вреден. Нужно вызывать internet.socket, чтобы можно было получить id сокета и вызвать finishConnect, и вручную класть стрим в буфер. См. 4.5–4.8 про то, как правильно создать и использовать сокет.
Таким образом, действительно полезна только одна функция — internet.socket. И очень зря она не удостоилась такой характеризации цитируемым комментарием.
-
3
-
1
-
-
3 часа назад, levshx сказал:Непоняв, так как мне использовац этот ваш request, просто по ссылке мне нид получать JSON ответ
я добавив ваш код, выполняюlocal stat = request("https://levshx.000webhostapp.com/loader.php?option=stat", nil,nil,5)if stat then...но stat = nil шо за приколы
Этот пост, я ещё раз повторюсь, не столько про интернет-карточку, сколько про обработку ошибок. Даже assert поставить — это уже обработка ошибок.
local handle = assert(request(url, nil, nil, 5))
В коде из цитаты обработки ошибок нет. Ошибка если и есть, то теряется. Такой код проблему не решает и ещё порождает новые. Поэтому код неправильный.
3 часа назад, levshx сказал:и скока надо пихать в timeout непанятна
Меня огорчает, что код скопирован, а времени то, чтобы понять, как он работает, не потрачено совершенно.
Внутри функции request находится цикл. Этот цикл ждёт соединения с сервером. timeout ограничивает время пребывания в этом цикле. Сколько ставить — это не мне решать, поэтому именно он и параметром к функции выведен. Зависит от программы.
3 часа назад, levshx сказал:очень сложна, так то всё работало с простым request просто со временем крашилась программка
Сетевые приложения никогда не были простыми. Исключительных случаев огромное множество, и за всеми надо уследить. В посте я постарался объяснить, зачем я использую свою обёртку и что именно она делает.
3 часа назад, levshx сказал:пажаласта можно пример использавання ?
Я не могу дать полностью готовый кусок кода и сказать, что это канон. Самое универсальное — это функция request. Как использовать, зависит от приложения.
Здесь я нарисовал с assert пример — при любой ошибке программа будет крашиться. Удобно при разработке.
Если есть консольный интерфейс, надо ошибку обрабатывать явно. Например:
local handle, err for i = 0, math.huge, 1 do handle, err = request(url, nil, nil, 5) if handle then break end local delay = math.min(180, i ^ 3) io.stderr:write([[ We've had a problem fetching a webpage: %s. Retrying in %d seconds...]]):format(err, delay)) os.sleep(delay) end
В посте как раз консольная программка, к слову.
Если интерфейс графический, ошибку писать надо куда-то ещё. Если программка автономная, то ошибку куда-то в лог класть.
-
2
-
1
-
-
12 минуты назад, ECS сказал:Я не про do ... end, а про __. Дело привычки, видимо.
А-а-а. Вспомнил Python полгода назад, а там приватные поля как раз через __ оформляются. Теперь вот и в Lua так делаю. С одной стороны, если юзер смотрит, какие поля есть (в интерпретаторе Lua в OpenOS есть автодополнение по полям таблицы), он сразу видит, что это что-то внутреннее, что может сломаться при обновлении либы, даже не смотря в доки. С другой стороны, если ему надо что-то закостылять, чего автор либы не предусмотрел, есть где развернуться.
-
1
-
1
-
-
34 минуты назад, ECS сказал:Ну почему же? Возьмем элементарный код: ...
И ведь действительно. Самое простое упустил. ¯\_(ツ)_/¯
37 минут назад, ECS сказал:Но зачем тогда усложнять изящную либу и делать приватные члены?
Не, do .. end — это исключительно для структурирования кода конструкция. А setmetatable заменяет цикл. Приватными вещи в луа делать смысла большого не вижу, если только не требуется это задачей (например, публичный луа-терминал делать). Достаточно пометить внутренние функции через __.
-
1
-
-
55 минут назад, ECS сказал:Новичков отпугнёт.
Критика валидная. Да, это так, не отрицаю. Четвёртый пункт не для новичков. Если бы я писал для новичков, сначала бы пришлось описывать, что такое сокет, что значат 3 буквы TCP, чем request не устраивает. Эта часть предназначена целиком для тех, кто уже пользовался сокетами (не обязательно на Lua).
В целом, вся запись подразумевает, что читатель уже знает Lua и использовал интернет-плату прежде. Наверное, надо было об этом написать явно.
1 час назад, ECS сказал:Во-первых, какое, блин, ООП?
В чужой программе у меня возникли бы те же сомнения. "А чем процедурный стиль не угодил?" — этот вопрос задал бы в первую очередь.
Получилось это так. Изначально я писал библиотеку, а не приложение. Написав 80% текста, я затем передумал и решил превратить библиотеку в чат-клиент. Но переписывать весь код было жалко, поэтому выбросил лишь отдельные части. Если бы начинал сразу приложением оформлять, разумеется, ООП был бы бесполезным, так как настройки бы все я запёк в константах в начале программы. Но мне было лень. Добавил для этого пункт 4.1, переписал 4.2, вставил в остальные пункты контекст и решил, что и так сойдёт.
Не знаю, стоит ли сейчас переписывать без объектов. В коде только self исчезнет.
1 час назад, ECS сказал:Во-вторых, "привычно" для кого, для Fingercomp'а? В луа не имеется общепринятых конвенций по реализации объектов.
Гм. Я до этого комментария считал наоборот. Где бы ни рассказывали здесь про то, как делать ООП, шаблон один и тот же: функция-конструктор new, метатаблица в некотором виде (где-то с рекурсивной ссылкой в __index, где-то таблица методов и {__index = methods} в конструкторе). do ... end — моя отсебятина, но выполняет она исключительно декоративную функцию.
А какие ещё способы используются? На ум приходят только замыкания, но это уже какой-то костыль экзотический.
P. S. Вообще, приятно, что кто-то потратил время, чтобы дельно покритиковать. :3
-
1
-
1
-
-
28 минут назад, Totoro сказал:Лайк за клиент для Stem'а.
Звучит, будто кроме стема остальное лайка не заслуживает.
-
1
-
-
35 минут назад, eu_tomat сказал:Что такое ханк? Хак?
Не знал, как по-русски понятно написать, оставил транскрипцией — hunk, часть диффа.
-
OpenPeripheral: Integration #1 Ванилла (и Чокола)
Блог пользователя: Xytabich
13 минуты назад, eu_tomat сказал:Да, точно же! Я почему-то думал, что нет у него исходников. Просто я иногда пытался что-то из модов декомпилировать, и не всегда получалось.
В названии OpenPeripheral первые 4 буквы недвусмысленно намекают на то, что в исходниках можно легко покопаться. :P
-
1
-
-
OpenOS. От дуба до Мастера. Часть вторая. [|··]
Блог пользователя: Fingercomp
4 часа назад, Hemou_ сказал:А как например напрямую открыть файл через function ?
Из скрипта программы?
local configPath = "/etc/program.cfg" local f = io.open(configPath, "r") local cfg = f:read("*a") f:close() local logPath = "/tmp/program.log" local log = io.open(logPath, "w") log:write("[01:01:01] Program started!\n") log:write("[01:01:10] Program stopped!\n") log:close()

OpenComputers 1.8.0
в Fingercomp's Playground
Блог пользователя: Fingercomp
Опубликовано:
Немного погодя выпустили версию 1.8.1 с багфиксами. 1.7.10 / 1.12.2. Откатили интернет-карточку к прежнему состоянию, потому что там как-то слишком много багов оказалось.