Skip to content

perf: eliminate redundant copies, fix memory leaks, use platform abstraction#50

Merged
AreteDriver merged 2 commits intomainfrom
claude/performance-code-review-omZxi
Feb 26, 2026
Merged

perf: eliminate redundant copies, fix memory leaks, use platform abstraction#50
AreteDriver merged 2 commits intomainfrom
claude/performance-code-review-omZxi

Conversation

@AreteDriver
Copy link
Copy Markdown
Owner

Capture pipeline:

  • Skip RGBX→RGB conversion in xlib capture (RGBX handled natively by QImage)
  • Pass pre-computed raw bytes to pil_to_qimage to avoid double tobytes()
  • Add RGBX format support to pil_to_qimage via Format_RGBX8888
  • Close superseded PIL images during frame deduplication (memory leak fix)

Platform layer:

  • Singleton cache for factory functions (avoid redundant instance creation)
  • get_window_list() now uses wmctrl cache (consistent with get_eve_windows)
  • _activate_window uses platform abstraction instead of raw subprocess

Intel parser:

  • Replace O(n) regex scan over 200+ ship names with set intersection
  • Tokenize message once, use fast set lookup for single-word ships

Tests:

  • Add setup_method to factory tests to clear singleton cache for isolation

https://claude.ai/code/session_01QuCbaZcM64kfksMbKkSKfK

…raction

Capture pipeline:
- Skip RGBX→RGB conversion in xlib capture (RGBX handled natively by QImage)
- Pass pre-computed raw bytes to pil_to_qimage to avoid double tobytes()
- Add RGBX format support to pil_to_qimage via Format_RGBX8888
- Close superseded PIL images during frame deduplication (memory leak fix)

Platform layer:
- Singleton cache for factory functions (avoid redundant instance creation)
- get_window_list() now uses wmctrl cache (consistent with get_eve_windows)
- _activate_window uses platform abstraction instead of raw subprocess

Intel parser:
- Replace O(n) regex scan over 200+ ship names with set intersection
- Tokenize message once, use fast set lookup for single-word ships

Tests:
- Add setup_method to factory tests to clear singleton cache for isolation

https://claude.ai/code/session_01QuCbaZcM64kfksMbKkSKfK
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @AreteDriver, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's performance and memory efficiency by optimizing image processing within the capture pipeline and refining the Intel parser's ship extraction logic. It also improves code maintainability and robustness by introducing a singleton cache for platform-specific components and abstracting window activation operations, alongside addressing potential memory leaks.

Highlights

  • Capture Pipeline Optimizations: Eliminated redundant RGBX to RGB conversion in Xlib capture, passed pre-computed raw bytes to pil_to_qimage to avoid double tobytes() calls, and added native RGBX support to pil_to_qimage.
  • Memory Leak Fixes: Ensured superseded PIL images are explicitly closed during frame deduplication to prevent memory leaks.
  • Platform Abstraction Enhancements: Implemented a singleton cache for platform factory functions to prevent redundant instance creation and updated window activation logic to use the platform abstraction layer.
  • Intel Parser Performance: Replaced an inefficient O(n) regex scan for ship names with a faster set intersection approach, tokenizing the message once.
  • Testing Improvements: Added setup_method to platform factory tests to clear the singleton cache, ensuring better test isolation.
Changelog
  • src/argus_overview/intel/parser.py
    • Refactored _extract_ships to use set intersection for single-word ship names and a substring check for multi-word names, replacing a regex-based scan.
  • src/argus_overview/platform/init.py
    • Introduced a singleton_cache and modified all get* factory functions to return cached singleton instances, avoiding repeated object creation.
    • Added _clear_singleton_cache for testing purposes.
  • src/argus_overview/platform/linux.py
    • Updated get_window_list to utilize a cached wmctrl output, aligning with get_eve_windows.
    • Modified _capture_xlib to return RGBX images directly, eliminating an unnecessary convert("RGB") call.
  • src/argus_overview/ui/main_tab.py
    • Enhanced pil_to_qimage to accept optional pre-computed raw bytes and added support for RGBX format using QImage.Format.Format_RGBX8888.
    • Modified update_frame to pass pre-computed raw bytes to pil_to_qimage and to sample raw pixel bytes for frame fingerprinting.
    • Implemented explicit closing of superseded PIL images in _process_capture_results to prevent memory leaks.
  • src/argus_overview/ui/main_window_v21.py
    • Refactored _activate_window to use the platform abstraction layer's is_valid_window_id, minimize_window, and activate_window methods instead of direct subprocess calls to xdotool.
  • tests/test_platform.py
    • Added setup_method to TestFactoryFunctions and TestWindowsFactoryBranches to clear the singleton cache before each test, ensuring test isolation.
Activity
  • No human activity (comments, reviews, etc.) has been recorded for this pull request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces significant performance improvements, memory leak fixes, and a major refactoring to a platform abstraction layer. The changes are well-executed and align with the goals described. The use of singleton caching for platform-specific managers and optimizations in the image processing pipeline are particularly effective.

My review includes a few suggestions:

  • A critical fix for a test that will fail due to an API change in the capture logic.
  • A recommendation to reduce code duplication in the new platform factory functions for better maintainability.
  • A couple of minor performance tweaks in the intel parser and image conversion utility.

Overall, this is a high-quality contribution that substantially improves the application's performance and structure. Addressing the identified issues will make it even better.

img = Image.frombytes("RGBX", (geom.width, geom.height), raw.data, "raw", "BGRX")
return img.convert("RGB")
# Return RGBX directly — avoids a full-image copy from .convert("RGB")
return Image.frombytes("RGBX", (geom.width, geom.height), raw.data, "raw", "BGRX")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

This change to return an 'RGBX' image directly is a great performance optimization. However, it seems the corresponding test TestXlibCapture.test_capture_xlib_success in tests/test_platform.py was not updated. The test still asserts result.mode == 'RGB' at line 1423, which will now fail. Please update the test to assert for 'RGBX'.

Comment on lines +485 to 489
words = set(re.findall(r"[a-z]+", message.lower()))
# Single-word ships via fast set intersection
found = list(words & self.SHIP_TYPES)
# Multi-word ship names (e.g. "force auxiliary") need substring check
msg_lower = message.lower()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This is a great performance improvement. To make it even more efficient, you can avoid calling .lower() twice on the message.

Suggested change
words = set(re.findall(r"[a-z]+", message.lower()))
# Single-word ships via fast set intersection
found = list(words & self.SHIP_TYPES)
# Multi-word ship names (e.g. "force auxiliary") need substring check
msg_lower = message.lower()
msg_lower = message.lower()
words = set(re.findall(r"[a-z]+", msg_lower))
# Single-word ships via fast set intersection
found = list(words & self.SHIP_TYPES)
# Multi-word ship names (e.g. "force auxiliary") need substring check

Comment on lines 95 to +220
def get_window_manager() -> WindowManager:
"""Create a platform-appropriate WindowManager instance.
"""Get the platform-appropriate WindowManager singleton.

Returns:
WindowManager implementation for current platform

Raises:
RuntimeError: If platform is not supported
"""
platform = get_platform_name()
if platform == "windows":
from .windows import WindowManagerWindows
key = "window_manager"
if key not in _singleton_cache:
platform = get_platform_name()
if platform == "windows":
from .windows import WindowManagerWindows

return WindowManagerWindows()
elif platform == "linux":
from .linux import WindowManagerLinux
_singleton_cache[key] = WindowManagerWindows()
elif platform == "linux":
from .linux import WindowManagerLinux

return WindowManagerLinux()
raise RuntimeError(f"Unsupported platform: {platform}")
_singleton_cache[key] = WindowManagerLinux()
else:
raise RuntimeError(f"Unsupported platform: {platform}")
return _singleton_cache[key] # type: ignore[return-value]


def get_window_capture(max_workers: int = 4) -> WindowCapture:
"""Create a platform-appropriate WindowCapture instance.
"""Get the platform-appropriate WindowCapture singleton.

Args:
max_workers: Number of capture worker threads
max_workers: Number of capture worker threads (only used on first call)

Returns:
WindowCapture implementation for current platform

Raises:
RuntimeError: If platform is not supported
"""
platform = get_platform_name()
if platform == "windows":
from .windows import WindowCaptureWindows
key = "window_capture"
if key not in _singleton_cache:
platform = get_platform_name()
if platform == "windows":
from .windows import WindowCaptureWindows

return WindowCaptureWindows(max_workers=max_workers)
elif platform == "linux":
from .linux import WindowCaptureLinux
_singleton_cache[key] = WindowCaptureWindows(max_workers=max_workers)
elif platform == "linux":
from .linux import WindowCaptureLinux

return WindowCaptureLinux(max_workers=max_workers)
raise RuntimeError(f"Unsupported platform: {platform}")
_singleton_cache[key] = WindowCaptureLinux(max_workers=max_workers)
else:
raise RuntimeError(f"Unsupported platform: {platform}")
return _singleton_cache[key] # type: ignore[return-value]


def get_screen_manager() -> ScreenManager:
"""Create a platform-appropriate ScreenManager instance.
"""Get the platform-appropriate ScreenManager singleton.

Returns:
ScreenManager implementation for current platform

Raises:
RuntimeError: If platform is not supported
"""
platform = get_platform_name()
if platform == "windows":
from .windows import ScreenManagerWindows
key = "screen_manager"
if key not in _singleton_cache:
platform = get_platform_name()
if platform == "windows":
from .windows import ScreenManagerWindows

return ScreenManagerWindows()
elif platform == "linux":
from .linux import ScreenManagerLinux
_singleton_cache[key] = ScreenManagerWindows()
elif platform == "linux":
from .linux import ScreenManagerLinux

return ScreenManagerLinux()
raise RuntimeError(f"Unsupported platform: {platform}")
_singleton_cache[key] = ScreenManagerLinux()
else:
raise RuntimeError(f"Unsupported platform: {platform}")
return _singleton_cache[key] # type: ignore[return-value]


def get_eve_path_resolver() -> EVEPathResolver:
"""Create a platform-appropriate EVEPathResolver instance.
"""Get the platform-appropriate EVEPathResolver singleton.

Returns:
EVEPathResolver implementation for current platform

Raises:
RuntimeError: If platform is not supported
"""
platform = get_platform_name()
if platform == "windows":
from .windows import EVEPathResolverWindows
key = "eve_path_resolver"
if key not in _singleton_cache:
platform = get_platform_name()
if platform == "windows":
from .windows import EVEPathResolverWindows

return EVEPathResolverWindows()
elif platform == "linux":
from .linux import EVEPathResolverLinux
_singleton_cache[key] = EVEPathResolverWindows()
elif platform == "linux":
from .linux import EVEPathResolverLinux

return EVEPathResolverLinux()
raise RuntimeError(f"Unsupported platform: {platform}")
_singleton_cache[key] = EVEPathResolverLinux()
else:
raise RuntimeError(f"Unsupported platform: {platform}")
return _singleton_cache[key] # type: ignore[return-value]


def get_hotkey_helper() -> HotkeyHelper:
"""Create a platform-appropriate HotkeyHelper instance.
"""Get the platform-appropriate HotkeyHelper singleton.

Returns:
HotkeyHelper implementation for current platform

Raises:
RuntimeError: If platform is not supported
"""
platform = get_platform_name()
if platform == "windows":
from .windows import HotkeyHelperWindows

return HotkeyHelperWindows()
elif platform == "linux":
from .linux import HotkeyHelperLinux

return HotkeyHelperLinux()
raise RuntimeError(f"Unsupported platform: {platform}")
key = "hotkey_helper"
if key not in _singleton_cache:
platform = get_platform_name()
if platform == "windows":
from .windows import HotkeyHelperWindows

_singleton_cache[key] = HotkeyHelperWindows()
elif platform == "linux":
from .linux import HotkeyHelperLinux

_singleton_cache[key] = HotkeyHelperLinux()
else:
raise RuntimeError(f"Unsupported platform: {platform}")
return _singleton_cache[key] # type: ignore[return-value]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The introduction of a singleton cache is a good performance improvement. However, the implementation is very repetitive across all the factory functions (get_window_manager, get_window_capture, etc.). To improve maintainability and reduce code duplication, consider abstracting the caching and platform-switching logic into a generic helper function or a decorator. This would make the code much more DRY (Don't Repeat Yourself).

Comment on lines +529 to +534
_FORMAT_MAP = {
"RGB": (3, QImage.Format.Format_RGB888),
"RGBX": (4, QImage.Format.Format_RGBX8888),
"RGBA": (4, QImage.Format.Format_RGBA8888),
"L": (1, QImage.Format.Format_Grayscale8),
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This refactoring is much cleaner. For a minor performance improvement, consider defining _FORMAT_MAP as a module-level constant outside of the pil_to_qimage function. This will prevent it from being recreated on every function call.

…layer

- Update _activate_window tests to use capture_system mock instead of
  subprocess.run (7 tests fixed in test_main_window_v21.py)
- Fix test_get_window_list to patch _get_wmctrl_window_list instead of
  run_x11_subprocess (test_platform.py)
- Fix test_capture_xlib_success to assert RGBX mode (matches new xlib
  capture that skips RGB conversion)
- Fix test_get_window_list_exception to patch correct target
- Move _FORMAT_MAP from pil_to_qimage() body to module-level constant
  (avoids dict recreation on every frame)
- Add RGBX and raw_data kwarg tests for pil_to_qimage
- Run ruff format on files with formatting violations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AreteDriver AreteDriver merged commit 331031c into main Feb 26, 2026
14 checks passed
@AreteDriver AreteDriver deleted the claude/performance-code-review-omZxi branch February 26, 2026 22:47
@codecov
Copy link
Copy Markdown

codecov bot commented Feb 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants