summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-12-06 11:52:26 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-12-06 11:52:26 +0200
commit6a565ea71745aaf4c91a7698bbf56f7d906fcaaa (patch)
treee68ed6140097be20ab51193dfd25ac1a4d1c502d /src
parente43ecd3eb279e117cbce8fd507ecef247938e4ac (diff)
Added build option for sleeping while idle
It appears at least on macOS, SDL is doing a while lot of stuff while waiting for new events. Perhaps because it has some sort of high-frequency input/sensor processing? Not sure. Now Lagrange will idle by polling events every 15 ms and sleeping in between. This reduces CPU time by an order of magnitude on macOS. Need to still test on other platforms.
Diffstat (limited to 'src')
-rw-r--r--src/app.c79
-rw-r--r--src/app.h1
2 files changed, 71 insertions, 9 deletions
diff --git a/src/app.c b/src/app.c
index 1e0a847d..ba7d41d2 100644
--- a/src/app.c
+++ b/src/app.c
@@ -89,6 +89,8 @@ static const char *prefsFileName_App_ = "prefs.cfg";
89static const char *stateFileName_App_ = "state.binary"; 89static const char *stateFileName_App_ = "state.binary";
90static const char *downloadDir_App_ = "~/Downloads"; 90static const char *downloadDir_App_ = "~/Downloads";
91 91
92static const int idleThreshold_App_ = 1000; /* ms */
93
92struct Impl_App { 94struct Impl_App {
93 iCommandLine args; 95 iCommandLine args;
94 iString * execPath; 96 iString * execPath;
@@ -100,7 +102,12 @@ struct Impl_App {
100 iSortedArray tickers; 102 iSortedArray tickers;
101 uint32_t lastTickerTime; 103 uint32_t lastTickerTime;
102 uint32_t elapsedSinceLastTicker; 104 uint32_t elapsedSinceLastTicker;
103 iBool running; 105 iBool isRunning;
106#if defined (LAGRANGE_IDLE_SLEEP)
107 iBool isIdling;
108 uint32_t lastEventTime;
109 int sleepTimer;
110#endif
104 iAtomicInt pendingRefresh; 111 iAtomicInt pendingRefresh;
105 int tabEnum; 112 int tabEnum;
106 iStringList *launchCommands; 113 iStringList *launchCommands;
@@ -320,6 +327,16 @@ static void saveState_App_(const iApp *d) {
320 iRelease(f); 327 iRelease(f);
321} 328}
322 329
330#if defined (LAGRANGE_IDLE_SLEEP)
331static uint32_t checkAsleep_App_(uint32_t interval, void *param) {
332 iApp *d = param;
333 SDL_Event ev = { .type = SDL_USEREVENT };
334 ev.user.code = asleep_UserEventCode;
335 SDL_PushEvent(&ev);
336 return interval;
337}
338#endif
339
323static void init_App_(iApp *d, int argc, char **argv) { 340static void init_App_(iApp *d, int argc, char **argv) {
324 const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_)); 341 const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_));
325 d->isFinishedLaunching = iFalse; 342 d->isFinishedLaunching = iFalse;
@@ -349,7 +366,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
349#endif 366#endif
350 init_Prefs(&d->prefs); 367 init_Prefs(&d->prefs);
351 setCStr_String(&d->prefs.downloadDir, downloadDir_App_); 368 setCStr_String(&d->prefs.downloadDir, downloadDir_App_);
352 d->running = iFalse; 369 d->isRunning = iFalse;
353 d->window = NULL; 370 d->window = NULL;
354 set_Atomic(&d->pendingRefresh, iFalse); 371 set_Atomic(&d->pendingRefresh, iFalse);
355 d->mimehooks = new_MimeHooks(); 372 d->mimehooks = new_MimeHooks();
@@ -358,6 +375,11 @@ static void init_App_(iApp *d, int argc, char **argv) {
358 d->bookmarks = new_Bookmarks(); 375 d->bookmarks = new_Bookmarks();
359 d->tabEnum = 0; /* generates unique IDs for tab pages */ 376 d->tabEnum = 0; /* generates unique IDs for tab pages */
360 setThemePalette_Color(d->prefs.theme); 377 setThemePalette_Color(d->prefs.theme);
378#if defined (LAGRANGE_IDLE_SLEEP)
379 d->isIdling = iFalse;
380 d->lastEventTime = 0;
381 d->sleepTimer = SDL_AddTimer(1000, checkAsleep_App_, d);
382#endif
361#if defined (iPlatformApple) 383#if defined (iPlatformApple)
362 setupApplication_MacOS(); 384 setupApplication_MacOS();
363#endif 385#endif
@@ -484,19 +506,25 @@ const iString *debugInfo_App(void) {
484} 506}
485 507
486iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 508iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
509#if defined (LAGRANGE_IDLE_SLEEP)
510 if (d->isIdling) {
511 return iFalse;
512 }
513#endif
487 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers); 514 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers);
488} 515}
489 516
490void processEvents_App(enum iAppEventMode eventMode) { 517void processEvents_App(enum iAppEventMode eventMode) {
491 iApp *d = &app_; 518 iApp *d = &app_;
492 SDL_Event ev; 519 SDL_Event ev;
520 iBool gotEvents = iFalse;
493 while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode && 521 while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode &&
494 SDL_WaitEvent(&ev)) || 522 SDL_WaitEvent(&ev)) ||
495 ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) && 523 ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) &&
496 SDL_PollEvent(&ev))) { 524 SDL_PollEvent(&ev))) {
497 switch (ev.type) { 525 switch (ev.type) {
498 case SDL_QUIT: 526 case SDL_QUIT:
499 d->running = iFalse; 527 d->isRunning = iFalse;
500 goto backToMainLoop; 528 goto backToMainLoop;
501 case SDL_DROPFILE: { 529 case SDL_DROPFILE: {
502 iBool newTab = iFalse; 530 iBool newTab = iFalse;
@@ -516,6 +544,25 @@ void processEvents_App(enum iAppEventMode eventMode) {
516 break; 544 break;
517 } 545 }
518 default: { 546 default: {
547#if defined (LAGRANGE_IDLE_SLEEP)
548 if (ev.type == SDL_USEREVENT && ev.user.code == asleep_UserEventCode) {
549 if (SDL_GetTicks() - d->lastEventTime > idleThreshold_App_) {
550 if (!d->isIdling) {
551 printf("[App] idling...\n");
552 fflush(stdout);
553 }
554 d->isIdling = iTrue;
555 }
556 continue;
557 }
558 d->lastEventTime = SDL_GetTicks();
559 if (d->isIdling) {
560 printf("[App] ...woke up\n");
561 fflush(stdout);
562 }
563 d->isIdling = iFalse;
564#endif
565 gotEvents = iTrue;
519 iBool wasUsed = processEvent_Window(d->window, &ev); 566 iBool wasUsed = processEvent_Window(d->window, &ev);
520 if (!wasUsed) { 567 if (!wasUsed) {
521 /* There may be a key bindings for this. */ 568 /* There may be a key bindings for this. */
@@ -539,6 +586,14 @@ void processEvents_App(enum iAppEventMode eventMode) {
539 } 586 }
540 } 587 }
541 } 588 }
589#if defined (LAGRANGE_IDLE_SLEEP)
590 if (d->isIdling && !gotEvents) {
591 /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we
592 can't wait too long after the user tries to interact again with the app. In any
593 case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */
594 SDL_Delay(1000 / 60);
595 }
596#endif
542backToMainLoop:; 597backToMainLoop:;
543} 598}
544 599
@@ -586,10 +641,10 @@ static int resizeWatcher_(void *user, SDL_Event *event) {
586 641
587static int run_App_(iApp *d) { 642static int run_App_(iApp *d) {
588 arrange_Widget(findWidget_App("root")); 643 arrange_Widget(findWidget_App("root"));
589 d->running = iTrue; 644 d->isRunning = iTrue;
590 SDL_EventState(SDL_DROPFILE, SDL_ENABLE); /* open files via drag'n'drop */ 645 SDL_EventState(SDL_DROPFILE, SDL_ENABLE); /* open files via drag'n'drop */
591 SDL_AddEventWatch(resizeWatcher_, d); 646 SDL_AddEventWatch(resizeWatcher_, d);
592 while (d->running) { 647 while (d->isRunning) {
593 processEvents_App(waitForNewEvents_AppEventMode); 648 processEvents_App(waitForNewEvents_AppEventMode);
594 runTickers_App_(d); 649 runTickers_App_(d);
595 refresh_App(); 650 refresh_App();
@@ -600,6 +655,9 @@ static int run_App_(iApp *d) {
600 655
601void refresh_App(void) { 656void refresh_App(void) {
602 iApp *d = &app_; 657 iApp *d = &app_;
658#if defined (LAGRANGE_IDLE_SLEEP)
659 if (d->isIdling) return;
660#endif
603 destroyPending_Widget(); 661 destroyPending_Widget();
604 draw_Window(d->window); 662 draw_Window(d->window);
605 set_Atomic(&d->pendingRefresh, iFalse); 663 set_Atomic(&d->pendingRefresh, iFalse);
@@ -657,6 +715,9 @@ int run_App(int argc, char **argv) {
657 715
658void postRefresh_App(void) { 716void postRefresh_App(void) {
659 iApp *d = &app_; 717 iApp *d = &app_;
718#if defined (LAGRANGE_IDLE_SLEEP)
719 d->isIdling = iFalse;
720#endif
660 const iBool wasPending = exchange_Atomic(&d->pendingRefresh, iTrue); 721 const iBool wasPending = exchange_Atomic(&d->pendingRefresh, iTrue);
661 if (!wasPending) { 722 if (!wasPending) {
662 SDL_Event ev; 723 SDL_Event ev;
@@ -1085,12 +1146,12 @@ iBool handleCommand_App(const char *cmd) {
1085 } 1146 }
1086 else if (equal_Command(cmd, "prefs.sideicon.changed")) { 1147 else if (equal_Command(cmd, "prefs.sideicon.changed")) {
1087 d->prefs.sideIcon = arg_Command(cmd) != 0; 1148 d->prefs.sideIcon = arg_Command(cmd) != 0;
1088 refresh_App(); 1149 postRefresh_App();
1089 return iTrue; 1150 return iTrue;
1090 } 1151 }
1091 else if (equal_Command(cmd, "prefs.hoveroutline.changed")) { 1152 else if (equal_Command(cmd, "prefs.hoveroutline.changed")) {
1092 d->prefs.hoverOutline = arg_Command(cmd) != 0; 1153 d->prefs.hoverOutline = arg_Command(cmd) != 0;
1093 refresh_App(); 1154 postRefresh_App();
1094 return iTrue; 1155 return iTrue;
1095 } 1156 }
1096 else if (equal_Command(cmd, "saturation.set")) { 1157 else if (equal_Command(cmd, "saturation.set")) {
@@ -1373,13 +1434,13 @@ iBool handleCommand_App(const char *cmd) {
1373 } 1434 }
1374 else if (equal_Command(cmd, "feeds.update.started")) { 1435 else if (equal_Command(cmd, "feeds.update.started")) {
1375 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iFalse); 1436 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iFalse);
1376 refresh_App(); 1437 postRefresh_App();
1377 return iFalse; 1438 return iFalse;
1378 } 1439 }
1379 else if (equal_Command(cmd, "feeds.update.finished")) { 1440 else if (equal_Command(cmd, "feeds.update.finished")) {
1380 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iTrue); 1441 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iTrue);
1381 refreshFinished_Feeds(); 1442 refreshFinished_Feeds();
1382 refresh_App(); 1443 postRefresh_App();
1383 return iFalse; 1444 return iFalse;
1384 } 1445 }
1385 else if (equal_Command(cmd, "visited.changed")) { 1446 else if (equal_Command(cmd, "visited.changed")) {
diff --git a/src/app.h b/src/app.h
index bc086dfe..743484a5 100644
--- a/src/app.h
+++ b/src/app.h
@@ -46,6 +46,7 @@ enum iAppEventMode {
46enum iUserEventCode { 46enum iUserEventCode {
47 command_UserEventCode = 1, 47 command_UserEventCode = 1,
48 refresh_UserEventCode = 2, 48 refresh_UserEventCode = 2,
49 asleep_UserEventCode = 3,
49}; 50};
50 51
51const iString *execPath_App (void); 52const iString *execPath_App (void);