-
Notifications
You must be signed in to change notification settings - Fork 494
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
add sapp_input_wait() to fix high cpu usage while idle #640
base: master
Are you sure you want to change the base?
Conversation
a sokol_app produces constant cpu load because it keeps repainting the screen whether something has changed or not. we can fix this easily by simply calling XNextEvent(), which blocks if there are no pending events. this causes the app to idle until the user interacts with the program. a new function sapp_input_wait() was added to control this behaviour, which causes the sokol app to block until the next input is received. afterwards, the input_wait flag is cleared and the user has to set it again if so desired.
Related: #301 |
interesting. the suggested solution there (just skipping draw) doesn't fix the problem entirely - the app will still be executing stuff over and over while "polling" for input. i tried this approach before and it resulted in roughly 4% constant cpu usage even without redrawing and some usleep()s built in. |
Hmm, I could've sworn I had written a detailed reply to this PR already, oh well... ;) The problem with the PR is that it doesn't fit into the frame-callback-based sokol_app.h backends (any backend which is not Windows or X11 basically), but I think that's already discussed in the issue thread linked by @Manuzor |
maybe you're misunderstanding, the function added doesn't block itself, it merely sets a flag which causes the event/frame dispatch loop in the header to block upon next execution. a typical use case would look like: // timestamp in microsecs of last user activity
static uint64_t user_activity = -1ULL;
static uint64_t get_ts(void) {
struct timespec nowtime;
clock_gettime(CLOCK_REALTIME, &nowtime);
return nowtime.tv_sec * 1000000ul + nowtime.tv_nsec/1000000ul;
}
static int need_render(void) {
if (user_activity == -1ULL || !sim_get_paused()) return 1;
uint64_t ts = get_ts();
return (ts - user_activity < 200);
}
static void app_frame(void) {
if (!need_render()) {
sapp_input_wait();
return;
}
gfx_new_frame(sapp_widthf(), sapp_heightf());
ui_frame();
....
}
static void app_input(const sapp_event* ev) {
input_handle_event(ev);
user_activity = get_ts();
}
sapp_desc sokol_main(int argc, char* argv[]) {
sargs_setup(&(sargs_desc){ .argc = argc, .argv = argv });
return (sapp_desc){
.init_cb = app_init,
.frame_cb = app_frame,
.event_cb = app_input,
...
} (from https://github.com/rofl0r/visualz80/blob/nofips/src/main.c ) |
this removes cpu load when idle, and reduces it when moving the mouse around, etc. the implementation reflects the landscape of the magical world of linux; xlib is not thread-safe so we can't push a dummy event, and select can mark an fd ready even though io would block. based on ideas from floooh/sokol#640
a sokol_app produces constant cpu load because it keeps repainting
the screen whether something has changed or not. we can fix this
easily by simply calling XNextEvent(), which blocks if there are no
pending events. this causes the app to idle until the user interacts
with the program.
a new function sapp_input_wait() was added to control this behaviour,
which causes the sokol app to block until the next input is received.
afterwards, the input_wait flag is cleared and the user has to set
it again if so desired.
this PR currently only addresses linux, and uses a "dirty" goto, which can be avoided by factoring out the XNextEvent block into a separate function.