| Files | Last commit | Last update |
|---|---|---|
| 4 months ago | ||
| 9 days ago | ||
| 1 month ago | ||
| 1 month ago | ||
| 1 month ago |
Mock HCCL Server Framework
English | 简体中文
Overview
This framework provides a general HCCL Server-side mock implementation that replaces the real CCU Server / HCCL communication backend in a single-device environment. It is independent of specific MC2 operators. Any operator that interacts with the HCCL Server through the workspace message protocol (such as AllGatherMatmul and MatmulReduceScatter) can use this framework for single-device testing.
Background: hcclClient / Server Architecture
In a real multi-device environment, the communication flow of MC2 operators is as follows:
Device (kernel) CCU (HCCL Server)
│ │
│ 1. Fill sendMsgs[slot] │
│ 2. Write commitTurnCnt[slot] │
│ ──────── workspace ──────────→ │
│ │ 3. Read commitTurnCnt and find a valid entry
│ │ 4. Read sendMsgs and perform collective communication
│ │ 5. Write finishedTurnCnt[slot]
│ ←──────── workspace ───────── │
│ 6. Poll finishedTurnCnt and continue │
│ │
The kernel submits communication requests to the server through the message protocol in the workspace. The server performs the actual cross-rank data movement and writes back the completion flag through the workspace. This workspace message protocol is operator-independent. Different MC2 operators (AllGather, ReduceScatter, and so on) use the same protocol format and differ only in the commType field.
This framework simulates the behavior of this server with a polling thread on the host side.
Directory structure:
tests/mc2_mock_test_frame/ # This directory: general mock framework
├── mock_framework.h # C++ core (MockContextBuilder + MultiRankMockContext + MockHcclServer)
├── mock_framework_test.cpp # C++ unit tests (protocol interaction verification)
├── mock_framework.cpp # pybind11 torch extension (Python binding)
└── README.md # This document
tests/torch_extension_tests/mc2/all_gather_matmul_v3/ # V3 operator tests
├── conftest.py # Common utilities for mock tests
├── test_all_gather_matmul_v3_mock.py # Single-rank mock test
├── test_all_gather_matmul_v3_mock_multirank.py # Multi-rank multi-stream mock test
└── test_all_gather_matmul_v3.py # Real multi-device test (torchrun)
1. Workspace Message Protocol
The core of what MockHcclServer simulates is the workspace message protocol. This is the kernel ↔ server communication interface defined by HCCL, and it is independent of specific operators.
1.1 Workspace Layout
The workspace must be 512B-aligned and contains 4 regions:
Workspace (512B-aligned):
┌──────────────────────────────────────┐
│ sendMsgs[64] (each 112B) │ +0x0000 Communication requests from kernel to server
├──────────────────────────────────────┤
│ recvMsgs[64] (each 112B) │ +0x1C00 Responses from server to kernel (reserved)
├──────────────────────────────────────┤
│ commitTurnCnt[64] (each 64B) │ +0x5800 Kernel commit flags
├──────────────────────────────────────┤
│ finishedTurnCnt[64](each 64B) │ +0x6800 Server completion flags
└──────────────────────────────────────┘
1.2 Message Structure
HcclMsg (112 bytes) — Communication request filled in by the kernel:
| Offset | Field | Description |
|---|---|---|
| +0x00 | commType (u32) | Communication type: AllGather=6, ReduceScatter=7 |
| +0x04 | opType (u32) | Reduce operation type |
| +0x08 | sendBuffer (u64) | Device source address |
| +0x10 | recvBuffer (u64) | Device destination address |
| +0x18 | dataCnt (u64) | Number of elements |
| +0x20 | strideCount (u64) | Stride between ranks in recvBuf |
| +0x28 | msgValid (u32) | HCCL_MSG_VALID_MASK (0x5CDF123A) |
| +0x2C | hcclDataType (u32) | Data type: FP32=0, FP16=1, BF16=5, ... |
| +0x30 | rest[64] | Remaining fields |
TurnCnt (64 bytes) — Commit/completion counters:
| Offset | Field | Description |
|---|---|---|
| +0x00 | valid (u64) | COMMIT_VALID_MASK (987654321) indicates validity |
| +0x08 | cnt (u64) | Commit/completion count |
| +0x10 | reserved[6] | Padding to cache line alignment |
1.3 Protocol Flow
Regular communication (AllGather/ReduceScatter):
kernel:
1. Fill in sendMsgs[slot] (commType, sendBuf, recvBuf, dataCnt, ...)
2. Write commitTurnCnt[slot].valid = COMMIT_VALID_MASK
server (MockHcclServer):
3. Poll commitTurnCnt; when a valid entry is found, read sendMsgs[slot]
4. Perform the operation according to commType (single device: D2D memcpy sendBuf → recvBuf)
5. Write finishedTurnCnt[slot].cnt = commitCnt
6. Clear commitTurnCnt[slot].valid
kernel:
7. Poll until finishedTurnCnt[slot].cnt >= the expected value, then continue
Finalize (communication-end handshake):
kernel Finalize():
1. Submit the finalize commit (the last message)
server:
2. Detect the finalize commit
3. Write finishedTurnCnt[slot].cnt = FINALIZE_FINISH_CNT (1234567899999999999)
kernel:
4. Detect FINALIZE_FINISH_CNT → the communication flow ends
2. Framework Components
2.1 MockHcclServer — General HCCL Server Mock
Core responsibility: Starts a polling thread on the host side, listens for communication requests in the workspace, and uses the passed-in input tensors of each rank to simulate real collective communication semantics.
During construction, you must pass in the input tensor of each rank (device pointers). When the server processes a communication request, it reads these tensors to simulate fetching data from remote ranks.
Supported communication types:
| commType | Operation | Mock Behavior |
|---|---|---|
| 6 (AllGather) | Concatenation of chunks from all ranks | rankInputs[r] → recvBuf[r * stride]; the local device uses sendBuf |
| 7 (ReduceScatter) | reduce + scatter | Read all ranks through D2H → element-wise reduce on the host → write back chunk[localRank] through H2D |
| 2 (AllReduce) | Full reduce | Read all ranks through D2H → element-wise reduce on the host → write back the full result through H2D |
| 12 (AlltoAll) | Block rearrangement | block[localRank] of each rank → recvBuf[r] |
Reduce operations: SUM(0) / PROD(1) / MAX(2) / MIN(3) are supported. The host side performs the computation after FP16/BF16 ↔ float conversion.
2.2 MockContextBuilder — Single-Rank HCCL Context Construction
Constructs the HcclA2CombineOpParam structure (that is, commContext) required by the kernel on the device side. The windowsIn[i] of all ranks point to the same device memory, which makes the flag synchronization mechanism of the 910B AIV mode self-consistent.
2.3 MultiRankMockContext — Multi-Rank Context Construction
Allocates N independent windows (184MB each) plus N contexts. The windowsIn[] entries in the contexts cross-reference each other. Together with concurrent kernels on multiple streams, this implements real multi-rank communication.
2.4 Python Binding (mock_framework.cpp)
Exposed to Python through pybind11:
import mock_hccl_ext
# Single-rank test
ctx = mock_hccl_ext.MockContext(rank_num=2, rank_id=0, device_id=0)
ctx.build()
server = mock_hccl_ext.MockServer(workspace_ptr=ctx.workspace_ptr(),
rank_inputs=[t0, t1], local_rank_id=0)
server.start()
# ... Call the operator ...
server.wait_for_finalize(slot=0, timeout_ms=10000)
server.stop()
# Multi-rank test
mctx = mock_hccl_ext.MultiRankContext(rank_num=2, device_id=0)
mctx.build()
ctx_r0 = mctx.context_tensor(0)
ctx_r1 = mctx.context_tensor(1)
# Launch on separate streams...
3. Unit Tests
mock_framework_test.cpp verifies the protocol correctness of the mock server (independent of specific operators):
| Test | Verification Point |
|---|---|
| TestContextBuilder | Context H2D/D2H; field readback is correct |
| TestServerProtocol | Manually write commitTurnCnt → the server responds with finishedTurnCnt |
| TestServerDataCopy | AllGather msg → the server performs the D2D copy → the recvBuf content is correct |
| TestFinalizeProtocol | regular msg + finalize commit → FINALIZE_FINISH_CNT response |
Compile and run:
ASCEND_HOME=~/Ascend/ascend-toolkit/latest
g++ -std=c++17 -O2 -I${ASCEND_HOME}/include \
mock_framework_test.cpp \
-L${ASCEND_HOME}/lib64 -lascendcl -lpthread \
-Wl,-rpath,${ASCEND_HOME}/lib64 \
-o /tmp/mock_framework_test
/tmp/mock_framework_test
4. How to Add Tests for a New Operator
This framework is operator-independent. Adding tests for a new MC2 operator requires only the following steps:
- Build the mock context —
MockContextBuilder.Build(rankNum, rankId) - Start the mock server —
MockHcclServer(workspace).Start() - Call the operator — pass the mock context to the operator as the commContext input
- Wait for completion —
WaitForFinalize()waits for the Finalize handshake of the kernel - Verify the result — check whether the computation output of the operator is correct
5. Known Limitations
| Limitation | Description |
|---|---|
| Single device only | Multiple devices require real HCCL or a multi-device mock |
| D2D memcpy replaces collective communication | A single device has no cross-rank data, so AllGather/ReduceScatter degrade to memcpy |
| No RDMA in the mock context | IbVerbsData / aiRMAInfo are 0; cross-node scenarios are not supported |
| Server polling latency | Host D2H/H2D polling has a latency of about 50 us and does not reflect real communication timing |
| Flag self-resolution does not verify timing | On a single-device mock, a flag is readable immediately after being written, so multi-device race conditions cannot be verified |