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

Профилируем программы под OC

Fingercomp

952 просмотра

В прошлый раз я патчил OpenComputers, чтобы пробрасывать нативную либу debug. Пойдём дальше.

  1. Добавим нативных либ package и os.
  2. Прокинем дефолтное окружение внутрь песочницы.
  3. Пропатчим мод, чтобы можно было загружать си-модули.
  4. Загрузим профилятор и посмотрим, что из этого вышло.

 

На винде ничего не заработает. Гарантирую. Если надо профилировать, ставьте нормальные оси или мучайтесь.

 

0. Сырцы мода

Так как мы будем патчить мод, надо сначала подготовить исходники.

$ git clone https://github.com/MightyPirates/OpenComputers.git
$ cd OpenComputers
$ git checkout master-MC1.12
$ ./gradlew setupDecompWorkspace

На третьей строке версию выбираем по вкусу и выпекаем всё необходимое для компиляции.

 

1. Нативные либы

Здесь всё просто. Открываем файл src/main/scala/li/cil/oc/server/machine/luac/LuaStateFactory.scala. Творим следующее:

K01QBof.png

Вуаля. Теперь в machine.lua будут глобальные переменные package и _os. Отмечу отдельно, что меняем мы только архитектуру Lua 5.3.

Уже на этом этапе у нас может сломаться персистентность. Это не страшно: она и должна сломаться.

 

2. Прокидываем окружение

Поступаем аналогично тому, что делали в прошлой записи: меняем src/main/resources/assets/opencomputers/lua/machine.lua:

IGx0c8D.png

Внутри песочницы в глобальной переменной env запечатлено будет всё окружение machine.lua.

 

3. C-модули

Уже сейчас можно загрузить OpenOS и прописать env.require("libname"). Проблема в том, что C-модули так подключить не получится. Связано это с особенностью Lua. Абстрактно задача заключается в том, чтобы загрузить библиотку Lua с dlopen(..., RTLD_GLOBAL). System.loadLibrary в жаве флаг этот упускает по очевидным причинам, а нам он нужен. Значит, пришло время костылей.

 

3.1. Подключаем JNA: build.gradle

n8g62pu.png

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

 

3.2. Патчим ещё раз src/main/scala/li/cil/oc/server/machine/luac/LuaStateFactory.scala

yHjJStm.png

Во-первых, подключаем хэшмапу. Потребуется.

Во-вторых, импортируем JNA. Вернее, его часть.

В-третьих, патчим код, чтобы он загружал Lua 5.3 через JNA. Магическая константа 0x101 — это значение RTLD_LAZY | RTLD_GLOBAL на моей системе. На фряхе, маке оно может отличаться.

 

На этом этапе Lua 5.2 не будет работать. Включаться будет только Lua 5.3 из-за конфликта имён.

Кроме того, JNA — это, вообще, огромная либа. Ради одной функции её подключать — это оверкилл. Но я в тонкостях JVM и JNI не силён. Как уже сказал, разбираться мне лень.

 

3.3. Компилируем

$ ./gradlew assemble

Выхлоп в build/libs. Берём жарник без суффиксов вроде -javadoc, -api, -sources.

 

4. Настраиваем профилятор

Профилятор я написал сам на Rust. Вот ссылка: https://github.com/Fingercomp/lprofile-rs

Очевидно, нам надо его скомпилировать.

 

4.1. Компилируем профилятор

Ставим cargo (мультитул раста такой) любым удобным способом. Собираем:

$ cd ..
$ git clone --recurse-submodules https://github.com/Fingercomp/lprofile-rs.git
$ cd lprofile-rs
$ cargo build --release

В target/release будет лежать liblprofile.so. Тырим его.

 

4.2. Определяем pwd

Кидаем пропатченный OC в моды и запускаем игру. Пишем в опенкомпе env._os.getenv("PWD"), чтобы определить текущую директорию. Кидаем либу-профилятор в неё.

 

4.3. Профилируем

Наконец, можно заняться мясом.

local profiler = env.require("lprofile").Profiler()

local result = profiler(function()
  local v = 0

  for i = 1, 10e6, 1 do
    v = v + i
  end
end)

table.sort(result, function(lhs, rhs)
  return lhs.totalTime < rhs.totalTime
end)

print("Name", "# of calls", "Total time", "Total time, excluding inner calls")

for _, v in ipairs(result) do
  print(("%s\t%d\t%.6f s\t%.6f s"):format(v.name, v.calls, v.totalTime, v.totalSelfTime))
end

print("total time:", result.totalTime)

HFVtxc2.png

 

5. Зачем

Мы получили наполовину сломанную версию OpenComputers: без Lua 5.3, без персистентности. Зато можем профилировать программы.

 

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

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


3 комментария


Рекомендуемые комментарии

Цитата

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

Спасибо за описание именно такой норкомагии. Мне было очень интересно читать. И заняться чем-то подобным в перспективе я тоже планировал.

 

И, хвала небесам, у меня есть нормальная ось.

 

Вот здесь не понял:

Цитата

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

Что такое ханк? Хак?

Поделиться комментарием


Ссылка на комментарий
35 минут назад, eu_tomat сказал:

Что такое ханк? Хак?

Не знал, как по-русски понятно написать, оставил транскрипцией — hunk, часть диффа.

Поделиться комментарием


Ссылка на комментарий
19 минут назад, Fingercomp сказал:

Не знал, как по-русски понятно написать, оставил транскрипцией — hunk, часть диффа.

Ясно. Похоже, как и с чанком, который мы уже привыкли транслитерировать. Хотя, и то и другое означает кусок, часть, фрагмент.

Поделиться комментарием


Ссылка на комментарий
Гость
Добавить комментарий...

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

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

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

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

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

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