From e0169cd84561cd172c914bab367f96385b4f22a3 Mon Sep 17 00:00:00 2001 From: Masonmason Date: Wed, 16 Jul 2025 21:45:14 +0800 Subject: [PATCH] Fix device detection format and pipeline deployment compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device Detection Updates: - Update device series detection to use product_id mapping (0x100 -> KL520, 0x720 -> KL720) - Handle JSON dict format from kp.core.scan_devices() properly - Extract usb_port_id correctly from device descriptors - Support multiple device descriptor formats (dict, list, object) - Enhanced debug output shows Product ID for verification Pipeline Deployment Fixes: - Remove invalid preprocessor/postprocessor parameters from MultiDongle constructor - Add max_queue_size parameter support to MultiDongle - Fix pipeline stage initialization to match MultiDongle constructor - Add auto_detect parameter support for pipeline stages - Store stage processors as instance variables for future use Example Updates: - Update device_detection_example.py to show Product ID in output - Enhanced error handling and format detection Resolves pipeline deployment error: "MultiDongle.__init__() got an unexpected keyword argument 'preprocessor'" Now properly handles real device descriptors with correct product_id to series mapping. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../core/functions/InferencePipeline.py | 8 +- cluster4npu_ui/core/functions/Multidongle.py | 115 ++++++++++++++---- cluster4npu_ui/device_detection_example.py | 8 +- 3 files changed, 103 insertions(+), 28 deletions(-) diff --git a/cluster4npu_ui/core/functions/InferencePipeline.py b/cluster4npu_ui/core/functions/InferencePipeline.py index 4571420..cd47888 100644 --- a/cluster4npu_ui/core/functions/InferencePipeline.py +++ b/cluster4npu_ui/core/functions/InferencePipeline.py @@ -49,11 +49,15 @@ class PipelineStage: ncpu_fw_path=config.ncpu_fw_path, model_path=config.model_path, upload_fw=config.upload_fw, - preprocessor=config.stage_preprocessor, - postprocessor=config.stage_postprocessor, + auto_detect=config.auto_detect if hasattr(config, 'auto_detect') else False, max_queue_size=config.max_queue_size ) + # Store preprocessor and postprocessor for later use + self.stage_preprocessor = config.stage_preprocessor + self.stage_postprocessor = config.stage_postprocessor + self.max_queue_size = config.max_queue_size + # Inter-stage processors self.input_preprocessor = config.input_preprocessor self.output_postprocessor = config.output_postprocessor diff --git a/cluster4npu_ui/core/functions/Multidongle.py b/cluster4npu_ui/core/functions/Multidongle.py index 0c66606..5ccd303 100644 --- a/cluster4npu_ui/core/functions/Multidongle.py +++ b/cluster4npu_ui/core/functions/Multidongle.py @@ -95,21 +95,67 @@ class MultiDongle: return [] devices_info = [] - print(f' - Found {len(device_descriptors)} device(s):') - for i, device_desc in enumerate(device_descriptors): - # Get device series (e.g., KL520, KL720, etc.) - series = MultiDongle._get_device_series(device_desc) - port_id = device_desc.port_id + # Handle both dict and object formats + if isinstance(device_descriptors, dict): + # Handle JSON dict format: {"0": {...}, "1": {...}} + print(f' - Found {len(device_descriptors)} device(s):') + + for key, device_desc in device_descriptors.items(): + # Get device series using product_id + series = MultiDongle._get_device_series(device_desc) + # Use usb_port_id from the device descriptor + port_id = device_desc.get('usb_port_id', 0) + + device_info = { + 'port_id': port_id, + 'series': series, + 'device_descriptor': device_desc + } + devices_info.append(device_info) + + print(f' [{int(key)+1}] Port ID: {port_id}, Series: {series}, Product ID: {device_desc.get("product_id", "Unknown")}') + + elif isinstance(device_descriptors, (list, tuple)): + # Handle list/array format + print(f' - Found {len(device_descriptors)} device(s):') + + for i, device_desc in enumerate(device_descriptors): + # Get device series + series = MultiDongle._get_device_series(device_desc) + + # Extract port_id based on format + if isinstance(device_desc, dict): + port_id = device_desc.get('usb_port_id', device_desc.get('port_id', 0)) + else: + port_id = getattr(device_desc, 'usb_port_id', getattr(device_desc, 'port_id', 0)) + + device_info = { + 'port_id': port_id, + 'series': series, + 'device_descriptor': device_desc + } + devices_info.append(device_info) + + print(f' [{i+1}] Port ID: {port_id}, Series: {series}') + else: + # Handle single device or other formats + print(' - Found 1 device:') + series = MultiDongle._get_device_series(device_descriptors) + + if isinstance(device_descriptors, dict): + port_id = device_descriptors.get('usb_port_id', device_descriptors.get('port_id', 0)) + else: + port_id = getattr(device_descriptors, 'usb_port_id', getattr(device_descriptors, 'port_id', 0)) device_info = { 'port_id': port_id, 'series': series, - 'device_descriptor': device_desc + 'device_descriptor': device_descriptors } devices_info.append(device_info) - print(f' [{i+1}] Port ID: {port_id}, Series: {series}') + print(f' [1] Port ID: {port_id}, Series: {series}') return devices_info @@ -120,16 +166,42 @@ class MultiDongle: @staticmethod def _get_device_series(device_descriptor): """ - Extract device series from device descriptor. + Extract device series from device descriptor using product_id. Args: - device_descriptor: Device descriptor from scan_devices() + device_descriptor: Device descriptor from scan_devices() - can be dict or object Returns: str: Device series (e.g., 'KL520', 'KL720', etc.) """ try: - # Try to get the chip from device descriptor + # Product ID to device series mapping + product_id_mapping = { + '0x100': 'KL520', + '0x720': 'KL720', + '0x630': 'KL630', + '0x730': 'KL730', + '0x540': 'KL540', + # Add more mappings as needed + } + + # Handle dict format (from JSON) + if isinstance(device_descriptor, dict): + product_id = device_descriptor.get('product_id', '') + if product_id in product_id_mapping: + return product_id_mapping[product_id] + return f'Unknown ({product_id})' + + # Handle object format (from SDK) + if hasattr(device_descriptor, 'product_id'): + product_id = device_descriptor.product_id + if isinstance(product_id, int): + product_id = hex(product_id) + if product_id in product_id_mapping: + return product_id_mapping[product_id] + return f'Unknown ({product_id})' + + # Legacy chip-based detection (fallback) if hasattr(device_descriptor, 'chip'): chip = device_descriptor.chip if chip == kp.ModelNefDescriptor.KP_CHIP_KL520: @@ -142,17 +214,8 @@ class MultiDongle: return 'KL730' elif chip == kp.ModelNefDescriptor.KP_CHIP_KL540: return 'KL540' - elif chip == kp.ModelNefDescriptor.KP_CHIP_KL630_LEGACY: - return 'KL630_LEGACY' - elif chip == kp.ModelNefDescriptor.KP_CHIP_KL720_LEGACY: - return 'KL720_LEGACY' - elif chip == kp.ModelNefDescriptor.KP_CHIP_KL520_LEGACY: - return 'KL520_LEGACY' - - # Fallback: try to get from device descriptor attributes - if hasattr(device_descriptor, 'product_name'): - return device_descriptor.product_name + # Final fallback return 'Unknown' except Exception as e: @@ -195,7 +258,7 @@ class MultiDongle: except kp.ApiKPException as exception: raise Exception(f'Failed to connect devices: {str(exception)}') - def __init__(self, port_id: list = None, scpu_fw_path: str = None, ncpu_fw_path: str = None, model_path: str = None, upload_fw: bool = False, auto_detect: bool = False): + def __init__(self, port_id: list = None, scpu_fw_path: str = None, ncpu_fw_path: str = None, model_path: str = None, upload_fw: bool = False, auto_detect: bool = False, max_queue_size: int = 0): """ Initialize the MultiDongle class. :param port_id: List of USB port IDs for the same layer's devices. If None and auto_detect=True, will auto-detect devices. @@ -204,6 +267,7 @@ class MultiDongle: :param model_path: Path to the model file. :param upload_fw: Flag to indicate whether to upload firmware. :param auto_detect: Flag to auto-detect and connect to available devices. + :param max_queue_size: Maximum size for internal queues. If 0, unlimited queues are used. """ self.auto_detect = auto_detect self.connected_devices_info = [] @@ -234,9 +298,12 @@ class MultiDongle: self.generic_inference_input_descriptor = None # Queues for data # Input queue for images to be sent - self._input_queue = queue.Queue() - # Output queue for received results - self._output_queue = queue.Queue() + if max_queue_size > 0: + self._input_queue = queue.Queue(maxsize=max_queue_size) + self._output_queue = queue.Queue(maxsize=max_queue_size) + else: + self._input_queue = queue.Queue() + self._output_queue = queue.Queue() # Threading attributes self._send_thread = None diff --git a/cluster4npu_ui/device_detection_example.py b/cluster4npu_ui/device_detection_example.py index 6a2d730..96e7f88 100644 --- a/cluster4npu_ui/device_detection_example.py +++ b/cluster4npu_ui/device_detection_example.py @@ -28,7 +28,9 @@ def example_device_scan(): print(f"Found {len(devices)} device(s):") for i, device in enumerate(devices): - print(f" [{i+1}] Port ID: {device['port_id']}, Series: {device['series']}") + desc = device['device_descriptor'] + product_id = desc.get('product_id', 'Unknown') if isinstance(desc, dict) else 'Unknown' + print(f" [{i+1}] Port ID: {device['port_id']}, Series: {device['series']}, Product ID: {product_id}") except Exception as e: print(f"Error during device scan: {str(e)}") @@ -47,7 +49,9 @@ def example_auto_connect(): print(f"Successfully connected to {len(connected_devices)} device(s):") for i, device in enumerate(connected_devices): - print(f" [{i+1}] Port ID: {device['port_id']}, Series: {device['series']}") + desc = device['device_descriptor'] + product_id = desc.get('product_id', 'Unknown') if isinstance(desc, dict) else 'Unknown' + print(f" [{i+1}] Port ID: {device['port_id']}, Series: {device['series']}, Product ID: {product_id}") # Disconnect devices import kp