Commit 6ad4d07
[BREAKING][refactor] Convert BatchMeta to columnar layout; enable zero-copy serialization by default
Co-authored-by: 看我72遍<m.pb@msn.com>
# message auto-generated for no-merge-commit merge:
!28 merge refactor/columnar-batchmeta-zero-copy into main
[BREAKING][refactor] Convert BatchMeta to columnar layout; enable zero-copy serialization by default
Created-by: mpb159753
Commit-by: 看我72遍
Merged-by: ascend-robot
Description: # Columnar BatchMeta + Zero-Copy Default
## 1. Context & Motivation
Closes: **[refactor] Convert BatchMeta from row-oriented to column-oriented layout**
The current `BatchMeta` uses a **row-oriented** design (`BatchMeta` → `List[SampleMeta]` → `Dict[str, FieldMeta]`), which introduces three scaling issues in high-throughput scenarios:
1. **O(B×F) Complexity**: Critical paths (`build_storage_meta_groups`, `add_fields`, `_filter_storage_data`) involve nested loops over every sample × every field, incurred multiple times per PUT.
2. **Small Object Explosion**: A batch of 1024 samples with 10 fields creates **10,000+ Python objects**, causing GC pressure and unpredictable tail latency.
3. **Redundant Transmission**: Schema info (dtype, shape) is duplicated per sample; row-oriented serialization produces fragmented ZMQ frames, preventing zero-copy optimization.
This PR refactors `BatchMeta` to a **column-oriented** (structure-of-arrays) design, reducing metadata complexity from **O(B×F)** to **O(B) + O(F)**, and enables zero-copy serialization by default with automatic pickle fallback.
## 2. Key Changes
### 2.1 Columnar BatchMeta (`metadata.py`)
| Aspect | Before (Row-oriented) | After (Column-oriented) |
|:---|:---|:---|
| Structure | `BatchMeta.samples: List[SampleMeta]` | Flat arrays: `global_indexes`, `partition_ids`, `production_status` |
| Field metadata | Per-sample `FieldMeta` objects (**B×F** instances) | Shared `field_schema` dict (**F** entries) |
| Status check | Loop over samples **O(B)** | `np.all()` on ndarray **O(1)** |
| Classes | `BatchMeta`, `SampleMeta`, `FieldMeta` | `BatchMeta` only |
- **Removed**: `SampleMeta` and `FieldMeta` classes entirely
- **Added**: `field_schema` dict with three field types: Regular Tensor, Nested Tensor (`is_nested`), Non-Tensor (`is_non_tensor`)
- **Vectorized**: `production_status` as `np.ndarray(int8)` — enables O(1) readiness checks via `np.all()`
### 2.2 Zero-Copy Serialization Default (`serial_utils.py`)
- Zero-copy serialization is now the **default behavior** (previously gated by env var)
- Automatic **fallback to pickle** on serialization failure, with one-time warning
- Removed `ZERO_COPY_SERIALIZATION` environment variable switch
### 2.3 Storage & Transport Adaptation
- **`simple_backend.py`** / **`simple_backend_manager.py`** / **`controller.py`**: Adapted to columnar API; `clear()` uses `del` instead of `None` assignment to reduce memory fragmentation
- **`zmq_utils.py`**: ZMQ transport uses new serialization utilities; frame count reduced from **O(B)** to **F+1** (one metadata header + one per field)
### 2.4 Test Suite
- **`test_metadata.py`**: Fully rewritten for columnar API (net -799 lines)
- All other test files adapted to new `BatchMeta` constructor
## 3. Benchmark Results
Tests conducted in Docker (single-node Ray) across 7 payload sizes. Three configurations compared:
- **main-no-zerocopy**: Baseline (row-oriented, pickle serialization)
- **main-zero-copy**: Row-oriented + custom zero-copy serialization (previous PR)
- **columnar-batchmeta-zero-copy**: This PR (columnar + zero-copy default)
### Throughput Comparison (Gbps)
| Config | Operation | main (No ZC) | main (ZC) | **This PR** | vs main (ZC) |
|:---|:---|:---|:---|:---|:---|
| **debug** (0.05 MB) | PUT | 0.004 | 0.005 | **0.005** | +17% |
| | GET | 0.005 | 0.006 | **0.008** | +33% |
| **tiny** (0.6–1.5 MB) | PUT | 0.055 | 0.058 | **0.119** | +106% |
| | GET | 0.057 | 0.086 | **0.220** | +157% |
| **small** (50–150 MB) | PUT | 0.89 | 1.56 | **4.71** | +202% |
| | GET | 1.14 | 2.53 | **5.87** | +132% |
| **medium** (0.5–1.5 GB) | PUT | 2.91 | 6.82 | **18.26** | +168% |
| | GET | 3.31 | 6.95 | **8.83** | +27% |
| **large** (3–6 GB) | PUT | 4.32 | 12.34 | **26.11** | +112% |
| | GET | 4.57 | 8.41 | **9.60** | +14% |
| **xlarge** (6–13 GB) | PUT | 4.37 | 11.86 | **25.74** | +117% |
| | GET | 4.67 | 8.47 | **10.20** | +20% |
| **huge** (10–25 GB) | PUT | 4.31 | 11.08 | **23.89** | +116% |
| | GET | 4.49 | 5.50 | **9.70** | +76% |
### Speedup vs Baseline (main-no-zerocopy)
| Config | PUT Speedup | GET Speedup |
|:---|:---:|:---:|
| debug | 1.2× | 1.5× |
| tiny | **2.2×** | **3.8×** |
| small | **5.3×** | **5.2×** |
| medium | **6.3×** | **2.7×** |
| large | **6.0×** | **2.1×** |
| xlarge | **5.9×** | **2.2×** |
| huge | **5.5×** | **2.2×** |
### Visualization




### Resource Usage
Columnar layout reduces CPU time by eliminating per-sample object creation and pickle overhead:
| Config | main (No ZC) CPU-sec | main (ZC) CPU-sec | **This PR** CPU-sec | Reduction vs main (ZC) |
|:---|:---|:---|:---|:---|
| **large** | 850 | 572 | **574** | ~0% (2× throughput) |
| **xlarge** | 1570 | 1166 | **1009** | **-13%** (2× throughput) |
| **huge** | 2569 | 2387 | **1936** | **-19%** (2× throughput) |
> Note: CPU time is comparable or lower despite processing **2× more data** per unit time.
## 4. API Breaking Changes
| Item | Before | After |
|:---|:---|:---|
| `BatchMeta.samples` | `List[SampleMeta]` | **Removed** |
| `SampleMeta` class | Available | **Removed** |
| `FieldMeta` class | Available | **Removed** |
| `sample.fields['x'].dtype` | Per-sample access | `batch.field_schema['x']['dtype']` |
| Constructor | `BatchMeta(samples=[...])` | `BatchMeta(global_indexes=..., partition_ids=..., field_schema=..., production_status=...)` |
## 5. Files Changed
```
16 files changed, 1369 insertions(+), 2168 deletions(-)
```
| Category | Files | Summary |
|:---|:---|:---|
| Core | `metadata.py` | Columnar BatchMeta rewrite |
| Serialization | `serial_utils.py`, `zmq_utils.py` | Zero-copy default + ZMQ adaptation |
| Storage | `simple_backend.py`, `simple_backend_manager.py`, `base.py` | Columnar API adaptation |
| Controller | `controller.py` | Columnar API adaptation |
| Tests | `test_metadata.py` + 7 test files | Full rewrite + adaptation |
| Scripts | `put_benchmark.py` | Minor adjustments |
## 6. Conclusion
The columnar `BatchMeta` refactoring combined with default zero-copy serialization delivers:
- **PUT throughput**: Up to **6.3×** improvement over baseline, **+100–200%** over previous zero-copy PR
- **GET throughput**: Up to **5.2×** improvement over baseline, **+14–157%** over previous zero-copy PR
- **CPU efficiency**: Comparable or lower CPU time despite 2× higher throughput
- **Code reduction**: Net **-799 lines** of metadata-related code
See merge request: Ascend/TransferQueue!281 parent 87d7e13 commit 6ad4d07
21 files changed
Lines changed: 2166 additions & 2612 deletions
File tree
- scripts
- tests
- e2e
- transfer_queue
- storage
- managers
- utils
- tutorial
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
42 | 39 | | |
| 40 | + | |
43 | 41 | | |
44 | 42 | | |
45 | 43 | | |
| |||
309 | 307 | | |
310 | 308 | | |
311 | 309 | | |
312 | | - | |
| 310 | + | |
313 | 311 | | |
314 | 312 | | |
315 | 313 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
420 | 420 | | |
421 | 421 | | |
422 | 422 | | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
427 | 435 | | |
428 | | - | |
429 | | - | |
430 | | - | |
431 | | - | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
432 | 439 | | |
433 | 440 | | |
434 | 441 | | |
| |||
641 | 648 | | |
642 | 649 | | |
643 | 650 | | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
644 | 705 | | |
645 | 706 | | |
0 commit comments