from __future__ import annotations
from abc import ABC, abstractmethod
from affinity_sched.task.task_base import Task, TaskType, PriorityLevel
from affinity_sched.task.thread_task import ThreadTask
from affinity_sched.affinity_domain import AffinityDomainManager
import affinity_sched.utils as utils
ACL_THREAD = "acl_thread"
RELEASE_THREAD = "release_thread"
RT_RECYCLE_THREAD = "RT_RECYCLE"
SQ_IRQ = "sq_send_trigger_irq"
CQ_IRQ = "cq_update_irq"
TRS_MBOX_IRQ_PREFIX = "trs-mbox"
class NpuTask(Task, ABC):
def __init__(self, task_type: TaskType, group_id: int, npu_id: int):
super().__init__(task_type=task_type, group_id=group_id, task_id=npu_id)
self.priority = PriorityLevel.HIGH
self.bind_pid: int | None = None
self.bind_high_prio_thread: list[ThreadTask] = []
@abstractmethod
def init_npu(self) -> None:
pass
@abstractmethod
def print(self) -> None:
pass
@property
def processes(self) -> list[int]:
return []
class NpuTaskA3(NpuTask):
def __init__(self, group_id: int, npu_id: int):
super().__init__(task_type=TaskType.NPU_A3, group_id=group_id, npu_id=npu_id)
self._acl_thread: int | None = None
self._release_thread: int | None = None
self._rt_recycle_thread: int | None = None
self._sq_irq: int | None = None
self._cq_irqs: list[int] = []
self._trs_mbox_irq: int | None = None
self._dev_sq_task: int | None = None
self._dev_sq_send_wq: int | None = None
self._acl_thread_cpus: list[int] = []
self._release_thread_cpus: list[int] = []
self._rt_recycle_thread_cpus: list[int] = []
self._sq_irq_cpus: list[int] = []
self._cq_irqs_cpus: list[int] = []
self._trs_mbox_irq_cpus: list[int] = []
self._dev_sq_task_cpus: list[int] = []
self._dev_sq_send_wq_cpus: list[int] = []
self.trs_mbox_name = f"{TRS_MBOX_IRQ_PREFIX}-{self.task_id}-0"
self.dev_sq_task_name = f"dev{self.task_id}_sq_task"
self.dev_sq_send_wq_name = f"dev{self.task_id}_sq_send_wq"
def init_npu(self) -> None:
print(f"\nStarting init npu[{self.task_id}]...")
self._get_npu_threads()
self._get_npu_irqs()
self._get_npu_dev_sq()
@property
def min_cpu(self) -> int:
need_cpu = 0
need_cpu += 1 if self._acl_thread is not None else 0
need_cpu += 1 if self._release_thread is not None else 0
need_cpu += 1 if self._rt_recycle_thread is not None else 0
need_cpu += 1 if self._sq_irq is not None else 0
need_cpu += 1 if self._cq_irqs else 0
need_cpu += 1 if self._trs_mbox_irq is not None else 0
need_cpu += 1 if self._dev_sq_task is not None else 0
need_cpu += 1 if self._dev_sq_send_wq is not None else 0
need_cpu += len(self.bind_high_prio_thread)
return need_cpu
@property
def min_cluster(self) -> int:
CPUS_PER_CLUSTER = 4
base = self.min_cpu // CPUS_PER_CLUSTER
extra = self.min_cpu % CPUS_PER_CLUSTER
return base + 1 if extra > 0 else base
@property
def processes(self) -> list[int]:
procs = []
if self._dev_sq_task is not None:
procs.append(self._dev_sq_task)
if self._dev_sq_send_wq is not None:
procs.append(self._dev_sq_send_wq)
return procs
@property
def irqs(self) -> list[tuple[int, str]]:
irqs = []
if self._sq_irq is not None:
irqs.append((self._sq_irq, SQ_IRQ))
for cq in self._cq_irqs:
irqs.append((cq, CQ_IRQ))
if self._trs_mbox_irq is not None:
irqs.append((self._trs_mbox_irq, self.trs_mbox_name))
return irqs
def _get_npu_dev_sq(self) -> None:
print(f"Starting get npu[{self.task_id}] dev_sq...")
pids = utils.get_pid_by_process_name(process_name=self.dev_sq_task_name)
if not pids:
print(f"[Warning] cannot found {self.dev_sq_task_name} for npu [{self.task_id}]")
else:
self._dev_sq_task = pids[0][0]
print(f"get npu process (name={self.dev_sq_task_name}, pid={self._dev_sq_task}) success.")
pids = utils.get_pid_by_process_name(process_name=self.dev_sq_send_wq_name[:15])
if not pids:
print(f"[Warning] cannot found {self.dev_sq_send_wq_name} for npu [{self.task_id}]")
else:
self._dev_sq_send_wq = pids[0][0]
print(f"get npu process (name={self.dev_sq_send_wq_name}, pid={self._dev_sq_send_wq}) success.")
def _get_npu_threads(self) -> None:
print(f"Starting get npu[{self.task_id}] threads...")
tids = utils.get_tid_by_thread_name(thread_name=ACL_THREAD, pid=self.bind_pid)
if not tids:
print(f"[Warning] cannot found {ACL_THREAD} for npu [{self.task_id}]")
else:
self._acl_thread = tids[0]
print(f"get npu thread (name={ACL_THREAD}, tid={self._acl_thread}) success.")
tids = utils.get_tid_by_thread_name(thread_name=RELEASE_THREAD, pid=self.bind_pid)
if not tids:
print(f"[Warning] cannot found {RELEASE_THREAD} for npu [{self.task_id}]")
else:
self._release_thread = tids[0]
print(f"get npu thread (name={RELEASE_THREAD}, tid={self._release_thread}) success.")
tids = utils.get_tid_by_thread_name(thread_name=RT_RECYCLE_THREAD, pid=self.bind_pid)
if not tids:
raise ValueError(f"[Warning] cannot found {RT_RECYCLE_THREAD} for npu [{self.task_id}]")
else:
self._rt_recycle_thread = tids[0]
print(f"get npu thread (name={RT_RECYCLE_THREAD}, tid={self._rt_recycle_thread}) success.")
def _get_npu_irqs(self) -> None:
print(f"Starting get npu[{self.task_id}] irqs...")
irqs = utils.get_npu_irq_by_name(irq_name=SQ_IRQ, npu_id=self.task_id)
if not irqs:
print(f"[Warning] cannot found {SQ_IRQ} of npu [{self.task_id}]")
else:
self._sq_irq = irqs[0]
print(f"get npu irq (name={SQ_IRQ}, id={self._sq_irq}) success.")
irqs = utils.get_npu_irq_by_name(irq_name=CQ_IRQ, npu_id=self.task_id)
if not irqs:
print(f"[Warning] cannot found {CQ_IRQ} of npu [{self.task_id}]")
else:
self._cq_irqs = irqs
print(f"get npu irq (name={CQ_IRQ}, id={self._cq_irqs}) success.")
irqs = utils.get_npu_irq_by_name(irq_name=self.trs_mbox_name, npu_id=self.task_id)
if not irqs:
print(f"[Warning] cannot found {self.trs_mbox_name} of npu [{self.task_id}]")
else:
self._trs_mbox_irq = irqs[0]
print(f"get npu irq (name={self.trs_mbox_name}, id={self._trs_mbox_irq}) success.")
def bind_cpu(self) -> None:
if self._acl_thread is not None and self._acl_thread_cpus:
print(
f"binding npu[{self.task_id}] thread[{self._acl_thread}]({ACL_THREAD}) "
f"to cpu {self._acl_thread_cpus}"
)
utils.bind_thread_to_cpus(tid=self._acl_thread, cpus=self._acl_thread_cpus)
if self._release_thread is not None and self._release_thread_cpus:
print(
f"binding npu[{self.task_id}] thread[{self._release_thread}]({RELEASE_THREAD}) "
f"to cpu {self._release_thread_cpus}"
)
utils.bind_thread_to_cpus(tid=self._release_thread, cpus=self._release_thread_cpus)
if self._rt_recycle_thread is not None and self._rt_recycle_thread_cpus:
print(
f"binding npu[{self.task_id}] thread[{self._rt_recycle_thread}]({RT_RECYCLE_THREAD}) "
f"to cpu {self._rt_recycle_thread_cpus}"
)
utils.bind_thread_to_cpus(tid=self._rt_recycle_thread, cpus=self._rt_recycle_thread_cpus)
if self._sq_irq is not None and self._sq_irq_cpus:
print(
f"binding npu[{self.task_id}] irq[{self._sq_irq}]({SQ_IRQ})"
f"to cpu {self._sq_irq_cpus}"
)
utils.bind_irq_to_cpus(irq_id=self._sq_irq, cpus=self._sq_irq_cpus, irq_name=SQ_IRQ)
if self._cq_irqs and self._cq_irqs_cpus:
print(
f"binding npu[{self.task_id}] irq{self._cq_irqs}({CQ_IRQ})"
f"to cpu {self._cq_irqs_cpus}"
)
for cq in self._cq_irqs:
utils.bind_irq_to_cpus(irq_id=cq, cpus=self._cq_irqs_cpus, irq_name=CQ_IRQ)
if self._trs_mbox_irq is not None and self._trs_mbox_irq_cpus:
print(
f"binding npu[{self.task_id}] irq[{self._trs_mbox_irq}]({self.trs_mbox_name}) "
f"to cpu {self._trs_mbox_irq_cpus}"
)
utils.bind_irq_to_cpus(irq_id=self._trs_mbox_irq, cpus=self._trs_mbox_irq_cpus, irq_name=self.trs_mbox_name)
if self._dev_sq_task is not None and self._dev_sq_task_cpus:
print(
f"binding npu[{self.task_id}] process[{self._dev_sq_task}]({self.dev_sq_task_name}) "
f"to cpu {self._dev_sq_task_cpus}"
)
utils.bind_process_to_cpus(pid=self._dev_sq_task, cpus=self._dev_sq_task_cpus)
if self._dev_sq_send_wq is not None and self._dev_sq_send_wq_cpus:
print(
f"binding npu[{self.task_id}] process[{self._dev_sq_send_wq}]({self.dev_sq_send_wq_name}) "
f"to cpu {self._dev_sq_send_wq_cpus}"
)
utils.bind_npu_sq_send_wq_to_cpus(npu_id=self.task_id, cpus=self._dev_sq_send_wq_cpus)
def assign_cpu(self, cpus: list[int]) -> None:
self.cpus.set_list(cpus)
cpu_num = len(cpus)
if cpu_num < self.min_cpu:
print(
f"[Error] assign cpu for npu[{self.task_id}] fail, "
f"no enough cpus, assigned {cpu_num}, need {self.min_cpu}"
)
return
start = 0
for thread in self.bind_high_prio_thread:
end = start + 1
thread.assign_cpu(cpus[start:end])
start = end
thread.socket = list(self.socket)
thread.numa = list(self.numa)
thread.cluster = list(self.cluster)
if self._acl_thread is not None:
end = start + 1
self._acl_thread_cpus = cpus[start:end]
start = end
if self._release_thread is not None:
end = start + 1
self._release_thread_cpus = cpus[start:end]
start = end
if self._rt_recycle_thread is not None:
end = start + 1
self._rt_recycle_thread_cpus = cpus[start:end]
start = end
if self._dev_sq_task is not None:
end = start + 1
self._dev_sq_task_cpus = cpus[start:end]
start = end
if self._dev_sq_send_wq is not None:
end = start + 1
self._dev_sq_send_wq_cpus = cpus[start:end]
start = end
if self._sq_irq is not None:
end = start + 1
self._sq_irq_cpus = cpus[start:end]
start = end
if self._cq_irqs is not None:
end = start + 1
self._cq_irqs_cpus = cpus[start:end]
start = end
if self._trs_mbox_irq is not None:
end = start + 1
self._trs_mbox_irq_cpus = cpus[start:end]
start = end
def print(self) -> None:
print(f" - {self}")
if self._dev_sq_task is not None:
print(
f" - Process[{self._dev_sq_task}]({self.dev_sq_task_name}): "
f"cpu={utils.compress_continuous(self._dev_sq_task_cpus)}"
)
if self._dev_sq_send_wq is not None:
print(
f" - Process[{self._dev_sq_send_wq}]({self.dev_sq_send_wq_name}): "
f"cpu={utils.compress_continuous(self._dev_sq_send_wq_cpus)}"
)
if self._acl_thread is not None:
print(
f" - Thread[{self._acl_thread}]({ACL_THREAD}): "
f"cpu={utils.compress_continuous(self._acl_thread_cpus)}"
)
if self._release_thread is not None:
(
f" - Thread[{self._release_thread}]({RELEASE_THREAD}): "
f"cpu={utils.compress_continuous(self._release_thread_cpus)}"
)
if self._rt_recycle_thread is not None:
print(
f" - Thread[{self._rt_recycle_thread}]({RT_RECYCLE_THREAD}): "
f"cpu={utils.compress_continuous(self._rt_recycle_thread_cpus)}"
)
if self._sq_irq is not None:
print(
f" - Irq[{self._sq_irq}]({SQ_IRQ}): "
f"cpu={utils.compress_continuous(self._sq_irq_cpus)}"
)
if self._cq_irqs:
print(
f" - Irq[{self._cq_irqs[0]}]({CQ_IRQ}): "
f"cpu={utils.compress_continuous(self._cq_irqs_cpus)}"
)
if self._trs_mbox_irq is not None:
print(
f" - Irq[{self._trs_mbox_irq}]({self.trs_mbox_name}): "
f"cpu={utils.compress_continuous(self._trs_mbox_irq_cpus)}"
)
def print_actual_affinity(self, domain: AffinityDomainManager) -> None:
print(f" - NPU_A3[{self.task_id}]: ")
if self._dev_sq_task is not None:
cpus = utils.get_process_cpus_by_pid(pid=self._dev_sq_task)
print(
f" - Process[{self._dev_sq_task}]({self.dev_sq_task_name}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._dev_sq_send_wq is not None:
cpus = utils.get_npu_work_queue_cpus_by_name(wq_name=self.dev_sq_send_wq_name)
print(
f" - Process[{self._dev_sq_send_wq}]({self.dev_sq_send_wq_name}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._acl_thread is not None:
cpus = utils.get_thread_cpus_by_tid(tid=self._acl_thread)
print(
f" - Thread[{self._acl_thread}]({ACL_THREAD}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._release_thread is not None:
cpus = utils.get_thread_cpus_by_tid(tid=self._release_thread)
print(
f" - Thread[{self._release_thread}]({RELEASE_THREAD}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._rt_recycle_thread is not None:
cpus = utils.get_thread_cpus_by_tid(tid=self._rt_recycle_thread)
print(
f" - Thread[{self._rt_recycle_thread}]({RT_RECYCLE_THREAD}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._sq_irq is not None:
cpus = utils.get_irq_cpus_by_irq_id(irq_id=self._sq_irq)
print(
f" - Irq[{self._sq_irq}]({SQ_IRQ}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
for cq in self._cq_irqs:
cpus = utils.get_irq_cpus_by_irq_id(irq_id=cq)
print(
f" - Irq[{cq}]({CQ_IRQ}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._trs_mbox_irq is not None:
cpus = utils.get_irq_cpus_by_irq_id(irq_id=self._trs_mbox_irq)
print(
f" - Irq[{self._trs_mbox_irq}]({self.trs_mbox_name}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
def build_dev_bind_data(self) -> dict:
bind_data = {}
if self._dev_sq_task is not None:
try:
bind_data["dev_sq_task"] = {
"pid": self._dev_sq_task,
"name": self.dev_sq_task_name,
"cpu_affinity": utils.get_process_cpus_by_pid(pid=self._dev_sq_task),
}
except Exception as e:
print(f"npu[{self.task_id}] {self.dev_sq_task_name} get cpu affinity failed, {str(e)}")
if self._dev_sq_send_wq is not None:
try:
bind_data["dev_sq_send_wq"] = {
"wq_name": self.dev_sq_send_wq_name,
"cpu_affinity": utils.get_npu_work_queue_cpus_by_name(wq_name=self.dev_sq_send_wq_name),
}
except Exception as e:
print(f"npu[{self.task_id}] {self.dev_sq_send_wq_name} get cpu affinity failed, {str(e)}")
return bind_data
class NpuTaskA5(NpuTask):
def __init__(self, group_id: int, npu_id: int):
super().__init__(task_type=TaskType.NPU_A5, group_id=group_id, npu_id=npu_id)
self._acl_thread: int | None = None
self._release_thread: int | None = None
self._rt_recycle_thread: int | None = None
self._acl_thread_cpus: list[int] = []
self._release_thread_cpus: list[int] = []
self._rt_recycle_thread_cpus: list[int] = []
def init_npu(self) -> None:
print(f"\nStarting init npu[{self.task_id}]...")
self._get_npu_threads()
@property
def min_cpu(self) -> int:
need_cpu = 0
need_cpu += 1 if self._acl_thread is not None else 0
need_cpu += 1 if self._release_thread is not None else 0
need_cpu += 1 if self._rt_recycle_thread is not None else 0
need_cpu += len(self.bind_high_prio_thread)
return need_cpu
@property
def min_cluster(self) -> int:
CPUS_PER_CLUSTER = 8
base = self.min_cpu // CPUS_PER_CLUSTER
extra = self.min_cpu % CPUS_PER_CLUSTER
return base + 1 if extra > 0 else base
def _get_npu_threads(self) -> None:
print(f"Starting get npu[{self.task_id}] threads...")
tids = utils.get_tid_by_thread_name(thread_name=ACL_THREAD, pid=self.bind_pid)
if not tids:
print(f"[Warning] cannot found {ACL_THREAD} for npu [{self.task_id}]")
else:
self._acl_thread = tids[0]
print(f"get npu thread (name={ACL_THREAD}, tid={self._acl_thread}) success.")
tids = utils.get_tid_by_thread_name(thread_name=RELEASE_THREAD, pid=self.bind_pid)
if not tids:
print(f"[Warning] cannot found {RELEASE_THREAD} for npu [{self.task_id}]")
else:
self._release_thread = tids[0]
print(f"get npu thread (name={RELEASE_THREAD}, tid={self._release_thread}) success.")
tids = utils.get_tid_by_thread_name(thread_name=RT_RECYCLE_THREAD, pid=self.bind_pid)
if not tids:
raise ValueError(f"[Warning] cannot found {RT_RECYCLE_THREAD} for npu [{self.task_id}]")
else:
self._rt_recycle_thread = tids[0]
print(f"get npu thread (name={RT_RECYCLE_THREAD}, tid={self._rt_recycle_thread}) success.")
def bind_cpu(self) -> None:
if self._acl_thread is not None and self._acl_thread_cpus:
print(
f"binding npu[{self.task_id}] thread[{self._acl_thread}]({ACL_THREAD}) "
f"to cpu {self._acl_thread_cpus}"
)
utils.bind_thread_to_cpus(tid=self._acl_thread, cpus=self._acl_thread_cpus)
if self._release_thread is not None and self._release_thread_cpus:
print(
f"binding npu[{self.task_id}] thread[{self._release_thread}]({RELEASE_THREAD}) "
f"to cpu {self._release_thread_cpus}"
)
utils.bind_thread_to_cpus(tid=self._release_thread, cpus=self._release_thread_cpus)
if self._rt_recycle_thread is not None and self._rt_recycle_thread_cpus:
print(
f"binding npu[{self.task_id}] thread[{self._rt_recycle_thread}]({RT_RECYCLE_THREAD}) "
f"to cpu {self._rt_recycle_thread_cpus}"
)
utils.bind_thread_to_cpus(tid=self._rt_recycle_thread, cpus=self._rt_recycle_thread_cpus)
def assign_cpu(self, cpus: list[int]) -> None:
self.cpus.set_list(cpus)
cpu_num = len(cpus)
if cpu_num < self.min_cpu:
print(
f"[Error] assign cpu for npu[{self.task_id}] fail, "
f"no enough cpus, assigned {cpu_num}, need {self.min_cpu}"
)
return
start = 0
if self._acl_thread is not None:
end = start + 1
self._acl_thread_cpus = cpus[start:end]
start = end
if self._release_thread is not None:
end = start + 1
self._release_thread_cpus = cpus[start:end]
start = end
if self._rt_recycle_thread is not None:
end = start + 1
self._rt_recycle_thread_cpus = cpus[start:end]
start = end
for thread in self.bind_high_prio_thread:
end = start + 1
thread.assign_cpu(cpus[start:end])
thread.socket = list(self.socket)
thread.numa = list(self.numa)
thread.cluster = list(self.cluster)
start = end
def print(self) -> None:
print(f" - {self}")
if self._acl_thread is not None:
print(
f" - Thread[{self._acl_thread}]({ACL_THREAD}): "
f"cpu={utils.compress_continuous(self._acl_thread_cpus)}"
)
if self._release_thread is not None:
print(
f" - Thread[{self._release_thread}]({RELEASE_THREAD}): "
f"cpu={utils.compress_continuous(self._release_thread_cpus)}"
)
if self._rt_recycle_thread is not None:
print(
f" - Thread[{self._rt_recycle_thread}]({RT_RECYCLE_THREAD}): "
f"cpu={utils.compress_continuous(self._rt_recycle_thread_cpus)}"
)
def print_actual_affinity(self, domain: AffinityDomainManager) -> None:
print(f" - NPU_A5[{self.task_id}]: ")
if self._acl_thread is not None:
cpus = utils.get_thread_cpus_by_tid(tid=self._acl_thread)
print(
f" - Thread[{self._acl_thread}]({ACL_THREAD}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._release_thread is not None:
cpus = utils.get_thread_cpus_by_tid(tid=self._release_thread)
print(
f" - Thread[{self._release_thread}]({RELEASE_THREAD}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
if self._rt_recycle_thread is not None:
cpus = utils.get_thread_cpus_by_tid(tid=self._rt_recycle_thread)
print(
f" - Thread[{self._rt_recycle_thread}]({RT_RECYCLE_THREAD}): "
f"numa=[{utils.compress_continuous(domain.get_numas_of_cpus(cpus))}], "
f"cluster=[{utils.compress_continuous(domain.get_clusters_of_cpus(cpus))}], "
f"cpu=[{utils.CPUMask().from_list(cpus)}]"
)
def create_npu_task(group_id: int, npu_id: int) -> NpuTask:
device_type = utils.get_ascend_device_type()
if device_type == utils.AscendDeviceType.A3:
return NpuTaskA3(group_id=group_id, npu_id=npu_id)
elif device_type == utils.AscendDeviceType.A5:
return NpuTaskA5(group_id=group_id, npu_id=npu_id)
else:
raise RuntimeError(f"Unsupported ascend device type {device_type}")