Skip to content

Conversation

@RandomShaper
Copy link
Member

@RandomShaper RandomShaper commented Oct 21, 2024

Using the yield primitive lets the OS know our intent better than a microwait. This may improve energy efficiency and/or performance.


2024-10-31:

@lyuma's comment about the specific cases made me realize we don't even need to discuss how to implement a yield mechanism, since there's no real need for that.

So, I've updated the PR addressing each case of delay_usec(1) in loops:

  • EditorFileSystem: It was used to poll for the status of the batched import. I've overhauled it so a semaphore controls it instead.
  • EditogLog: I've added a non-polling sync mechanism to RichTextLabel. (By the way, RichTextLabel threading warrants further threading improvements, but that's out of the scope of this PR.)
  • EditorNode::immediate_confirmation_dialog(), EditorFileSystemImportFormatSupportQueryBlend: They are already using main loop iterations, so pacing is implicit.
  • HTTPRequest: In threaded mode, it uses blocking sockets, so the loop isn't really going to run freely. Therefore, I've just removed the relevant call. (Is blocking not supported somewhere?)

@RandomShaper RandomShaper added enhancement topic:core performance cherrypick:4.3 Considered for cherry-picking into a future 4.3.x release labels Oct 21, 2024
@RandomShaper RandomShaper added this to the 4.4 milestone Oct 21, 2024
@RandomShaper RandomShaper requested review from a team as code owners October 21, 2024 13:38
@mrsaturnsan
Copy link
Contributor

mrsaturnsan commented Oct 29, 2024

Yield has really poor performance on macOS. The function gets compiled down to sched_yield, which can yield the process to other processes running on the system. Lack of SIMT also means you can't yield work to other threads.

@RandomShaper RandomShaper requested review from a team as code owners October 30, 2024 16:31
@RandomShaper RandomShaper force-pushed the thread_yield branch 2 times, most recently from 5c16dcb to 329e0f5 Compare October 30, 2024 16:45
@RandomShaper
Copy link
Member Author

I've added a special implementation for Apple platforms.

@mrsaturnsan
Copy link
Contributor

mrsaturnsan commented Oct 30, 2024

Thanks for looking into making changes.

Unfortunately, pthread_yield_np also messed with thread priorities :(

There's not really a good option, but you're better off spinning and burning cycles rather than yielding. Ideally you could use os_unfair_lock to let the scheduler know what thread another thread is waiting on.

@lyuma
Copy link
Contributor

lyuma commented Oct 30, 2024

EditorNode::immediate_confirmation_dialog
editor/editor_log.cpp
EditorFileSystemImportFormatSupportQueryBlend
HTTPRequest::_thread_func
static_test_daemon

I don't think busy waiting is needed or even appropriate in any of these cases (except maybe editor_log if it's invoked by multiple threads).

May I ask why this code isn't using a semaphore or condition variable or similar mechanism?

@RandomShaper RandomShaper changed the title Use thread yield primitive for busy waits Rationalize busy waits Oct 31, 2024
@RandomShaper RandomShaper requested a review from a team as a code owner October 31, 2024 10:09
@RandomShaper RandomShaper requested a review from Faless October 31, 2024 10:09
@RandomShaper
Copy link
Member Author

@mrsaturnsan, good point. I was misinformed that pthread_yield_np() was better on MacOS.

@lyuma, you'be brought the greatest sanity here. Please check the updated description.

Copy link
Member

@clayjohn clayjohn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code and the approach look good to me, but I am not an expert in this area so TIWAGOS

@Repiteo Repiteo requested review from lyuma and removed request for a team November 6, 2024 16:08
@Calinou
Copy link
Member

Calinou commented Nov 6, 2024

cc @adamscott regarding HTTPRequest in threaded mode. Will this be an issue on the web platform?

@fire fire requested a review from adamscott November 7, 2024 17:26
@adamscott
Copy link
Member

adamscott commented Nov 7, 2024

I got this error warning while running a threaded HTTPRequest on the Web platform.

WARNING: HTTPClientWeb polled multiple times in one frame, but request cannot progress more than once per frame on the Web platform.
overrideMethod @ hook.js:608
onPrintError @ godot.editor.js:15281
put_char @ godot.editor.js:1669
write @ godot.editor.js:1618
write @ godot.editor.js:3476
doWritev @ godot.editor.js:9118
_fd_write @ godot.editor.js:9136
__emscripten_receive_on_main_thread_js @ godot.editor.js:6214
$run_js_func @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x3748754
$call_then_finish_task @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x3748655
$call_with_ctx @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x3748588
$em_task_queue_execute @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x3747d5c
$receive_notification @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x374804c
$em_task_queue_execute @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x3747d5c
$_emscripten_check_mailbox @ godot.web.editor.dev.wasm32.wasm-9a60df2e:0x3750d03
callUserCallback @ godot.editor.js:5748
checkMailbox @ godot.editor.js:5780
Promise.then
__emscripten_thread_mailbox_await @ godot.editor.js:5762
checkMailbox @ godot.editor.js:5779
Promise.then
__emscripten_thread_mailbox_await @ godot.editor.js:5762
checkMailbox @ godot.editor.js:5779
Promise.then
__emscripten_thread_mailbox_await @ godot.editor.js:5762
checkMailbox @ godot.editor.js:5779
...
godot.editor.js:15281    at: poll (platform/web/http_client_web.cpp:240)

Either:

  • we shush the warning on the Web (kinda bad)
  • we check the capabilities of the platform to poll http requests before (relatively clean)
  • we just add a #ifdef WEB_ENABLED macro to force waiting (ugly as heck)

cc. @Faless

@RandomShaper
Copy link
Member Author

Wow, that check comes from seven years ago!: #16781.

Back them, HTTP requests on the web were backed by XMLHttpRequest instead of fetch(). I wonder if the limitation still holds. In any case, I wonder what's the harm of multiple pollings on the same frame. Was it to ensure HTTPRequest is implemented correctly?

@RandomShaper
Copy link
Member Author

CC @Faless

@adamscott
Copy link
Member

I'm gonna check this out.

@adamscott
Copy link
Member

cc @adamscott regarding HTTPRequest in threaded mode. Will this be an issue on the web platform?

Just realized that HTTPRequest in threaded mode isn't compatible with the Web platform at all (we cannot set_blocking_mode(true), as threaded mode does). So this is a non-issue (?).

@RandomShaper
Copy link
Member Author

Since we're too slow in coming up with a consensus on the HTTPRequest change, I'm leaving it untouched so this PR can be merged. HTTPRequest can be discussed and changed separately.

@akien-mga
Copy link
Member

@lyuma Please take another look if you can, so we can get this merged.

@akien-mga akien-mga merged commit 8a743f2 into godotengine:master Dec 20, 2024
20 checks passed
@akien-mga
Copy link
Member

Thanks!

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

Labels

cherrypick:4.3 Considered for cherry-picking into a future 4.3.x release enhancement performance topic:core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants