Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_multicore / tasks / swiglu.py: 100%
68 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-15 05:03 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-11-15 05:03 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""SwiGLU fill config: forward (TASK_SWI_GLU) and backward gradient (TASK_SWI_GLU_GRAD)."""
17import math
18import struct
19from dataclasses import dataclass
21from hyper_multicore.scheduler.config import (
22 TaskDescC, TensorDescC, RuntimeConfigC,
23 TaskAiCoreType, TaskType,
24 MAX_TENSOR_DIMS,
25)
26from hyper_multicore.scheduler.graph import OpType
27from hyper_multicore.tasks.task_base import FillConfig
28from hyper_multicore.tasks.utils import advance_tsv_vector
31def _encode_clamp_limit(clamp_limit: float | None) -> int:
32 """Encode a positive float32 clamp limit, reserving zero for no clamp."""
33 if clamp_limit is None:
34 return 0
35 valid_type = isinstance(clamp_limit, (int, float)) and not isinstance(
36 clamp_limit, bool
37 )
38 try:
39 clamp_bits = struct.unpack(
40 "<I", struct.pack("<f", float(clamp_limit))
41 )[0]
42 encoded_limit = struct.unpack("<f", struct.pack("<I", clamp_bits))[0]
43 except (OverflowError, TypeError, ValueError, struct.error):
44 encoded_limit = 0.0
45 clamp_bits = 0
46 if not valid_type or not math.isfinite(encoded_limit) or encoded_limit <= 0:
47 raise ValueError(
48 "clamp_limit must be finite, positive, and float32-representable "
49 "when provided"
50 )
51 return clamp_bits
54@dataclass
55class SwiGLUFillConfig(FillConfig):
56 """
57 SwiGLU fill config — forward (TASK_SWI_GLU) and backward (TASK_SWI_GLU_GRAD).
59 ``clamp_limit`` is serialized in ``TaskDesc.extra_value_0``. Zero keeps
60 the legacy unclamped path; a positive value enables clipped SwiGLU.
61 """
63 clamp_limit: float | None = None
65 def fill(
66 self,
67 cfg: RuntimeConfigC,
68 op,
69 tsv,
70 ) -> None:
71 """Serialize SwiGLU tasks into the runtime configuration.
73 Args:
74 cfg: Runtime configuration receiving task descriptors.
75 op: SwiGLU operator node to serialize.
76 tsv: Topology and task split values for the current graph.
77 """
78 task_type = (TaskType.TASK_SWI_GLU if op.op_type == OpType.SWIGLU
79 else TaskType.TASK_SWI_GLU_GRAD)
80 clamp_bits = _encode_clamp_limit(self.clamp_limit)
82 num_triggers = tsv.per_expert_seq // op.split_value
83 task_num = op.task_num
84 param = op.param_positions
86 for i in range(task_num):
87 task = TaskDescC()
88 task.task_type = task_type
89 task.task_aicore_type = TaskAiCoreType.TASK_AICORE_VECTOR
90 task.num_inputs = len(op.inputs)
91 task.num_outputs = len(op.outputs)
93 for j, spec in enumerate(op.inputs):
94 td = TensorDescC()
95 td.tensor_type = 1 # all SwiGLU inputs are tensor lists
96 td.data_type = spec.dtype_size
97 td.input_position = param[j]
98 td.base_ptr_offset = i * spec.shape[1] * op.split_value
99 td.dynamic_shape = int(spec.is_dynamic)
100 for k in range(min(len(spec.shape), MAX_TENSOR_DIMS)):
101 td.dim[k] = spec.shape[k]
102 task.inputs[j] = td
104 for j, spec in enumerate(op.outputs):
105 td = TensorDescC()
106 td.tensor_type = 1 # all SwiGLU outputs are tensor lists
107 td.data_type = spec.dtype_size
108 td.input_position = param[task.num_inputs + j]
109 td.base_ptr_offset = i * spec.shape[1] * op.split_value
110 td.dynamic_shape = int(spec.is_dynamic)
111 for k in range(min(len(spec.shape), MAX_TENSOR_DIMS)):
112 td.dim[k] = spec.shape[k]
113 task.outputs[j] = td
115 ev_idx = i // num_triggers
116 task.dependent_event = tsv.pre_pre_event_num + ev_idx + 1
117 task.trigger_event = tsv.pre_event_num + ev_idx + 1
118 cfg.all_event_num_triggers[task.trigger_event] = num_triggers
120 task.task_index = i
121 task.task_split_num = task_num
122 task.task_split_value = op.split_value
123 task.extra_value_0 = clamp_bits
124 task.tiling_data_position = op.tiling_position
126 cfg.all_tasks[tsv.pre_task_num + i] = task
127 cfg.vector_task_indices[tsv.pre_vector_task_num + i] = tsv.pre_task_num + i
129 cfg.task_index_num[1] += task_num
130 advance_tsv_vector(tsv, task_num, event_group_size=tsv.single_rank_expert_num)