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

ECS

Гуру
  • Публикации

    533
  • Зарегистрирован

  • Посещение

  • Победитель дней

    203

Сообщения, опубликованные пользователем ECS


  1. Очень даже удобно, что если где-то доигрался с computer.pullSignal, можно всё равно остановить программу

    И очень даже неудобно, если требуется запретить прерывание софтины в частности. Если я желаю остановить выполнение зависшего скрипта, использовать фильтры и листенеры, то, очевидно, воспользуюсь библиотекой event, в противном случае я стану использовать нативный метод pullSignal. Увы, эту возможность у кодеров под OpenOS нагло отняли и навязали подмену функции без разумного объяснения причин. Высказывание автора о том, что он "never liked the user solution to be change this openos internal method" я разумным счесть не могу, ибо на производительность OpenOS это никак не повлияет, а немаловажная фича была слита в унитаз. Это не разумная причина, а субъективная придурь, и именно поэтому я и использовал термин "ерунда", и именно поэтому решение ерундовое


  2.  

     

    в версиях новых OpenOS интеррапт обрабатывается в том числе и в computer.pullSignal (он переопределяется в /lib/event.lua)
     

    Фига, не ждал от них подобной ерунды, еще один повод  в копилку "отказаться от опеносовской либы". Если по теме, то проверил следующий код на последней версии опенкомпов, интерруптинг отключается без проблем:

    event.shouldInterrupt = function() return false end
    event.shouldSoftInterrupt = event.shouldInterrupt
    
    • Нравится 1

  3. Простым решением проблемы будет использование computer.pullSignal() вместо event.pull(), убрав тем самым поддержку прерывания скрипта. В качестве альтернативы предлагаю эквивалентную по структуре либу, где для отключения прерывания необходимо поставить флаг event.interruptingEnabled = false


  4. Да, но такие программы должны слушать событие "screen_resized", чтобы сразу обновить свои переменные в соответствии с новым размером окна. 

     

    Ну, в современных фреймворках при изменении размера окна генерируется банальный ивент, и содержимое окна лишь "обрезается" в соответствии с его границами. А уж изменять геометрию содержимого или оставлять прежней - это задача программиста прикладного ПО, так что не вижу в прослушке событий ничего плохого.

     

    К примеру, в QT это реализовывается так:

    void MyMainWindow::resizeEvent(QResizeEvent* event)
    {
       QMainWindow::resizeEvent(event);
       // Do something
    }

  5. Не нашел в интернете алгоритм Питера Ширли, да и его в целом, выскакивает какой-то музыкант) Можно узнать где вы нашли его алгоритм? Хотя бы ссылку или книгу, может у него и другие эффективные алгоритмы есть.

     

    Спасибо за советы, приму к сведению и постараюсь применить их в новой версии кода :)

     

    Книга "Fundamentals of Computer Graphics", хоть она и не очень: есть пара интересных алгоритмов по быстрой растеризации примитивов, но именно что лишь пара. Да и те пришлось изрядно оптимизировать, чтобы GC не грузили.

    • Нравится 2

  6. Годная софтинка. Пожалуй, стырю в качестве скринсейвера, если не против. Есть, правда, парочка деликатных моментов: во-первых, отрисовка линий через atan/sin/cos хоть и проста, но крайне неэффективна. Рекомендую использовать следующий код, основанный на модифицированном алгоритме Питера Ширли и предназначенный специально для низкопроизводительных машин (значительно быстрее, чем классический алгоритм Брезенхема):

    local function line(x1, y1, x2, y2, color)
      local inLoopValueFrom, inLoopValueTo, outLoopValueFrom, outLoopValueTo, isReversed, inLoopValueDelta, outLoopValueDelta = x1, x2, y1, y2, false, math.abs(x2 - x1), math.abs(y2 - y1)
      if inLoopValueDelta < outLoopValueDelta then
        inLoopValueFrom, inLoopValueTo, outLoopValueFrom, outLoopValueTo, isReversed, inLoopValueDelta, outLoopValueDelta = y1, y2, x1, x2, true, outLoopValueDelta, inLoopValueDelta
      end
     
      if outLoopValueFrom > outLoopValueTo then
        outLoopValueFrom, outLoopValueTo = outLoopValueTo, outLoopValueFrom
        inLoopValueFrom, inLoopValueTo = inLoopValueTo, inLoopValueFrom
      end
     
      local outLoopValue, outLoopValueCounter, outLoopValueTriggerIncrement = outLoopValueFrom, 1, inLoopValueDelta / outLoopValueDelta
      local outLoopValueTrigger = outLoopValueTriggerIncrement
      for inLoopValue = inLoopValueFrom, inLoopValueTo, inLoopValueFrom < inLoopValueTo and 1 or -1 do
        if isReversed then
          -- setPixel(outLoopValue, inLoopValue, color)
        else
          -- setPixel(inLoopValue, outLoopValue, color)
        end
     
        outLoopValueCounter = outLoopValueCounter + 1
        if outLoopValueCounter > outLoopValueTrigger then
          outLoopValue, outLoopValueTrigger = outLoopValue + 1, outLoopValueTrigger + outLoopValueTriggerIncrement
        end
      end
    end

    Во-вторых, я бы использовал либу буферизации графики, чтобы не было "промигиваний", и была возможность выставлять хоть 50 линий за раз. Также она уже имеет функции растеризации отрезков, в том числе полупиксельных:
     
    FLMot0V.png?1

    • Нравится 5

  7. Библиотека обновлена. Исправлены мелкие баги, а также добавлено несколько вкусных плюшек:

     

    • Появилась возможность создания автоматических анимаций виджетов:

     

    f5aO73U.gif

     

    • Контекстное меню заимело фичу скроллинга контента, а также поддержку вложенных контекстных меню:

     

    A9NCEdc.gif

     

    • Значительно улучшен GUI.layout, заимев поддержку абсолютного и релятивного размеров ячеек, возможность выравнивания и отступов по произвольному краю, возможность установки расстояния между элементами, а также фиттинга элементов по размеру ячейки:

     

    qf91PuM.png

     

    C2TWOJ7.png?1

     

    • Появились два дополнительных варианта отрисовки GUI.button, а также их adaptive-аналоги:

     

    9zZvR6g.gif

     

    • Появился виджет GUI.brailleCanvas, позволяющий быстро и просто отрисовывать мелкую графику при помощи шрифта Брайля:

     

    3Oq1nzY.png

    • Нравится 7

  8. Это что за программы? Есть пример? Я привык, что всегда нужно pullSignal писать в программе, чтобы она работала 

    local redstone = require("component").redstone
    while true do
      redstone.setOutput(1, math.random(15))
    end 

    Что примечательно, эту софтину возможно завершить только путем отсоединения редстоун-компонента. Как верно подметил eu_tomat, каждое обращение к нему ведет себя аналогично .pullSignal(), однако не вызывает его


  9. Есть пример рабочей реализации? Чтобы две-три программы работали, рисовали графику. Я бы посмотрел исходники

     

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

     

    hTFGCqj.gif

    • Нравится 4

  10. Многозадачность можно реализовать двумя путями:

     

    Есть третий принципиально отличающийся вариант: обработка нескольких приложений-окон в общем потоке-контейнере. Из плюсов тут стоит выделить максимальное быстродействие, т.к. выполнение скрипта не будет искусственно замедлено множественными yield() в подмененных функциях, а также простоту написания такого концепта. Из минусов - поддерживать многозадачность будет лишь то ПО, которое написано под данную ОС, все остальное будет работать в штатном режиме. А также имеет место быть стабильный краш главного потока при краше любого из приложений - проблема решается изоляцией пространства приложения от контейнера и кешированием его состояния.


  11. Переменная весит сколько весит ссылка в ОS.

    А вот объект на который ссылается переменная весит в зависимости от типа.

    Как ты понимаешь ссылка это не объект на стеке и она ссылается на объект в твоей мапе который ты и так хранишь.

    nil помогает в том случае если у тебя переменная находится в скопе из которого ты часами не выходишь.

     

    Для справки: каждая переменная-указатель на таблицу или функцию в Lua весит в равной мере 9 байт.

     

    А теперь немного сухих расчетов: представим простейшую трехмерную сцену из восьми кубиков. Каждый куб имеет 8 вершин, каждая вершина - это трехмерная таблица-вектор с числовой индексацией, в сумме кушающая 40 (table) + 8 (double) * 3 = 64 байта. Все вершины заносятся в массив вершин сцены для минимизации расхода памяти. Также каждый куб имеет таблицу-линковщик, содержащую индексы вершин, образующие треугольники для отрисовки куба в количестве 12 штук. Каждый треугольник с ссылками на три вершины - это такой же трехмерный вектор, кушающий все так же 64 байта. Итого получаем 64 * 8 = 512 байт на вершины и 64 * 12 = 768 байт на линковку вершин, итого 1280 байт на куб. Сколько у нас там их? Восемь? Итого трехмерная сцена выжрет 1280 * 8 = 10240 байт = 10 КБайт. Это тот минимум, который необходим для старта отрисовки графики, материалы и текстуры для простоты рассматривать не будем. Если же использовать локальные переменные-сокращалки, то расход памяти взлетит по экспоненте.

     

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

    for triangleIndex = 1, #OCGL.triangles do
    	vertex1[1], vertex1[2], vertex1[3] = renderer.viewport.xCenter + OCGL.vertices[OCGL.triangles[triangleIndex][1]][1], renderer.viewport.yCenter - OCGL.vertices[OCGL.triangles[triangleIndex][1]][2], OCGL.vertices[OCGL.triangles[triangleIndex][1]][3]
    	vertex2[1], vertex2[2], vertex2[3] = renderer.viewport.xCenter + OCGL.vertices[OCGL.triangles[triangleIndex][2]][1], renderer.viewport.yCenter - OCGL.vertices[OCGL.triangles[triangleIndex][2]][2], OCGL.vertices[OCGL.triangles[triangleIndex][2]][3]
    	vertex3[1], vertex3[2], vertex3[3] = renderer.viewport.xCenter + OCGL.vertices[OCGL.triangles[triangleIndex][3]][1], renderer.viewport.yCenter - OCGL.vertices[OCGL.triangles[triangleIndex][3]][2], OCGL.vertices[OCGL.triangles[triangleIndex][3]][3]
    	material = OCGL.triangles[triangleIndex][4]
    
    ...

    Также привожу скриншот с результирующим FPS в 7 единиц и расходом оперативной памяти в 46% от максимального запаса (4 Мб)

     

    IXkJ4qZ.png?1

     

     

    А теперь намутим-ка локальных сокращений для минимизации нагрузки на ЦП:

    local ti, ve1, ve2, ve3
    for triangleIndex = 1, #OCGL.triangles do
    	
    	ti = OCGL.triangles[triangleIndex]
    	ve1, ve2, ve3 = OCGL.vertices[ti[1]], OCGL.vertices[ti[2]], OCGL.vertices[ti[3]]
    
    	vertex1[1], vertex1[2], vertex1[3] = renderer.viewport.xCenter + ve1[1], renderer.viewport.yCenter - ve1[2], ve1[3]
    	vertex2[1], vertex2[2], vertex2[3] = renderer.viewport.xCenter + ve2[1], renderer.viewport.yCenter - ve2[2], ve2[3]
    	vertex3[1], vertex3[2], vertex3[3] = renderer.viewport.xCenter + ve3[1], renderer.viewport.yCenter - ve3[2], ve3[3]
    	material = OCGL.triangles[triangleIndex][4]
    
    ...

    Результат плачевный. Не замечено ни прироста, ни убыли значений FPS, однако расход памяти возрос до 61%. Магия? Нет, особенности конкретного ЯП и его интеграции в виде мода.

     

    tq3OUxU.png?1

    • Нравится 1
    • В шоке 1

  12. RccHD немного не убедительно написал, я попробую его поправить.

    1. выполнение buffer.currentFrame[index]

       -- обращение к переменной buffer

       -- обращение к полю объекта. Но мы имеем дело с lua, по-этому buffer это HashMap а currentFrame это ключ.

           - расчёт hash("currentFrame")

           - определение смещения по хешу

           - выборка списка (может дерева) элементов по смещению из массива

           - разрешение коллизий (дорого)

           - ...

     

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

     

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

     

    Ручной вызов GC в OpenComputers невозможен, эта фича отключена авторами мода по понятным причинам. Если бы я мог активировать сборку мусора - то неужели стал бы писать сюда о проблемах с локальными переменными?

     

    И переменная весит ровно 64 бита.

     

    Переменная весит столько, сколько определено ее типом: строки занимают 17 байт + длина самой строки, таблица кушает 40 байт + ее содержимое, каждая функция - 20 байт + локальные данные. Пожалуйста, не пиши глупости без знания матчасти.

     

    Мне кажется, что кто-то просто забывает писать ключевое слово local.

     

    А мне кажется, что кто-то слишком много умничает не по делу. Использование локальных переменных - чуть ли не основа основ при кодинге на любом ЯП. И присвоение переменной nil, как оказалось, отнюдь не ускоряет ее очистку из памяти, ибо, разумеется, этот вариант мы также рассматривали.

    • Нравится 2

  13. Всегда считал, что переменные(они же указатели на объекты) не могут занимать много памяти... Хотя бы потому что исходники библиотек OpenOS прямо-таки напичканы переменными. Может дело все-таки не в таких мелочных деталях как переменные, а в самой реализации?

     

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

     

    А насчет исходников OpenOS - с каких это пор они стали эталоном грамотного и эффективного кода? Лично я вообще не понимаю, что в ней может кушать столько памяти (пс-с-ст, более 200 КБайт по дефолту, жуть какая). Хотя приведенный тобой пример вносит определенную ясность хд

    • Нравится 1

  14. По поводу нагрузки на ЦПУ: писать "buffer.currentFrame[index]" плохо так как система будет каждый раз выполняет следующие действия: 1) получает значение переменной "buffer" 2) получает поле "currentFrame" объекта "buffer" 3) получает поле "index" объекта "buffer.currentFrame" А если хранить это значение в переменной, то будет одно действие: 1) получает значение переменной "el0

     

    Увы, такой подход крайне нерационален. Безусловно, визуально куда проще выделить локальную переменную под жирную таблицу с множеством вложенных обращений, сэкономив тем самым несколько тиков - однако если бы я использовал такой подход при написании требовательного софта, то он вылетал бы с not enough memory еще до старта. Примером может послужить наш 3D-движок: сборщик мусора банально не успевал очищать локальные переменные-указатели на таблицы векторов при отрисовке сцен, и ошибка о нехватке памяти вылезала как результат. Сократив подобный "некорявый код" до минимума, мы смогли запустить движок всего лишь на 2 МБ RAM. Так что лучше помучиться с лишними буковками, нежели писать неоптимизированное в данном контексте ПО. Имхо, конечно же

    • В шоке 1

  15. блиотека довольно коряво в плане стиля написания кода(мое личное мнение)

     

    Ну блин, стараешься тут, стараешься, разбивая код на суб-сегменты по классическим идиомам проектирования, минимизируя нагрузку на оперативку и ЦПУ, а потом его "корявым" называют. Обидно  :wacko:

     

    А вообще интересно, каким образом ты уменьшил размер сырцов в 5 раз - уж не путем ли удаления половины "не нужных" для твоей ОС элементов? Го инфу, любопытно стало.

    • Нравится 4

  16. MNLWULz.gif
     
    Cобсна, программа проста, как три копейки: левый и правый клики по спиннеру меняют его цвет, а нажатие на любую клавишу позволяет выйти. Надеюсь, любители особых извращений оценят ее по достоинству.

     

    Команда для установки:

    pastebin run MMvSd2be
    

    Команда для запуска:

    /Spinner/Main.lua
    • Нравится 3

  17. local filesystem = require("filesystem")
    
    ---------------------------------------------------------------------
    
    function table.unserialize(serializedString)
      checkArg(1, serializedString, "string")
      local success, result = pcall(load("return " .. serializedString))
      if success then
        return result
      else
        return nil, result
      end
    end
    
    function table.fromFile(path)
      checkArg(1, path, "string")
    
      if filesystem.exists(path) then
        if filesystem.isDirectory(path) then
          error("\"" .. path .. "\" is a directory")
        else
          local file = io.open(path, "r")
          local data = table.unserialize(file:read("*a"))
          file:close()
    
          return data
        end
      else
        error("\"" .. path .. "\" doesn't exists")
      end
    end
    
    ---------------------------------------------------------------------
    
    local myTable = table.fromFile("/myFileWithTable.lua")
    

     

    Десериализация таблицы на чистом луа без лишних библиотек


  18. local function sleep(timeout)
      local deadline = computer.uptime() + (timeout or 0)
      while computer.uptime() < deadline do
        computer.pullSignal(deadline - computer.uptime())
      end
    end
    

    Держи простейший вариант задержки, учитывающий возможные ивенты, если дефолтный os.sleep юзать не можешь/не хочешь


  19. Может заменить округление на целочисленное деление на 1?

    10мультов операций деления на 1 и округления вниз

    b8197d28be2e27a17c035c4281f0baa2.png

     

     

    iterCount = 10000000
    print(iterCount, 'cycles')
    
    startTime = os.clock()
    for i=1,iterCount do
    a=1.1//1
    end
    print('1.1//1:', os.clock()-startTime)
    
    startTime = os.clock()
    for i=1,iterCount do
    a=math.floor(1.1)
    end
    print('math.floor(1.1):', os.clock()-startTime)

     

     

     

    Ага, спасибо. Я вообще не в курсе был про вариант целочисленного деления с двумя слешами в 5.3, заменим в ближайшее время

     

    UPD: Существенной разницы при отрисовке сложных сцен не заметно, но сам факт приятен

    • Нравится 1

  20. Ну это, конечно, относилось не конкретно к этой либе, а к инсталлятору MineOS в целом - ребята ставили, а оказывалось, что либа сериализации затиралась. Я, как говорил, уверен, что это не было сделано специально, но иногда можно не заметить.

     

    А, тогда понятно. В майноси чутка иная сериализация - вот и крашится, угу.11

     

    Печально, что с репозиторием такое мнение. Посмотрю, как можно обойти установку одних и тех же файлов в миллионах мест. Либы заменить нечем, особенно буферизацию.

     

    Когда-нибудь, когда горы полетят по ветру, как опавшие листья... возможно, появится мыслишка с этим поколупаться. Но не сейчас точно. Чертовы Вексатосы!

    • Нравится 1
×
×
  • Создать...