async def benchmark_node_execution(
        self,
        inputs: Optional[Dict[str, Any]] = None,
        iterations: int = 1,
        warmup: bool = False,
    ) -> List[NodeExecutionInfo]:
        """
        Measures the execution time of individual nodes in the PyTorch model.

        This method loads the converted model, runs predictions, and retrieves the execution time
        of each operation within the model.

        Parameters
        ----------
        inputs : Optional[Dict[str, Any]]
            The input data for the model prediction. If None, random input data will be generated.

        iterations: int
            The number of prediction iterations to run. Defaults to 1.

        warmup: bool
            Whether to perform a warmup iteration. Defaults to False.

        Returns
        -------
        List[TorchNodeExecutionInfo]
            A list of TorchNodeExecutionInfo objects, each containing
            details about an node's execution, sorted by execution time in descending order.

        Notes
        -----
        - The returned list is sorted by execution time, with the most time-consuming operations first.
        - Execution times are estimated based on the overall prediction time and the converted model's compute plan.
        """
        source_operation_execution_infos = {
            source: TorchMLModelBenchmarker.NodeExecutionInfo.from_source(source)
            for source in self._source_to_target_ops_mapping
        }

        target_execution_infos = await self.benchmark_operation_execution(
            inputs=inputs,
            iterations=iterations,
            warmup=warmup,
        )

        for target_execution_info in target_execution_infos:
            target_samples = target_execution_info.measurement.samples
            source_nodes = self.find_source_nodes_for_target_op(target_execution_info.spec)
            source_samples = [target_sample / len(source_nodes) for target_sample in target_samples]
            for source_node in source_nodes:
                source_execution_info = source_operation_execution_infos[source_node]
                source_execution_info.targets.append(target_execution_info)
                source_execution_info.measurement = source_execution_info.measurement.add_samples(
                    source_samples
                )

        result = list(source_operation_execution_infos.values())
        return sorted(result, key=lambda value: value.measurement.sort_key, reverse=True)

        Measures the execution time of individual nodes in the PyTorch model.

        This method loads the converted model, runs predictions, and retrieves the execution time
        of each operation within the model.

        Parameters
        ----------
        inputs : Optional[Dict[str, Any]]
            The input data for the model prediction. If None, random input data will be generated.

        iterations: int
            The number of prediction iterations to run. Defaults to 1.

        warmup: bool
            Whether to perform a warmup iteration. Defaults to False.

        Returns
        -------
        List[TorchNodeExecutionInfo]
            A list of TorchNodeExecutionInfo objects, each containing
            details about an node's execution, sorted by execution time in descending order.

        Notes
        -----
        - The returned list is sorted by execution time, with the most time-consuming operations first.
        - Execution times are estimated based on the overall prediction time and the converted model's compute plan.
        
coremltools/models/ml_program/experimental/torch/perf_utils.py