Преглед изворни кода

fix(touch): eliminate CPU busy-wait in touch monitor thread

The touch monitor thread was using a 10ms polling loop (100 iterations/sec)
while waiting for touch input, causing 100% CPU usage when screen was off.

Fixed by:
- Using select() with 1-second timeout instead of busy polling
- Removed time.sleep() calls that created artificial delays
- Changed evtest subprocess to binary mode for select() compatibility

This should reduce idle CPU from 100%+ to under 10% when screen is off.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
tuanchris пре 1 недеља
родитељ
комит
c2b1851958
1 измењених фајлова са 34 додато и 31 уклоњено
  1. 34 31
      dune-weaver-touch/backend.py

+ 34 - 31
dune-weaver-touch/backend.py

@@ -1236,40 +1236,45 @@ class Backend(QObject):
                 if evtest_available:
                 if evtest_available:
                     # Use evtest which is more sensitive to single touches
                     # Use evtest which is more sensitive to single touches
                     print("👆 Using evtest for touch detection")
                     print("👆 Using evtest for touch detection")
-                    process = subprocess.Popen(['sudo', 'evtest', touch_device], 
-                                             stdout=subprocess.PIPE, 
+                    process = subprocess.Popen(['sudo', 'evtest', touch_device],
+                                             stdout=subprocess.PIPE,
                                              stderr=subprocess.DEVNULL,
                                              stderr=subprocess.DEVNULL,
-                                             text=True)
-                    
-                    # Wait for any event line
+                                             text=False)  # Binary mode for select()
+
+                    # Use select() with timeout for CPU-efficient blocking
+                    import select
                     while not self._screen_on:
                     while not self._screen_on:
                         try:
                         try:
-                            line = process.stdout.readline()
-                            if line and 'Event:' in line:
-                                print("👆 Touch detected via evtest - waking screen")
-                                process.terminate()
-                                self._turn_screen_on()
-                                self._reset_activity_timer()
-                                break
-                        except:
-                            pass
-                        
+                            # Block up to 1 second waiting for input (CPU efficient)
+                            ready, _, _ = select.select([process.stdout], [], [], 1.0)
+                            if ready:
+                                # Data available - read a chunk
+                                data = process.stdout.read(1024)
+                                if data and b'Event:' in data:
+                                    print("👆 Touch detected via evtest - waking screen")
+                                    process.terminate()
+                                    self._turn_screen_on()
+                                    self._reset_activity_timer()
+                                    break
+                        except Exception as e:
+                            print(f"👆 Error in evtest select: {e}")
+                            break
+
                         if process.poll() is not None:
                         if process.poll() is not None:
                             break
                             break
-                        time.sleep(0.01)  # Small sleep to prevent CPU spinning
                 else:
                 else:
-                    # Fallback: Use cat with single byte read (more responsive)
+                    # Fallback: Use cat with blocking read via select
                     print("👆 Using cat for touch detection")
                     print("👆 Using cat for touch detection")
-                    process = subprocess.Popen(['sudo', 'cat', touch_device], 
-                                             stdout=subprocess.PIPE, 
+                    process = subprocess.Popen(['sudo', 'cat', touch_device],
+                                             stdout=subprocess.PIPE,
                                              stderr=subprocess.DEVNULL)
                                              stderr=subprocess.DEVNULL)
-                    
+
                     # Wait for any data (even 1 byte indicates touch)
                     # Wait for any data (even 1 byte indicates touch)
+                    import select
                     while not self._screen_on:
                     while not self._screen_on:
                         try:
                         try:
-                            # Non-blocking check for data
-                            import select
-                            ready, _, _ = select.select([process.stdout], [], [], 0.1)
+                            # Block up to 1 second waiting for data (CPU efficient)
+                            ready, _, _ = select.select([process.stdout], [], [], 1.0)
                             if ready:
                             if ready:
                                 data = process.stdout.read(1)  # Read just 1 byte
                                 data = process.stdout.read(1)  # Read just 1 byte
                                 if data:
                                 if data:
@@ -1278,15 +1283,13 @@ class Backend(QObject):
                                     self._turn_screen_on()
                                     self._turn_screen_on()
                                     self._reset_activity_timer()
                                     self._reset_activity_timer()
                                     break
                                     break
-                        except:
-                            pass
-                        
-                        # Check if screen was turned on by other means
-                        if self._screen_on:
-                            process.terminate()
+                        except Exception as e:
+                            print(f"👆 Error in cat select: {e}")
+                            break
+
+                        # Check if process died
+                        if process.poll() is not None:
                             break
                             break
-                        
-                        time.sleep(0.1)
                 
                 
         except Exception as e:
         except Exception as e:
             print(f"❌ Error monitoring touch input: {e}")
             print(f"❌ Error monitoring touch input: {e}")