Minimize CPU/energy usage

We received a report of Tux Paint generating too much heat on a MacBook
Pro (15-inch, 2017 running macOS Mojave 10.14.6).  The bug report
included a screenshot of Activity Monitor's Energy Tab showing Tux Paint
having an Enegy Impact of "23.4" and Avg Energy Impact of "3.94".

Although we weren't able to reproduce the same conditions exactly, we
did observe Tux Paint having an Energy Impact level of around ~15 even
when idle on both macOS Yosemite 10.10.5 and Big Sur 11.1.  Energy
Impact leve of ~25 when in use was not uncommon, and spiked to ~55.  The
MacBook Air used for testing (11-inch, Early 2014) did not become hot
"to the touch" as was originally reported, but it did become noticibly
warm.

An investigation found the cause to be in two places:

1. Tux Paint's main loop runs fairly tightly, yielding only a minimum
   time slice to the kernel after each iteration using SDL_Delay(1)
   (1 millisecond).  This has been increasd to 10 millisecond to give
   more slice back to the kernel.  Increasing the 1ms yield to 10ms
   should be only minimally noticible as Tux Paint is primarily a human
   interaction software and human eyes perceive responses < ~100ms as
   immediate, giving us over 90ms to accomplish what we need to after
   each iteration as opposed to the previous 99ms.

2. Enabling SDL's timer subsystem (SDL_INIT_TIMER), even when not used
   actively, has a high impact on the energy impact.  Some testing
   showed the timer subsystem, though supposedly a part of SDL_Delay() and
   SDL_GetTicks(), is not required to be enabled to use those functions.
   It does require to be enabled, however, to use SDL_AddTimer() which
   is only used in Tux Paint when scrolling.  Tux Paint therefore has
   been modified to enable the timer subsystem only when scrolling
   starts and disable it when not scrolling.

The solution to #2 is not an ideal approach but it did provide a quick
solution to the user having the problem.  Issue #2 should get resolved
naturally when we upgrade to SDL2 where the timer subsystem does not
appear to have the energy impact issue.
This commit is contained in:
Mark Kim 2021-01-16 20:31:29 -05:00
parent c929224ae5
commit 7727b995c5

View file

@ -4012,18 +4012,25 @@ static void mainloop(void)
if (!scrolling && event.type == SDL_MOUSEBUTTONDOWN)
{
/* printf("Starting scrolling\n"); */
DEBUG_PRINTF("Starting scrolling\n");
memcpy(&scrolltimer_event, &event, sizeof(SDL_Event));
scrolltimer_event.type = TP_SDL_MOUSEBUTTONSCROLL;
scrolling = 1;
/*
* We enable the timer subsystem only when needed (e.g., to use SDL_AddTimer() needed
* for scrolling) then disable it immediately after (e.g., after the timer has fired or
* after SDL_RemoveTimer()) because enabling the timer subsystem in SDL1 has a high
* energy impact on the Mac.
*/
scrolling = 1;
SDL_InitSubSystem(SDL_INIT_TIMER);
scrolltimer =
SDL_AddTimer(REPEAT_SPEED, scrolltimer_callback, (void *)&scrolltimer_event);
}
else
{
/* printf("Continuing scrolling\n"); */
DEBUG_PRINTF("Continuing scrolling\n");
scrolltimer =
SDL_AddTimer(REPEAT_SPEED / 3, scrolltimer_callback, (void *)&scrolltimer_event);
}
@ -4039,6 +4046,7 @@ static void mainloop(void)
scrolltimer = NULL;
}
scrolling = 0;
SDL_QuitSubSystem(SDL_INIT_TIMER);
}
}
}
@ -4930,6 +4938,7 @@ static void mainloop(void)
scrolltimer = NULL;
}
scrolling = 0;
SDL_QuitSubSystem(SDL_INIT_TIMER);
/* printf("Killing scrolling\n"); */
}
@ -5588,7 +5597,7 @@ static void mainloop(void)
handle_motioners(oldpos_x, oldpos_y, motioner, hatmotioner, old_hat_ticks, val_x, val_y, valhat_x, valhat_y);
SDL_Delay(1);
SDL_Delay(10);
}
while (!done);
}
@ -17242,13 +17251,13 @@ static Uint32 scrolltimer_callback(Uint32 interval, void *param)
/* printf("scrolltimer_callback(%d) -- ", interval); */
if (scrolling)
{
/* printf("(Still scrolling)\n"); */
DEBUG_PRINTF("(Still scrolling)\n");
SDL_PushEvent((SDL_Event *) param);
return interval;
}
else
{
/* printf("(all done)\n"); */
DEBUG_PRINTF("(all done scrolling)\n");
return 0;
}
}
@ -23865,7 +23874,7 @@ static void setup(void)
if (joystick_dev != -1)
do_lock_file();
init_flags = SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK;
init_flags = SDL_INIT_VIDEO | SDL_INIT_JOYSTICK;
if (use_sound)
init_flags |= SDL_INIT_AUDIO;
if (!fullscreen)