    def __init__(self, devices: List[str], postprocessing_delegate, timeout: int = 500):
        """
        Parameters
        ----------
        devices : List[str]
            device identifiers (contents of {CUDA,HIP}_VISIBLE_DEVICES)
        postprocessing_delegate :
            object responsible for postprocessing results after futures completion
        timeout : int
            timeout to wait for all profilers completion in seconds
        """
        if not devices:
            # devices is either None or empty list: use device 0
            devices = [0]
        # This queue is used to ensure only one task is executed on a device at a time
        self._device_queue = Queue()
        # This queue is used to ensure postprocessing in `join()` happens *after* done_callbacks complete
        self._done_queue = Queue()
        for d in devices:
            self._device_queue.put(str(d))
        _LOGGER.info(f"Initialized profiler runner with devices: {devices}")
        self._timeout = timeout
        self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=len(devices))
        self._futures = []
        self._cmds = []
        self._postprocessing_delegate = postprocessing_delegate
        try:
            target = Target.current()
        except RuntimeError:
            target = detect_target()
        self._dev_select_flag = target.dev_select_flag()
Parameters
----------
devices : List[str]
device identifiers (contents of {CUDA,HIP}_VISIBLE_DEVICES)
postprocessing_delegate :
object responsible for postprocessing results after futures completion
timeout : int
timeout to wait for all profilers completion in seconds
python/aitemplate/backend/profiler_runner.py