Перейти к содержимому
  • 0
Belzebub

Неблокирующее поток мерило tps?

Вопрос

Хочу мерить tps-ы, не блокируя поток.
Все мои попытки тщетны, мб у кого то есть идеи по реализации?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Рекомендуемые сообщения

10 часов назад, Belzebub сказал:

Хочу мерить tps-ы, не блокируя поток.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Технически в опенкомпах нет потоков, и все ОСи могут лишь софтверно "скакать" с одной операции на другую, периодически блокируя друг друга и выполняя таски по списку. То есть тут всё блокирующее. Если тебя устроит просто отображать TPS раз в N сек, то заюзай таймер. Код для опеноси:

local event = require("event")
local computer = require("computer")
local component = require("component")
local gpu = component.gpu

-- Возвращает кол-во реальных (не игровых) наносекунд, прошедших с 00:00:00 01.01.1970 до момента изменения файла на диске 
local function getRealTimestamp()
  -- Получаем виртуального компонента filesystem, где можно создавать временную помойку
  local proxy = component.proxy(computer.tmpAddress())
  local path = "timestamp.tmp"

  -- Создаем временный файл
  proxy.close(proxy.open(path, "wb"))
  -- Получаем дату изменения
  local lastModified = proxy.lastModified(path)
  -- Удаляем его
  proxy.remove(path)

  return lastModified
end

-- Стартуем фоновый таймер, обновляющийся раз в 1 сек
local interval = 1
local lastModified = getRealTimestamp()

event.timer(
  interval,
  function()
    -- Примерное значение TPS рассчитывается как расхождение между желаемым интервалом в 1 сек и фактическим,
    -- полученным через разницу в датах изменения временного файла
    local tps = interval / (getRealTimestamp() - lastModified) * 20000
    
    -- Выводим значение TPS на экран
    local oldForeground = gpu.getForeground()
    gpu.setForeground(0xFFFFFF)
    gpu.set(1, 1, "TPS: " .. math.floor(tps + 0.5))
    gpu.setForeground(oldForeground)
    
    -- Все операции вывода на экран занимают время, лучше обновить переменную ещё раз для точности
    lastModified = getRealTimestamp()
  end
)

Профит:

 

NWRATGe.png

 

И для майноси:

local computer = require("Computer")
local component = require("Component")
local GUI = require("GUI")
local system = require("System")

-- Функция та же
local function getRealTimestamp()
  local proxy = component.proxy(computer.tmpAddress())
  local path = "timestamp.tmp"

  proxy.close(proxy.open(path, "wb"))
  local lastModified = proxy.lastModified(path)
  proxy.remove(path)

  return lastModified
end

-- Добавляем окошко программы в UI
local workspace, window, menu = system.addWindow(GUI.filledWindow(1, 1, 60, 20, 0xE1E1E1))

-- Создаем текстовый виджет по центру окошка
local layout = window:addChild(GUI.layout(1, 1, window.width, window.height, 1, 1))
local text = layout:addChild(GUI.text(1, 1, 0x4B4B4B, "Тут будет TPS"))

-- Вместо event.timer юзаем computer.uptime
local uptime = computer.uptime()

-- С файликами история та же
local lastModified = getRealTimestamp()
local interval = 1

text.eventHandler = function(workspace, text, e1, ...)
  -- Вычисляем, сколько сек прошло с последнего события
  local deltaTime = computer.uptime() - uptime

  -- Если прошло больше ожидаемого интервала
  if deltaTime > interval then
    -- Вычисляем TPS
    local tps = deltaTime / (getRealTimestamp() - lastModified) * 20000
    
    -- Обновляем текстовый виджет
    text.text = "TPS: " .. math.floor(tps + 0.5)
    text.width = #text.text
    workspace:draw()
    
    -- Обновляем переменные
    lastModified = getRealTimestamp()
    uptime = computer.uptime()
  end
end

workspace:draw()

 

Результат:

 

EZ4E9IK.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 час назад, ECS сказал:

event.timer( interval, function() -- Примерное значение TPS рассчитывается как расхождение между желаемым интервалом в 1 сек и фактическим, -- полученным через разницу в датах изменения временного файла local tps = interval / (getRealTimestamp() - lastModified) * 20000

Этот код работает более-менее правильно при условии, если таймер не блокируертся основным кодом. Например, если сразу за кодом таймера запустить os.sleep достаточной продолжительности.

 

Но если вместо os.sleep будет что-то вроде этого for i=1,1e8 do end, то TPS окажется сильно заниженным.

 

Проблему можно решить, если в расчётах использовать не значение interval, а разницу между computer.uptime в моменты запроса getRealTimestamp().

 

Изменено пользователем eu_tomat
ошибка: не завышенным, а заниженным

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Для иллюстрации предыдущего поста написал короткую демонстрацию:

local event = require"event"
local uptime = require"computer".uptime

local t, t_
local function onTimer()
  t_ = t
  t = uptime()
  print( (t-t_+0.025)//0.05 )
end

t = uptime()
event.timer( 1, onTimer )
os.sleep( 1.1 )

t = uptime()
event.timer( 1, onTimer )
for i=1,2e8 do end
os.sleep( 1.1 )

Результаты:

20.0
52.0

Как можно видеть, нет гарантии выполнения события таймера строго в назначенное время. В первом случае таймер сработал строго через 20 тактов. А во втором случае потребовалось 52 такта, хотя предполагалось именно 20.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
22 минуты назад, eu_tomat сказал:

Проблему можно решить, если в расчётах использовать не значение interval, а разницу между computer.uptime в моменты запроса getRealTimestamp()

Согласен, в майносевском примере я так и поступил. Для опеноси хотелось более простой пример привести, мало ли логическая цепь не особо ясна будет

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 минуты назад, ECS сказал:

в майносевском примере я так и поступил

Ой! Пример-то для майноси я пролистал не глядя. Я эту OS даже не запускал ни разу, не то что программы для неё изучать. Штука, конечно, прикольная, но я так и не смог придумать, зачем лично мне нужна MineOS. Прошу понять и простить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, eu_tomat сказал:

Штука, конечно, прикольная, но я так и не смог придумать, зачем лично мне нужна MineOS. Прошу понять и простить

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 часов назад, eu_tomat сказал:

Проблему можно решить, если в расчётах использовать не значение interval, а разницу между computer.uptime в моменты запроса getRealTimestamp().

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
В 26.12.2021 в 20:40, ECS сказал:

Хех, да я сам хз, для чего она нужна

Цель существования MineOS сейчас вполне ясна - быть демонстрацией возможностей мода OpenComputers. И она прекрасно с этим справляется.

Изменено пользователем vford
Речевая ошибка

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...