Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_multicore / tasks / gmm.py: 100%
77 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"""GMM fill config: all GroupedMatMul variants (fwd up_proj/down_proj, bwd act/gate/w1/w2 grad)."""
16from dataclasses import dataclass, field
17from typing import Set
19from hyper_multicore._core_spec import DEFAULT_CORE_SPEC
20from hyper_multicore.scheduler.config import (
21 TaskDescC, TensorDescC, RuntimeConfigC,
22 TaskAiCoreType, TaskType, TaskSplitValue,
23 MAX_TENSOR_DIMS,
24)
25from hyper_multicore.tasks.task_base import FillConfig
26from hyper_multicore.scheduler.graph import OperatorNode
27from hyper_multicore.tasks.utils import (
28 advance_tsv_cube, advance_tsv_cube_only,
29)
32@dataclass
33class GmmFillConfig(FillConfig):
34 """
35 GMM fill config covering all variants (fwd up_proj/down_proj, bwd act_grad/w2_grad/
36 gate_grad/w1_grad). Tensor attributes (tensor_type, dtype_size, is_dynamic,
37 transpose, shape) are read from TensorSpec.
39 offset_inputs : Set[int]
40 Input indices that receive base_ptr_offset and dynamic_shape.
41 activation GMMs (up_proj, down_proj, act_grad, gate_grad): {0}
42 weight-grad GMMs (w2_grad, w1_grad): {0, 1}
44 transpose_inputs : Set[int]
45 Additional transposed operands, without changing shared TensorSpec objects.
47 rank_in_event : bool
48 True → dependent_event adds single_rank_expert_num * rank_id.
49 GMM1 (fwd/bwd), GMM4/w2_grad (bwd).
50 False → no rank offset.
51 GMM2 (fwd/bwd), GMM3/w1_grad (bwd).
53 global_trigger : bool
54 False → trigger_event = pre_event_num + data_index + 1 (per-expert).
55 GMM1/GMM2 (activation-gradient path).
56 True → trigger_event = all_event_num (global).
57 GMM4/GMM3 (weight-gradient path).
59 out_offset : bool
60 True → out.base_ptr_offset = data_index * 4096 * shape[1].
61 False → 0 (weight-grad output writes to a dedicated buffer).
63 advance : "cube" | "cube_only" | "cube_custom"
64 "cube" — standard cube advance (also advances events).
65 "cube_only" — advances task/cube counters only (no event update).
66 Used by: GMM1 bwd.
67 "cube_custom" — manual: pre_task_num/pre_cube_task_num += task_num,
68 pre_pre_event_num = pre_event_num,
69 pre_event_num += event_delta.
70 Used by: GMM4 bwd, GMM3 bwd.
72 event_delta : int
73 Only used when advance="cube_custom".
74 GMM4 bwd: single_rank_expert_num. GMM3 bwd: 1.
76 num_cube_cores : int
77 Number of Cube cores.
78 """
79 offset_inputs: Set[int] = field(default_factory=lambda: {0})
80 # Shared activation specs retain their producer's interpretation.
81 transpose_inputs: Set[int] = field(default_factory=set)
82 rank_in_event: bool = False
83 global_trigger: bool = False
84 out_offset: bool = True
85 advance: str = "cube" # "cube" | "cube_only" | "cube_custom"
86 event_delta: int = 0 # only used when advance="cube_custom"
87 num_cube_cores: int = DEFAULT_CORE_SPEC.num_cube_cores
89 def fill(self, cfg: RuntimeConfigC, op: OperatorNode, tsv: TaskSplitValue) -> None:
90 """Serialize operand interpretation and event dependencies.
92 Args:
93 cfg: Runtime descriptor to populate.
94 op: Operator supplying operands and split metadata.
95 tsv: Current task indices and expert dimensions.
96 """
97 task_num = op.task_num
98 param = op.param_positions
99 glist_j = len(op.inputs) - 1 # last input is always group_list
101 for i in range(task_num):
102 data_index = i // self.num_cube_cores
103 task = TaskDescC()
104 task.task_type = TaskType.TASK_GROUPED_MATMUL
105 task.task_aicore_type = TaskAiCoreType.TASK_AICORE_CUBE
106 task.num_inputs = len(op.inputs)
107 task.num_outputs = len(op.outputs)
109 for j, spec in enumerate(op.inputs):
110 td = TensorDescC()
111 td.input_position = param[j]
112 td.dynamic_shape = 0
113 td.base_ptr_offset = 0
115 if j == glist_j: # group_list: fixed type=0, dtype int64
116 td.tensor_type = 0
117 td.data_type = spec.dtype_size
118 else: # x or weight: tensor_type from TensorSpec
119 td.tensor_type = spec.tensor_type
120 td.data_type = spec.dtype_size
122 if j in self.offset_inputs:
123 td.base_ptr_offset = data_index * 4096 * spec.shape[1]
124 td.dynamic_shape = int(spec.is_dynamic)
126 td.transpose_flag = int(spec.transpose or j in self.transpose_inputs)
127 for k in range(min(len(spec.shape), MAX_TENSOR_DIMS)):
128 td.dim[k] = spec.shape[k]
129 task.inputs[j] = td
131 out_spec = op.outputs[0]
132 out = TensorDescC()
133 out.tensor_type = out_spec.tensor_type
134 out.data_type = out_spec.dtype_size
135 out.input_position = param[task.num_inputs]
136 out.dynamic_shape = int(out_spec.is_dynamic)
137 out.base_ptr_offset = (data_index * 4096 * out_spec.shape[1]
138 if self.out_offset else 0)
139 if self.out_offset: # C++ fills dims only for activation outputs
140 for k in range(min(len(out_spec.shape), MAX_TENSOR_DIMS)):
141 out.dim[k] = out_spec.shape[k]
142 task.outputs[0] = out
144 dep_extra = (tsv.single_rank_expert_num * tsv.rank_id
145 if self.rank_in_event else 0)
146 task.dependent_event = tsv.pre_pre_event_num + dep_extra + data_index + 1
147 if self.global_trigger:
148 task.trigger_event = tsv.all_event_num
149 else:
150 task.trigger_event = tsv.pre_event_num + data_index + 1
151 cfg.all_event_num_triggers[task.trigger_event] = self.num_cube_cores
153 task.task_index = i
154 task.task_split_num = task_num
155 task.task_split_value = op.split_value
156 task.tiling_data_position = op.tiling_position
158 cfg.all_tasks[tsv.pre_task_num + i] = task
159 cfg.cube_task_indices[tsv.pre_cube_task_num + i] = tsv.pre_task_num + i
161 cfg.task_index_num[0] += task_num
162 if self.advance == "cube":
163 advance_tsv_cube(tsv, task_num, event_group_size=task_num // self.num_cube_cores)
164 elif self.advance == "cube_only":
165 advance_tsv_cube_only(tsv, task_num)
166 else: # "cube_custom"
167 tsv.pre_task_num += task_num
168 tsv.pre_cube_task_num += task_num
169 tsv.pre_pre_event_num = tsv.pre_event_num
170 tsv.pre_event_num += self.event_delta