В прошлый раз я патчил OpenComputers, чтобы пробрасывать нативную либу debug. Пойдём дальше.
- Добавим нативных либ package и os.
- Прокинем дефолтное окружение внутрь песочницы.
- Пропатчим мод, чтобы можно было загружать си-модули.
- Загрузим профилятор и посмотрим, что из этого вышло.
На винде ничего не заработает. Гарантирую. Если надо профилировать, ставьте нормальные оси или мучайтесь.
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. Творим следующее:
Вуаля. Теперь в machine.lua будут глобальные переменные package и _os. Отмечу отдельно, что меняем мы только архитектуру Lua 5.3.
Уже на этом этапе у нас может сломаться персистентность. Это не страшно: она и должна сломаться.
2. Прокидываем окружение
Поступаем аналогично тому, что делали в прошлой записи: меняем src/main/resources/assets/opencomputers/lua/machine.lua:
Внутри песочницы в глобальной переменной env запечатлено будет всё окружение machine.lua.
3. C-модули
Уже сейчас можно загрузить OpenOS и прописать env.require("libname"). Проблема в том, что C-модули так подключить не получится. Связано это с особенностью Lua. Абстрактно задача заключается в том, чтобы загрузить библиотку Lua с dlopen(..., RTLD_GLOBAL). System.loadLibrary в жаве флаг этот упускает по очевидным причинам, а нам он нужен. Значит, пришло время костылей.
3.1. Подключаем JNA: build.gradle
Первый ханк нужен, чтобы можно было потом компилировать мод. Почему-то у курсов мавен не работает, а разбираться мне лень.
3.2. Патчим ещё раз src/main/scala/li/cil/oc/server/machine/luac/LuaStateFactory.scala
Во-первых, подключаем хэшмапу. Потребуется.
Во-вторых, импортируем 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)
5. Зачем
Мы получили наполовину сломанную версию OpenComputers: без Lua 5.3, без персистентности. Зато можем профилировать программы.
Этот пост я написал, чтобы не забыть самому. Сомневаюсь, что кому-то интересно заниматься такой норкомагией.
- 5
- 2
3 комментария
Рекомендуемые комментарии