From 6d010ee65cba1fbf90b5b5e91cc86781e35808b6 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Sun, 29 Jun 2025 12:44:32 +0545 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(memory=5Fmonitor)?= =?UTF-8?q?:=20improve=20memory=20calculation=20logic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memory_monitor.py | 382 ---------------------------------------------- 1 file changed, 382 deletions(-) delete mode 100755 memory_monitor.py diff --git a/memory_monitor.py b/memory_monitor.py deleted file mode 100755 index 9c5c8f6..0000000 --- a/memory_monitor.py +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/env python3 -""" -Memory Monitor Script for Modus Components -Shows memory usage for each component in the modules/ directory. -""" - -import os -import sys -import time -import psutil -import subprocess -from typing import Dict, List, Tuple, Optional -from dataclasses import dataclass -import json -import argparse - - -@dataclass -class ComponentMemory: - """Data class to store component memory information.""" - name: str - pid: Optional[int] - memory_mb: float - memory_percent: float - cpu_percent: float - status: str - children_count: int = 0 - children_memory_mb: float = 0.0 - - -class ModusMemoryMonitor: - """Monitor memory usage of Modus components.""" - - def __init__(self): - self.modus_processes = {} - self.component_mapping = { - # Main components from modules/ - 'dock': ['dock', 'Dock'], - 'launcher': ['launcher', 'Launcher'], - 'notification_popup': ['notification', 'NotificationPopup'], - 'osd': ['osd', 'OSD'], - 'switcher': ['switcher', 'ApplicationSwitcher'], - 'corners': ['corners', 'Corners'], - - # Dock components - 'dock_applications': ['applications'], - 'dock_battery': ['battery'], - 'dock_controls': ['controls'], - 'dock_indicators': ['indicators'], - 'dock_metrics': ['metrics'], - 'dock_notifications': ['dock_notifications'], - 'dock_workspaces': ['workspaces'], - - # Launcher plugins - 'plugin_applications': ['plugin_applications'], - 'plugin_bluetooth': ['plugin_bluetooth'], - 'plugin_bookmarks': ['plugin_bookmarks'], - 'plugin_caffeine': ['plugin_caffeine'], - 'plugin_calculator': ['plugin_calculator'], - 'plugin_calendar': ['plugin_calendar'], - 'plugin_clipboard': ['plugin_clipboard'], - 'plugin_emoji': ['plugin_emoji'], - 'plugin_kanban': ['plugin_kanban'], - 'plugin_network': ['plugin_network'], - 'plugin_otp': ['plugin_otp'], - 'plugin_password': ['plugin_password'], - 'plugin_power': ['plugin_power'], - 'plugin_process': ['plugin_process'], - 'plugin_reminders': ['plugin_reminders'], - 'plugin_screencapture': ['plugin_screencapture'], - 'plugin_system': ['plugin_system'], - 'plugin_wallpaper': ['plugin_wallpaper'], - 'plugin_websearch': ['plugin_websearch'], - - # Services - 'service_brightness': ['brightness'], - 'service_network': ['network'], - 'service_battery': ['battery_service'], - 'service_mpris': ['mpris'], - 'service_notification': ['notification_service'], - } - - def find_modus_processes(self) -> List[psutil.Process]: - """Find all processes related to Modus.""" - modus_processes = [] - - try: - for proc in psutil.process_iter(['pid', 'name', 'cmdline', 'ppid']): - try: - info = proc.info - cmdline = ' '.join(info['cmdline']) if info['cmdline'] else '' - - # Check if this is a Modus-related process - if (info['name'] == 'modus' or - 'main.py' in cmdline or - 'Modus' in cmdline or - any(module in cmdline.lower() for module in ['dock', 'launcher', 'notification'])): - modus_processes.append(proc) - - except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): - continue - - except Exception as e: - print(f"Error finding Modus processes: {e}") - - return modus_processes - - def get_process_memory_info(self, proc: psutil.Process) -> Tuple[float, float, float]: - """Get memory and CPU information for a process.""" - try: - memory_info = proc.memory_info() - memory_mb = memory_info.rss / (1024 * 1024) - memory_percent = proc.memory_percent() - cpu_percent = proc.cpu_percent() - return memory_mb, memory_percent, cpu_percent - except (psutil.NoSuchProcess, psutil.AccessDenied): - return 0.0, 0.0, 0.0 - - def categorize_process(self, proc: psutil.Process) -> str: - """Categorize a process based on its command line and name.""" - try: - info = proc.info - cmdline = ' '.join(info['cmdline']) if info['cmdline'] else '' - name = info['name'].lower() - - # Check for main process - if 'main.py' in cmdline: - return 'main_process' - - # Check for specific components based on command line or imports - for component, keywords in self.component_mapping.items(): - if any(keyword.lower() in cmdline.lower() or keyword.lower() in name for keyword in keywords): - return component - - # Default categorization - if 'python' in name: - return 'python_subprocess' - else: - return 'other' - - except (psutil.NoSuchProcess, psutil.AccessDenied): - return 'unknown' - - def get_component_memory_usage(self) -> Dict[str, ComponentMemory]: - """Get memory usage for each Modus component.""" - components = {} - modus_processes = self.find_modus_processes() - - if not modus_processes: - print("No Modus processes found. Make sure Modus is running.") - return components - - # Initialize CPU monitoring for better readings - for proc in modus_processes: - try: - proc.cpu_percent() - except (psutil.NoSuchProcess, psutil.AccessDenied): - continue - - # Wait a bit for CPU percentage calculation - time.sleep(0.1) - - for proc in modus_processes: - try: - category = self.categorize_process(proc) - memory_mb, memory_percent, cpu_percent = self.get_process_memory_info(proc) - - if category not in components: - components[category] = ComponentMemory( - name=category, - pid=proc.pid, - memory_mb=memory_mb, - memory_percent=memory_percent, - cpu_percent=cpu_percent, - status=proc.status(), - children_count=0, - children_memory_mb=0.0 - ) - else: - # Aggregate memory for components with multiple processes - existing = components[category] - existing.memory_mb += memory_mb - existing.memory_percent += memory_percent - existing.cpu_percent += cpu_percent - existing.children_count += 1 - existing.children_memory_mb += memory_mb - - # Also check for child processes - try: - children = proc.children(recursive=True) - for child in children: - child_memory_mb, child_memory_percent, child_cpu_percent = self.get_process_memory_info(child) - components[category].children_memory_mb += child_memory_mb - components[category].memory_mb += child_memory_mb - components[category].memory_percent += child_memory_percent - components[category].cpu_percent += child_cpu_percent - components[category].children_count += 1 - - except (psutil.NoSuchProcess, psutil.AccessDenied): - pass - - except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): - continue - - return components - - def get_module_file_sizes(self) -> Dict[str, float]: - """Get file sizes for modules in the modules/ directory.""" - module_sizes = {} - modules_dir = os.path.join(os.path.dirname(__file__), 'modules') - - if not os.path.exists(modules_dir): - return module_sizes - - try: - for root, _, files in os.walk(modules_dir): - for file in files: - if file.endswith('.py'): - file_path = os.path.join(root, file) - try: - size_kb = os.path.getsize(file_path) / 1024 - relative_path = os.path.relpath(file_path, modules_dir) - module_sizes[relative_path] = size_kb - except OSError: - continue - except Exception as e: - print(f"Error getting module file sizes: {e}") - - return module_sizes - - def print_memory_report(self, components: Dict[str, ComponentMemory], - module_sizes: Dict[str, float], - format_type: str = 'table'): - """Print a formatted memory usage report.""" - if not components: - print("No Modus components found running.") - return - - total_memory = sum(comp.memory_mb for comp in components.values()) - total_cpu = sum(comp.cpu_percent for comp in components.values()) - - if format_type == 'json': - self._print_json_report(components, module_sizes, total_memory, total_cpu) - else: - self._print_table_report(components, module_sizes, total_memory, total_cpu) - - def _print_table_report(self, components: Dict[str, ComponentMemory], - module_sizes: Dict[str, float], - total_memory: float, total_cpu: float): - """Print memory report in table format.""" - print("\n" + "="*80) - print("MODUS MEMORY USAGE REPORT") - print("="*80) - - # Sort components by memory usage - sorted_components = sorted(components.items(), key=lambda x: x[1].memory_mb, reverse=True) - - print(f"\n{'Component':<25} {'Memory (MB)':<12} {'Memory %':<10} {'CPU %':<8} {'PID':<8} {'Status':<10}") - print("-" * 80) - - for name, comp in sorted_components: - print(f"{name:<25} {comp.memory_mb:>8.2f} {comp.memory_percent:>6.2f}% " - f"{comp.cpu_percent:>5.2f}% {comp.pid or 'N/A':<8} {comp.status:<10}") - - if comp.children_count > 0: - print(f" └─ Children: {comp.children_count} processes, " - f"{comp.children_memory_mb:.2f} MB") - - print("-" * 80) - print(f"{'TOTAL':<25} {total_memory:>8.2f} {'-':<10} {total_cpu:>5.2f}%") - - # Module file sizes - if module_sizes: - print(f"\n{'MODULE FILE SIZES':<25} {'Size (KB)':<12}") - print("-" * 40) - sorted_modules = sorted(module_sizes.items(), key=lambda x: x[1], reverse=True) - for module, size in sorted_modules[:10]: # Top 10 largest files - print(f"{module:<25} {size:>8.2f}") - - print("\n" + "="*80) - - def _print_json_report(self, components: Dict[str, ComponentMemory], - module_sizes: Dict[str, float], - total_memory: float, total_cpu: float): - """Print memory report in JSON format.""" - report = { - 'timestamp': time.time(), - 'total_memory_mb': round(total_memory, 2), - 'total_cpu_percent': round(total_cpu, 2), - 'components': {}, - 'module_file_sizes_kb': module_sizes - } - - for name, comp in components.items(): - report['components'][name] = { - 'memory_mb': round(comp.memory_mb, 2), - 'memory_percent': round(comp.memory_percent, 2), - 'cpu_percent': round(comp.cpu_percent, 2), - 'pid': comp.pid, - 'status': comp.status, - 'children_count': comp.children_count, - 'children_memory_mb': round(comp.children_memory_mb, 2) - } - - print(json.dumps(report, indent=2)) - - def monitor_continuously(self, interval: int = 5, format_type: str = 'table'): - """Monitor memory usage continuously.""" - try: - while True: - os.system('clear' if os.name == 'posix' else 'cls') - components = self.get_component_memory_usage() - module_sizes = self.get_module_file_sizes() - self.print_memory_report(components, module_sizes, format_type) - print(f"\nRefreshing every {interval} seconds... (Press Ctrl+C to stop)") - time.sleep(interval) - except KeyboardInterrupt: - print("\nMonitoring stopped.") - - def get_memory_summary(self) -> Dict[str, float]: - """Get a summary of memory usage by category.""" - components = self.get_component_memory_usage() - - summary = { - 'main_components': 0.0, - 'dock_components': 0.0, - 'launcher_plugins': 0.0, - 'services': 0.0, - 'other': 0.0 - } - - for name, comp in components.items(): - if name in ['main_process', 'dock', 'launcher', 'notification_popup', 'osd', 'switcher', 'corners']: - summary['main_components'] += comp.memory_mb - elif name.startswith('dock_'): - summary['dock_components'] += comp.memory_mb - elif name.startswith('plugin_'): - summary['launcher_plugins'] += comp.memory_mb - elif name.startswith('service_'): - summary['services'] += comp.memory_mb - else: - summary['other'] += comp.memory_mb - - return summary - - -def main(): - """Main function to run the memory monitor.""" - parser = argparse.ArgumentParser(description='Monitor memory usage of Modus components') - parser.add_argument('--format', choices=['table', 'json'], default='table', - help='Output format (default: table)') - parser.add_argument('--monitor', action='store_true', - help='Monitor continuously') - parser.add_argument('--interval', type=int, default=5, - help='Refresh interval in seconds for continuous monitoring (default: 5)') - parser.add_argument('--summary', action='store_true', - help='Show only summary by category') - - args = parser.parse_args() - - monitor = ModusMemoryMonitor() - - if args.monitor: - monitor.monitor_continuously(args.interval, args.format) - elif args.summary: - summary = monitor.get_memory_summary() - print("\nMODUS MEMORY SUMMARY BY CATEGORY") - print("="*40) - total = sum(summary.values()) - for category, memory in summary.items(): - percentage = (memory / total * 100) if total > 0 else 0 - print(f"{category.replace('_', ' ').title():<20} {memory:>8.2f} MB ({percentage:>5.1f}%)") - print("-"*40) - print(f"{'Total':<20} {total:>8.2f} MB") - else: - components = monitor.get_component_memory_usage() - module_sizes = monitor.get_module_file_sizes() - monitor.print_memory_report(components, module_sizes, args.format) - - -if __name__ == '__main__': - main() \ No newline at end of file