Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Hashlink profiler does not work with OpenFL #2685

Open
LostBranch5502 opened this issue Feb 2, 2024 · 5 comments
Open

The Hashlink profiler does not work with OpenFL #2685

LostBranch5502 opened this issue Feb 2, 2024 · 5 comments

Comments

@LostBranch5502
Copy link

LostBranch5502 commented Feb 2, 2024

Describe the bug

The Hashlink profiler can be used to profile HL bytecode applications. It can be started by running Hashlink with the --profile switch. However, trying to run the profiler crashes OpenFL applications in haxe.io.Input.readLine.

The profiler is supposed to run in its own thread and not affect the rest of the program it samples, so it's not clear why the program runs differently (and fails) with the profiler enabled. The profiler works without issues when using it with Heaps programs with the same Hashlink, OS etc. versions.

To Reproduce

Steps to reproduce the behavior:

  1. Make e.g. a BunnyMark sample: openfl create BunnyMark
  2. Compile and run the sample with Hashlink: openfl test hl -debug
  3. Go to the directory with the compiled application cd Export/hl/bin
  4. Run with Hashlink (works): ./Bunnymark
  5. Run with Hashlink with the profiler (fails): ./Bunnymark --profile 1000

The last example starts but immediately fails with the following output:

Writing profiling data...
224 profile samples saved
Uncaught exception: Eof
Called from haxe.io.Input.readLine(.../haxe-4.3.3-linux64/haxe_20231117191750_de28889/std/haxe/io/Input.hx:189)
Called from openfl.text._internal.$TextEngine.getDefaultFont(openfl/text/_internal/TextEngine.hx:384)
Called from openfl.text._internal.$TextEngine.getFontInstance(openfl/text/_internal/TextEngine.hx:535)
Called from openfl.text._internal.TextEngine.getLayoutGroups(openfl/text/_internal/TextEngine.hx:1344)
Called from openfl.text._internal.TextEngine.update(openfl/text/_internal/TextEngine.hx:1847)
Called from openfl.text.TextField.__updateLayout(openfl/text/TextField.hx:2241)
Called from openfl.display._internal.$CairoTextField.render(openfl/display/_internal/CairoTextField.hx:45)
Called from openfl.display._internal.$Context3DTextField.render(openfl/display/_internal/Context3DTextField.hx:24)
Called from openfl.display._internal.$Context3DTextField.renderDrawable(openfl/display/_internal/Context3DTextField.hx:39)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:858)
Called from openfl.display._internal.$Context3DDisplayObjectContainer.renderDrawable(openfl/display/_internal/Context3DDisplayObjectContainer.hx:30)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:850)
Called from openfl.display._internal.$Context3DDisplayObjectContainer.renderDrawable(openfl/display/_internal/Context3DDisplayObjectContainer.hx:30)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:850)
Called from openfl.display._internal.$Context3DDisplayObjectContainer.renderDrawable(openfl/display/_internal/Context3DDisplayObjectContainer.hx:30)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:850)
Called from openfl.display.OpenGLRenderer.__render(openfl/display/OpenGLRenderer.hx:764)
Called from openfl.display.Stage.__onLimeRender(openfl/display/Stage.hx:2111)
Called from lime.app._Event_lime_graphics_RenderContext_Void.dispatch(lime/_internal/macros/EventMacro.hx:91)
Called from lime._internal.backend.native.NativeApplication.handleRenderEvent(lime/_internal/backend/native/NativeApplication.hx:371)
Called from lime._internal.backend.native.NativeApplication.exec(lime/_internal/backend/native/NativeApplication.hx:146)
Called from lime.app.Application.exec(lime/app/Application.hx:150)
Called from $ApplicationMain.create(ApplicationMain.hx:135)
Called from $ApplicationMain.main(ApplicationMain.hx:26)
Called from .init(?:1)

The output about "writing profiling data" is probably not related to the exception. Rather, the exception happens somewhere else in the program, and while closing, the Hashlink virtual machine first writes out the profiling data (like it always does when a profiled program closes) and then shows the exception that happened somewhere else.

OpenFL Targets

The problem is related to the Hashlink bytecode target. The following program versions were used:

  • Haxe: 4.3.3
  • Hashlink: 1.13.0
  • OpenFL: 9.2.2-L2fxn5
  • Lime: 8.0.2
  • OS: Ubuntu Linux 20.04.6 LTS (64-bit)

Additional context

1) How to define a custom Hashlink version for use with OpenFL?

A tangentially related issue is that the Hashlink version bundled with OpenFL can sometimes be out of date. For example, the profiler requires a newer Hashlink version than the one bundled with OpenFL. To use a more recent Hashlink version with OpenFL I have copied the newer Hashlink files over the ones in the Lime haxelib directory by replacing the files at e.g. haxelib/lime/8,0,2/templates/bin/hl/Linux64.

This appears to work fine but feels like a bit of a hack. Is there any official way to point OpenFL/Lime to use a user-defined Hashlink install instead of the bundled one?

2) How to pass Hashlink command line parameters to "openfl test"?

When compiling and running an OpenFL program with Hashlink, it is possible to pass arguments to the program with openfl test -args -arg value. However, these arguments are passed to the program itself, but the Hashlink virtual machine can also receive its own arguments, such as the --profile option.

Is there any way to pass Hashlink command line arguments via either the OpenFL command line interface or the OpenFL project.xml file?

3) How to start the Hashlink profiler without the command line argument?

This part is not really an OpenFL question, but I thought I would put it here in case someone with more experience with the Hashlink profiler can help. The profiler can be started with the --profile command line option, but it should also be possible to start it from within the program by calling hl.Profile.event(-7). However, this doesn't seem to have any effect.

@joshtynjala
Copy link
Member

  1. How to define a custom Hashlink version for use with OpenFL?

Instructions here: https://lime.openfl.org/docs/advanced-setup/hashlink/

@LostBranch5502
Copy link
Author

Thank you for the quick reply, and sorry for missing that information in the documentation!

I now setup my local Hashlink version using lime setup hashlink, and I also re-installed the whole Lime haxelib, just in case I had broken something when manually replacing the Hashlink files there. Doing that, I also noticed that my OpenFL/Lime versions were not the latest ones, so I updated them to OpenFL 9.3.2 and Lime 8.1.1.

I wanted to test the profiler also with the bundled Hashlink, but I can't seem to be able to switch back to it. The problem is that when running lime setup hashlink I can point it to my local install, but I cannot switch back. The command says to "Leave empty to use lime's default version", but if I just press enter at the prompt, the previously entered custom path remains unchanged. If I add a space and press enter, that empty path apparently becomes the HL_PATH, and then the system cannot find the bundled interpreter.

@joshtynjala
Copy link
Member

Try running lime config remove HL_PATH in a terminal. That should restore the bundled version.

@LostBranch5502
Copy link
Author

Thanks, that works for resetting the Hashlink path!

I wanted to test the profiler with both the bundled and external Hashlink, but I first ran into some issues of the generated BunnyMark executable (the renamed Hashlink interpreter) remaining the wrong Hashlink version despite setting HL_PATH. It seems that the build tool doesn't recopy the interpreter when HL_PATH changes if the interpreter has already been copied to the output directory, but deleting the Export subdirectory before re-running the openfl build tool solved this.

I tried both with and without the -debug mode, but this didn't change the outcome. Testing with OpenFL/Lime 9.3.2/8.1.1 and the latest bundled Hashlink (version 1.12.0) also results in a crash when running ./BunnyMark --profile 1000, although the error is slightly different, without the line about haxe.io.Input.readLine:

Writing profiling data...
273 profile samples saved
Uncaught exception: Eof
Called from openfl.text._internal.$TextEngine.getDefaultFont(openfl/text/_internal/TextEngine.hx:388)
Called from openfl.text._internal.$TextEngine.getFontInstance(openfl/text/_internal/TextEngine.hx:539)
Called from openfl.text._internal.TextEngine.getLayoutGroups(openfl/text/_internal/TextEngine.hx:1356)
Called from openfl.text._internal.TextEngine.update(openfl/text/_internal/TextEngine.hx:1859)
Called from openfl.text.TextField.__updateLayout(openfl/text/TextField.hx:2241)
Called from openfl.display._internal.$CairoTextField.render(openfl/display/_internal/CairoTextField.hx:45)
Called from openfl.display._internal.$Context3DTextField.render(openfl/display/_internal/Context3DTextField.hx:24)
Called from openfl.display._internal.$Context3DTextField.renderDrawable(openfl/display/_internal/Context3DTextField.hx:39)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:858)
Called from openfl.display._internal.$Context3DDisplayObjectContainer.renderDrawable(openfl/display/_internal/Context3DDisplayObjectContainer.hx:30)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:850)
Called from openfl.display._internal.$Context3DDisplayObjectContainer.renderDrawable(openfl/display/_internal/Context3DDisplayObjectContainer.hx:30)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:850)
Called from openfl.display._internal.$Context3DDisplayObjectContainer.renderDrawable(openfl/display/_internal/Context3DDisplayObjectContainer.hx:30)
Called from openfl.display.OpenGLRenderer.__renderDrawable(openfl/display/OpenGLRenderer.hx:850)
Called from openfl.display.OpenGLRenderer.__render(openfl/display/OpenGLRenderer.hx:764)
Called from openfl.display.Stage.__render(openfl/display/Stage.hx:2107)
Called from openfl.display.Stage.__onLimeRender(openfl/display/Stage.hx:2188)
Called from lime.app._Event_lime_graphics_RenderContext_Void.dispatch(lime/_internal/macros/EventMacro.hx:91)
Called from lime._internal.backend.native.NativeApplication.handleRenderEvent(lime/_internal/backend/native/NativeApplication.hx:375)
Called from lime._internal.backend.native.NativeApplication.exec(lime/_internal/backend/native/NativeApplication.hx:146)
Called from lime.app.Application.exec(lime/app/Application.hx:150)
Called from openfl.display.Application.exec(openfl/display/Application.hx:130)
Called from $ApplicationMain.create(ApplicationMain.hx:137)
Called from $ApplicationMain.main(ApplicationMain.hx:26)
Called from .init(?:1)

@LostBranch5502
Copy link
Author

Looking more into this, it seems that the issue with the profiler crash is not directly related to OpenFL, it just appears in OpenFL programs when openfl.text._internal.TextEngine uses subprocesses to find the default fonts.

The issue appears to be caused by the Hashlink profiler somehow interacting with sys.io.Process.stdout.readLine and causing an exception there. I opened a new issue about this at the Hashlink repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants