mxframe 0.2.1__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mxframe-0.3.0/CHANGELOG.md +199 -0
- mxframe-0.3.0/PKG-INFO +152 -0
- mxframe-0.3.0/README.md +119 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/__init__.py +1 -1
- {mxframe-0.2.1 → mxframe-0.3.0}/aot_kernels.py +193 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/custom_ops.py +134 -79
- {mxframe-0.2.1 → mxframe-0.3.0}/docs/vision-and-architecture.md +17 -40
- mxframe-0.3.0/kernels.mojopkg +0 -0
- mxframe-0.3.0/kernels_aot/libmxkernels_aot.so +0 -0
- mxframe-0.3.0/kernels_aot/libmxkernels_aot_gpu.so +0 -0
- mxframe-0.3.0/mxframe.egg-info/PKG-INFO +152 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/mxframe.egg-info/requires.txt +1 -1
- {mxframe-0.2.1 → mxframe-0.3.0}/pyproject.toml +2 -2
- mxframe-0.2.1/CHANGELOG.md +0 -64
- mxframe-0.2.1/PKG-INFO +0 -565
- mxframe-0.2.1/README.md +0 -532
- mxframe-0.2.1/kernels.mojopkg +0 -0
- mxframe-0.2.1/kernels_aot/libmxkernels_aot.so +0 -0
- mxframe-0.2.1/kernels_aot/libmxkernels_aot_gpu.so +0 -0
- mxframe-0.2.1/mxframe.egg-info/PKG-INFO +0 -565
- {mxframe-0.2.1 → mxframe-0.3.0}/MANIFEST.in +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/_modidx.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/compiler.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/kernels_aot/__init__.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/lazy_expr.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/lazy_frame.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/mxframe.egg-info/SOURCES.txt +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/mxframe.egg-info/dependency_links.txt +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/mxframe.egg-info/top_level.txt +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/optimizer.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/plan_validation.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/setup.cfg +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/setup.py +0 -0
- {mxframe-0.2.1 → mxframe-0.3.0}/sql_frontend.py +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# 📋 Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to MXFrame are documented here.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## [0.3.0] — 2026-07-10
|
|
9
|
+
|
|
10
|
+
### 📚 Docs & Benchmarks
|
|
11
|
+
- README restructured: 543 lines → 119 lines. Intro, quick start, and 4-row teaser only — all detail moved to dedicated docs.
|
|
12
|
+
- New `docs/benchmarks.md`: full 22-query TPC-H tables (1 M + 10 M rows), Mojo kernel catalogue, current limitations, roadmap, and reproduce instructions.
|
|
13
|
+
- New `docs/api.md`: LazyFrame method reference, expression syntax, SQL frontend, supported operations, project structure.
|
|
14
|
+
- `docs/vision-and-architecture.md`: fixed garbled sections 2.5/2.6/3; success criteria table repaired; all milestones marked ✅.
|
|
15
|
+
- `docs/archive/` added to `.gitignore` — old dev notes moved there, not published.
|
|
16
|
+
- All stale `Mojo 0.26.2` / `MAX Graph shape-cached join` references updated to reflect v0.2.3 reality (Mojo 26.4, AOT ctypes everywhere).
|
|
17
|
+
|
|
18
|
+
### 📊 Benchmark updates
|
|
19
|
+
- Q5/Q7/Q8/Q10/Q13/Q19 re-measured with per-run join-cache clearing (fresh-join). Previous v0.2.0 numbers for those queries were warm join-cache hits.
|
|
20
|
+
- Summary corrected: CPU 20/22 (Q13 loses fresh-join), GPU 12/22 (Q5/Q7 no longer win at 1 M without cache warmup).
|
|
21
|
+
- Q8 GPU marked `—` (MAX Graph `year()` groupby JIT too slow to benchmark; Phase 6 target).
|
|
22
|
+
|
|
23
|
+
### 🔨 Infrastructure
|
|
24
|
+
- `modular >= 26.4` requirement added to `pyproject.toml` runtime deps and Dependencies table in README.
|
|
25
|
+
- `docs/archive/` gitignored; previously committed archive files removed from history.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## [0.2.3] — 2026-07-09
|
|
30
|
+
|
|
31
|
+
### ⚡ Performance
|
|
32
|
+
- **Phase 4 — Device-resident GPU join pipeline** (`join_count_i32_gpu` + `join_scatter_i32_gpu`):
|
|
33
|
+
GPU inner joins now bypass MAX Graph JIT entirely. Cold-start join latency drops from ~300 ms (MAX session init + JIT) to ~70 ms. `AOTKernelsGPU.hash_join()` caches key arrays via `_cached_upload`; `AOTKernelsGPU.gather_table()` gathers all numeric columns with a single shared device-resident index upload.
|
|
34
|
+
- **Phase 5 — GPU sort + top-k** (`sort_topk_i32_gpu`): `ORDER BY … LIMIT k` fuses sort and limit in a single AOT bitonic sort kernel, downloading only `k × 4` bytes instead of `N × 4`. `_apply_post_ops_custom` peek-ahead passes `topk=k` directly to the sort kernel.
|
|
35
|
+
- **Phase 3 — Vectorised rank mapping**: `_encode_sort_key` replaces the per-unique-value Python `for` loop with a single vectorised NumPy scatter (`rank_of[sorted_order] = np.arange(n_unique)`). ~1.5× speedup for sort-key encoding at 5 M rows.
|
|
36
|
+
|
|
37
|
+
### 🛠 Fixed
|
|
38
|
+
- **GPU sort+limit crash**: `_apply_sort_custom` was calling `_gpu_gather_table` which referenced `gather_f32` as a MAX Graph custom op — that kernel was never registered in the mojopkg. Any `ORDER BY` on `device="gpu"` would crash. Now routes through `_aot_gpu.gather_table` (AOT ctypes, no MAX Graph).
|
|
39
|
+
- `_apply_sort_custom` CPU path now uses `np.argpartition` (O(N) partial sort) when `topk < N`, instead of a full O(N log N) argsort.
|
|
40
|
+
|
|
41
|
+
### 🔨 Infrastructure
|
|
42
|
+
- **Mojo/MAX 26.4 migration**: all `kernels/*.mojo` and `kernels_aot/*.mojo` migrated from 26.2 API (`fn` → `def`, `from tensor import` → `from extensibility import`, `DeviceContextPtr` → `DeviceContext`, `enqueue_function_experimental` → `enqueue_function`).
|
|
43
|
+
- **`kernels/_atomic.mojo`** (new): drop-in replacement for the missing `std.os.atomic.Atomic`. Implements `fetch_add`, `min`, `max`, `compare_exchange` via MLIR `llvm.atomicrmw` / `llvm.cmpxchg` instructions — portable across NVIDIA and AMD; works in both `mojo package` (JIT) and `mojo build --emit shared-lib` (AOT) contexts.
|
|
44
|
+
- All compiled artifacts rebuilt with Mojo 1.0.0b2 (modular 26.4): `kernels.mojopkg`, `libmxkernels_aot.so`, `libmxkernels_aot_gpu.so`.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## [0.2.2] — 2026-07-08
|
|
49
|
+
|
|
50
|
+
### 🔨 Infrastructure
|
|
51
|
+
- First release targeting **Mojo/MAX 26.4** (`modular = "26.4.*"` in `pixi.toml`).
|
|
52
|
+
- `_atomic.mojo` shim introduced to replace the removed `std.os.atomic` module.
|
|
53
|
+
- All kernel source files migrated to 26.4 syntax; compiled artefacts rebuilt.
|
|
54
|
+
- `pyproject.toml` `runtime` extra pinned to `modular>=26.4` to prevent 26.2 wheels from being installed by Colab/pip users.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## [0.2.1] — 2026-06-xx
|
|
59
|
+
|
|
60
|
+
### 🔨 Infrastructure
|
|
61
|
+
- TestPyPI re-upload to validate wheel packaging. No functional changes.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## [0.2.0] — 2026-05-xx
|
|
66
|
+
|
|
67
|
+
### ✨ Added
|
|
68
|
+
- **Phase 1 — GPU buffer cache + masked global min/max**:
|
|
69
|
+
- `masked_global_min_f32_gpu` / `masked_global_max_f32_gpu` Mojo AOT kernels.
|
|
70
|
+
- `AOTKernelsGPU` device-buffer cache (`_cached_upload`, eviction, `clear_buf_cache`) — eliminates redundant PCIe uploads on repeated hot queries.
|
|
71
|
+
- `group_mean_f32` GPU kernel (sum + count on GPU, divide on CPU).
|
|
72
|
+
- Masked global min/max fast-paths wired in `custom_ops.py`.
|
|
73
|
+
- **Phase 2 — Masked global aggregation for any expression**:
|
|
74
|
+
- `_compute_masked_global_agg` extended to handle any inner expression via `_eval_expr_arrow` (e.g. `a*(1-b)`, `case_when`, `startswith`, `isin`) — SUM reduction stays GPU-resident.
|
|
75
|
+
- Join-only plans emit `"join_mojo_shortcut"` provenance (not `"pyarrow_shortcut"`) — Q19 restructured to single-pass join+filter+global_agg.
|
|
76
|
+
- `audit_gpu_paths.py` updated: `join_mojo_shortcut` counted as Mojo-backed.
|
|
77
|
+
- **Phase 3 — GPU integer key encoding**:
|
|
78
|
+
- `group_encode_i32_gpu` open-addressing hash-table kernel for integer group keys; replaces PyArrow `dictionary_encode` for integer-keyed group-by on GPU.
|
|
79
|
+
- **Audit tool** (`scripts/audit_gpu_paths.py`): classifies each of 22 TPC-H queries as `GPU-CLEAN` / `MOJO-CPU` / `FALLBACK` via `last_compile_provenance["path"]`.
|
|
80
|
+
- **Interactive visualiser** (`visualize/mxframe_pipeline.html`): step-through of how a Python query becomes a plan tree and dispatches to GPU kernels.
|
|
81
|
+
|
|
82
|
+
### ⚡ Performance
|
|
83
|
+
- **22/22 TPC-H queries GPU-CLEAN** (100% Mojo-backed on GPU, zero PyArrow fallbacks in the reduction and join hot paths).
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## [0.1.2] — 2026-04-22
|
|
88
|
+
|
|
89
|
+
### 🛠 Fixed
|
|
90
|
+
- `pip install "mxframe[runtime]"` now gives a working install. The `[runtime]` extra pulls `modular>=25.5`, which provides the `max.engine` / `max.driver` modules that `mxframe.compiler` imports at module load. (Pixi users get `modular` from the Modular conda channel and should install `mxframe` without the extra.)
|
|
91
|
+
- `sqlglot` import in `mxframe.sql_frontend` is now lazy: `import mxframe` no longer requires the `[sql]` extra. Calling `mxframe.sql(…)` without `sqlglot` installed raises a clear `ImportError` with the install hint.
|
|
92
|
+
- `__init__.py` `__version__` now matches `pyproject.toml`.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## [0.1.1] — 2026-04-22
|
|
97
|
+
|
|
98
|
+
### 🛠 Fixed
|
|
99
|
+
- Packaging: `readme` now points to `README.md` so PyPI shows the full project page with benchmarks and quickstart (was accidentally showing the internal vision/architecture doc)
|
|
100
|
+
- CI: `AOTKernelsGPU` init no longer hard-fails on CPU-only runners (`CUDA driver unavailable` is caught, `self._aot_gpu` falls back to `None`)
|
|
101
|
+
- CI: `_find_kernels_path()` uses `Path(__file__).resolve().parent` directly, removing the stale `/home/ablearn/mxdf/…` dev fallback that surfaced in installed wheels
|
|
102
|
+
- Bug: `NameError: cache_key_count` in `_hash_join_mojo_cpu` MAX Graph fallback
|
|
103
|
+
- Tests: `scripts/_test_phase0_custom_ops.py` and `_test_phase1.py` no longer hard-code a developer's kernels path; they use the auto-detected default
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## [0.1.0] — 2026-04-20
|
|
108
|
+
|
|
109
|
+
### ✨ Added
|
|
110
|
+
- **All 22 TPC-H queries** on CPU and GPU AOT paths
|
|
111
|
+
- **GPU LEFT JOIN** — `join_count_left` + `join_scatter_left` Mojo kernels wired to Python (Q13)
|
|
112
|
+
- `bench_simple.py` — clean 4-column benchmark (Pandas | Polars | MX CPU | MX GPU)
|
|
113
|
+
- `--queries` and `--runs` flags for targeted benchmarking
|
|
114
|
+
|
|
115
|
+
### ⚡ Performance
|
|
116
|
+
- **Q22** phone prefix anti-join: vectorized via `pc.utf8_slice_codeunits` + `pc.is_in` + `np.isin` — 3.6× faster than Polars CPU (was 10× **slower**)
|
|
117
|
+
- **Q20** semi-join chain: eliminated `.to_pandas()` Pandas detour — 8.7× faster than Polars (was comparable)
|
|
118
|
+
- **Q21** EXISTS+NOT EXISTS: replaced `.to_pandas().groupby.nunique()` with NumPy composite key dedup
|
|
119
|
+
- **Q18** large volume customers: replaced `.to_pylist()` semi-join with Mojo join — semi-join now uses AOT kernel path
|
|
120
|
+
- **Q15** argmax supplier: replaced `0.9999 * max_rev` tolerance hack with exact `pc.equal()` on float32
|
|
121
|
+
- **Q13** LEFT JOIN: removed `.to_pandas()` groupby detour — now fully on GPU AOT path (19ms CPU, 29ms GPU vs 25ms Polars)
|
|
122
|
+
|
|
123
|
+
### 🐛 Fixed
|
|
124
|
+
- `not use_gpu_filter` gate bug in `custom_ops.py` section 4.6 that blocked GPU filter path
|
|
125
|
+
- Q7 nation pre-join cache key now uses `id()` preventing cache misses on repeated hot calls
|
|
126
|
+
|
|
127
|
+
### 🏗️ Infrastructure
|
|
128
|
+
- `pyproject.toml` updated with full metadata, dependencies, optional extras, package-data for `.so` files
|
|
129
|
+
- `CONTRIBUTING.md` — developer guide with kernel writing tutorial
|
|
130
|
+
- `PUBLISHING.md` — step-by-step pip release guide
|
|
131
|
+
- GitHub Actions: `test.yml` (CI), `publish.yml` (PyPI via OIDC)
|
|
132
|
+
|
|
133
|
+
### 📊 Benchmark Summary (1M and 10M rows, all 22 queries, warm median of 3)
|
|
134
|
+
|
|
135
|
+
See the full table in [README.md § TPC-H Benchmark](README.md#-tpc-h-benchmark--all-22-queries),
|
|
136
|
+
sourced from `scripts/bench_results_1M.csv` and `scripts/bench_results_10M.csv`.
|
|
137
|
+
|
|
138
|
+
- **Correctness:** 22/22 queries pass on CPU and GPU paths
|
|
139
|
+
- **MX CPU wins vs Polars:** **21/22** at 1 M, **18/22** at 10 M
|
|
140
|
+
— headline: **Q9 128× · Q12 89× · Q7 42× · Q8 31× · Q17 24× · Q5 22×** (at 10 M)
|
|
141
|
+
- **MX GPU wins vs Polars:** **16/22** at 1 M, **15/22** at 10 M
|
|
142
|
+
— headline: **Q12 26.5× · Q9 12× · Q8 10.8× · Q17 9.7× · Q7 4.7×** (at 10 M)
|
|
143
|
+
- **Remaining losses (Q4, Q6, Q13, Q21):** ops that still route through PyArrow fallback — kernel replacements tracked in `roadmap.md`
|
|
144
|
+
|
|
145
|
+
### 🛠 Fixed
|
|
146
|
+
- `pip install "mxframe[runtime]"` now gives a working install. The `[runtime]` extra pulls `modular>=25.5`, which provides the `max.engine` / `max.driver` modules that `mxframe.compiler` imports at module load. (Pixi users get `modular` from the Modular conda channel and should install `mxframe` without the extra.)
|
|
147
|
+
- `sqlglot` import in `mxframe.sql_frontend` is now lazy: `import mxframe` no longer requires the `[sql]` extra. Calling `mxframe.sql(…)` without `sqlglot` installed raises a clear `ImportError` with the install hint.
|
|
148
|
+
- `__init__.py` `__version__` now matches `pyproject.toml`.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## [0.1.1] — 2026-04-22
|
|
153
|
+
|
|
154
|
+
### 🛠 Fixed
|
|
155
|
+
- Packaging: `readme` now points to `README.md` so PyPI shows the full project page with benchmarks and quickstart (was accidentally showing the internal vision/architecture doc)
|
|
156
|
+
- CI: `AOTKernelsGPU` init no longer hard-fails on CPU-only runners (`CUDA driver unavailable` is caught, `self._aot_gpu` falls back to `None`)
|
|
157
|
+
- CI: `_find_kernels_path()` uses `Path(__file__).resolve().parent` directly, removing the stale `/home/ablearn/mxdf/…` dev fallback that surfaced in installed wheels
|
|
158
|
+
- Bug: `NameError: cache_key_count` in `_hash_join_mojo_cpu` MAX Graph fallback
|
|
159
|
+
- Tests: `scripts/_test_phase0_custom_ops.py` and `_test_phase1.py` no longer hard-code a developer's kernels path; they use the auto-detected default
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## [0.1.0] — 2026-04-20
|
|
164
|
+
|
|
165
|
+
### ✨ Added
|
|
166
|
+
- **All 22 TPC-H queries** on CPU and GPU AOT paths
|
|
167
|
+
- **GPU LEFT JOIN** — `join_count_left` + `join_scatter_left` Mojo kernels wired to Python (Q13)
|
|
168
|
+
- `bench_simple.py` — clean 4-column benchmark (Pandas | Polars | MX CPU | MX GPU)
|
|
169
|
+
- `--queries` and `--runs` flags for targeted benchmarking
|
|
170
|
+
|
|
171
|
+
### ⚡ Performance
|
|
172
|
+
- **Q22** phone prefix anti-join: vectorized via `pc.utf8_slice_codeunits` + `pc.is_in` + `np.isin` — 3.6× faster than Polars CPU (was 10× **slower**)
|
|
173
|
+
- **Q20** semi-join chain: eliminated `.to_pandas()` Pandas detour — 8.7× faster than Polars (was comparable)
|
|
174
|
+
- **Q21** EXISTS+NOT EXISTS: replaced `.to_pandas().groupby.nunique()` with NumPy composite key dedup
|
|
175
|
+
- **Q18** large volume customers: replaced `.to_pylist()` semi-join with Mojo join — semi-join now uses AOT kernel path
|
|
176
|
+
- **Q15** argmax supplier: replaced `0.9999 * max_rev` tolerance hack with exact `pc.equal()` on float32
|
|
177
|
+
- **Q13** LEFT JOIN: removed `.to_pandas()` groupby detour — now fully on GPU AOT path (19ms CPU, 29ms GPU vs 25ms Polars)
|
|
178
|
+
|
|
179
|
+
### 🐛 Fixed
|
|
180
|
+
- `not use_gpu_filter` gate bug in `custom_ops.py` section 4.6 that blocked GPU filter path
|
|
181
|
+
- Q7 nation pre-join cache key now uses `id()` preventing cache misses on repeated hot calls
|
|
182
|
+
|
|
183
|
+
### 🏗️ Infrastructure
|
|
184
|
+
- `pyproject.toml` updated with full metadata, dependencies, optional extras, package-data for `.so` files
|
|
185
|
+
- `CONTRIBUTING.md` — developer guide with kernel writing tutorial
|
|
186
|
+
- `PUBLISHING.md` — step-by-step pip release guide
|
|
187
|
+
- GitHub Actions: `test.yml` (CI), `publish.yml` (PyPI via OIDC)
|
|
188
|
+
|
|
189
|
+
### 📊 Benchmark Summary (1M and 10M rows, all 22 queries, warm median of 3)
|
|
190
|
+
|
|
191
|
+
See the full table in [README.md § TPC-H Benchmark](README.md#-tpc-h-benchmark--all-22-queries),
|
|
192
|
+
sourced from `scripts/bench_results_1M.csv` and `scripts/bench_results_10M.csv`.
|
|
193
|
+
|
|
194
|
+
- **Correctness:** 22/22 queries pass on CPU and GPU paths
|
|
195
|
+
- **MX CPU wins vs Polars:** **21/22** at 1 M, **18/22** at 10 M
|
|
196
|
+
— headline: **Q9 128× · Q12 89× · Q7 42× · Q8 31× · Q17 24× · Q5 22×** (at 10 M)
|
|
197
|
+
- **MX GPU wins vs Polars:** **16/22** at 1 M, **15/22** at 10 M
|
|
198
|
+
— headline: **Q12 26.5× · Q9 12× · Q8 10.8× · Q17 9.7× · Q7 4.7×** (at 10 M)
|
|
199
|
+
- **Remaining losses (Q4, Q6, Q13, Q21):** ops that still route through PyArrow fallback — kernel replacements tracked in `roadmap.md`
|
mxframe-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mxframe
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: GPU-accelerated DataFrame engine: Python ergonomics + Mojo AOT kernels, cross-vendor (NVIDIA/AMD/Apple).
|
|
5
|
+
Author-email: Abhishek Sreesaila <abhisheksreesaila@users.noreply.github.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/abhisheksreesaila/mxframe
|
|
8
|
+
Project-URL: Repository, https://github.com/abhisheksreesaila/mxframe
|
|
9
|
+
Keywords: dataframe,gpu,mojo,arrow,analytics,tpch
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
16
|
+
Classifier: Topic :: Database
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: pyarrow>=14.0
|
|
20
|
+
Requires-Dist: numpy>=1.24
|
|
21
|
+
Requires-Dist: pandas>=2.0
|
|
22
|
+
Provides-Extra: runtime
|
|
23
|
+
Requires-Dist: modular>=26.4; extra == "runtime"
|
|
24
|
+
Provides-Extra: polars
|
|
25
|
+
Requires-Dist: polars>=0.20; extra == "polars"
|
|
26
|
+
Provides-Extra: sql
|
|
27
|
+
Requires-Dist: sqlglot>=25.0; extra == "sql"
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
30
|
+
Requires-Dist: polars>=0.20; extra == "dev"
|
|
31
|
+
Requires-Dist: sqlglot>=25.0; extra == "dev"
|
|
32
|
+
Requires-Dist: duckdb>=0.9; extra == "dev"
|
|
33
|
+
|
|
34
|
+
# 🚀 MXFrame
|
|
35
|
+
|
|
36
|
+
> **GPU-accelerated DataFrames — Python ergonomics, Mojo speed, every GPU.**
|
|
37
|
+
|
|
38
|
+
MXFrame is a DataFrame query engine that pairs a Polars-style Python API with
|
|
39
|
+
pre-compiled Mojo AOT kernels. The same code runs on **NVIDIA, AMD, and Apple Silicon** —
|
|
40
|
+
no CUDA required, no JIT compilation at query time.
|
|
41
|
+
|
|
42
|
+
[](docs/benchmarks.md)
|
|
43
|
+
[](pyproject.toml)
|
|
44
|
+
[](pyproject.toml)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ✨ Why MXFrame?
|
|
50
|
+
|
|
51
|
+
| | pandas | Polars | cuDF (Rapids) | **MXFrame** |
|
|
52
|
+
|---|---|---|---|---|
|
|
53
|
+
| GPU support | ❌ | ❌ | ✅ NVIDIA only | ✅ **Any GPU** |
|
|
54
|
+
| Compiled kernels | ❌ | ✅ Rust | ✅ CUDA | ✅ **Mojo AOT** |
|
|
55
|
+
| Install complexity | pip | pip | CUDA + Rapids stack | **pixi install** |
|
|
56
|
+
| TPC-H competitive | ❌ | ✅ | ✅ | ✅ |
|
|
57
|
+
| Cross-vendor | ❌ | ❌ | ❌ | ✅ NVIDIA/AMD/Apple |
|
|
58
|
+
|
|
59
|
+
MXFrame is the **cuDF architecture without the CUDA lock-in**.
|
|
60
|
+
Kernels are compiled **once** to a `.so` at build time — loaded in ~1 ms, then pure dispatch on every query.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## ⚡ Quick Start
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
# 1. Install pixi (Modular's package manager)
|
|
68
|
+
curl -fsSL https://pixi.sh/install.sh | bash
|
|
69
|
+
|
|
70
|
+
# 2. Clone and set up
|
|
71
|
+
git clone https://github.com/abhisheksreesaila/mxframe
|
|
72
|
+
cd mxframe
|
|
73
|
+
pixi install
|
|
74
|
+
|
|
75
|
+
# 3. Verify GPU is working
|
|
76
|
+
pixi run python3 scripts/_check_gpu.py
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import pyarrow as pa
|
|
81
|
+
from mxframe import LazyFrame, Scan, col, lit
|
|
82
|
+
|
|
83
|
+
data = pa.table({
|
|
84
|
+
"dept": pa.array(["eng", "eng", "mkt", "mkt", "eng"]),
|
|
85
|
+
"salary": pa.array([120.0, 95.0, 80.0, 110.0, 130.0], pa.float32()),
|
|
86
|
+
"age": pa.array([32, 28, 35, 29, 40], pa.int32()),
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
result = (
|
|
90
|
+
LazyFrame(Scan(data))
|
|
91
|
+
.filter(col("age") > lit(28))
|
|
92
|
+
.groupby("dept")
|
|
93
|
+
.agg(
|
|
94
|
+
col("salary").sum().alias("total_salary"),
|
|
95
|
+
col("age").count().alias("headcount"),
|
|
96
|
+
)
|
|
97
|
+
.sort(col("total_salary"), descending=True)
|
|
98
|
+
.compute(device="gpu") # or "cpu"
|
|
99
|
+
)
|
|
100
|
+
print(result.to_pandas())
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
dept total_salary headcount
|
|
105
|
+
0 eng 345.0 3
|
|
106
|
+
1 mkt 110.0 1
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 📊 Performance — TPC-H at 1 M rows *(v0.3.0)*
|
|
112
|
+
|
|
113
|
+
MX CPU beats Polars on **20/22** queries. GPU advantage compounds at 10 M+ rows where kernel parallelism dominates PCIe upload cost.
|
|
114
|
+
|
|
115
|
+
| Query | MX CPU | MX GPU | Polars | CPU vs Polars |
|
|
116
|
+
|---|---:|---:|---:|---:|
|
|
117
|
+
| Q9 · Product profit (6-table join) | **0.6 ms** | 6.6 ms | 39.9 ms | **67×** |
|
|
118
|
+
| Q12 · 2-table join + agg | **0.5 ms** | 3.4 ms | 23.2 ms | **46×** |
|
|
119
|
+
| Q3 · 3-table join + agg | **2.6 ms** | 8.7 ms | 23.3 ms | **9×** |
|
|
120
|
+
| Q1 · Filter + 8 aggregations | **10.7 ms** | 42.1 ms | 33.3 ms | **3.1×** |
|
|
121
|
+
|
|
122
|
+
→ [Full 22-query tables (1 M + 10 M rows), methodology, and reproduce instructions](docs/benchmarks.md)
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 📚 Docs
|
|
127
|
+
|
|
128
|
+
| | |
|
|
129
|
+
|---|---|
|
|
130
|
+
| [**API Reference**](docs/api.md) | LazyFrame, expressions, SQL frontend, supported operations, running tests |
|
|
131
|
+
| [**Benchmarks**](docs/benchmarks.md) | Full TPC-H tables, kernel catalogue, limitations, roadmap, reproduce instructions |
|
|
132
|
+
| [**Architecture**](docs/vision-and-architecture.md) | Design philosophy, internal layers, how MAX Graph fits in |
|
|
133
|
+
| [**Contributing**](CONTRIBUTING.md) | Dev setup, writing Mojo kernels, adding queries |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 📦 Dependencies
|
|
138
|
+
|
|
139
|
+
| Package | Required | Purpose |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `pyarrow >= 14` | ✅ | Column storage, zero-copy NumPy bridge |
|
|
142
|
+
| `numpy >= 1.24` | ✅ | Vectorized pre/post processing |
|
|
143
|
+
| `pandas >= 2.0` | ✅ | Reference implementations |
|
|
144
|
+
| `modular >= 26.4` | GPU only | MAX Engine runtime, Mojo GPU dispatch |
|
|
145
|
+
| `polars >= 0.20` | optional | Benchmark comparison |
|
|
146
|
+
| `sqlglot >= 25` | optional | SQL frontend parsing |
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 📄 License
|
|
151
|
+
|
|
152
|
+
Apache 2.0 — see [LICENSE](LICENSE).
|
mxframe-0.3.0/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# 🚀 MXFrame
|
|
2
|
+
|
|
3
|
+
> **GPU-accelerated DataFrames — Python ergonomics, Mojo speed, every GPU.**
|
|
4
|
+
|
|
5
|
+
MXFrame is a DataFrame query engine that pairs a Polars-style Python API with
|
|
6
|
+
pre-compiled Mojo AOT kernels. The same code runs on **NVIDIA, AMD, and Apple Silicon** —
|
|
7
|
+
no CUDA required, no JIT compilation at query time.
|
|
8
|
+
|
|
9
|
+
[](docs/benchmarks.md)
|
|
10
|
+
[](pyproject.toml)
|
|
11
|
+
[](pyproject.toml)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ✨ Why MXFrame?
|
|
17
|
+
|
|
18
|
+
| | pandas | Polars | cuDF (Rapids) | **MXFrame** |
|
|
19
|
+
|---|---|---|---|---|
|
|
20
|
+
| GPU support | ❌ | ❌ | ✅ NVIDIA only | ✅ **Any GPU** |
|
|
21
|
+
| Compiled kernels | ❌ | ✅ Rust | ✅ CUDA | ✅ **Mojo AOT** |
|
|
22
|
+
| Install complexity | pip | pip | CUDA + Rapids stack | **pixi install** |
|
|
23
|
+
| TPC-H competitive | ❌ | ✅ | ✅ | ✅ |
|
|
24
|
+
| Cross-vendor | ❌ | ❌ | ❌ | ✅ NVIDIA/AMD/Apple |
|
|
25
|
+
|
|
26
|
+
MXFrame is the **cuDF architecture without the CUDA lock-in**.
|
|
27
|
+
Kernels are compiled **once** to a `.so` at build time — loaded in ~1 ms, then pure dispatch on every query.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## ⚡ Quick Start
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
# 1. Install pixi (Modular's package manager)
|
|
35
|
+
curl -fsSL https://pixi.sh/install.sh | bash
|
|
36
|
+
|
|
37
|
+
# 2. Clone and set up
|
|
38
|
+
git clone https://github.com/abhisheksreesaila/mxframe
|
|
39
|
+
cd mxframe
|
|
40
|
+
pixi install
|
|
41
|
+
|
|
42
|
+
# 3. Verify GPU is working
|
|
43
|
+
pixi run python3 scripts/_check_gpu.py
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import pyarrow as pa
|
|
48
|
+
from mxframe import LazyFrame, Scan, col, lit
|
|
49
|
+
|
|
50
|
+
data = pa.table({
|
|
51
|
+
"dept": pa.array(["eng", "eng", "mkt", "mkt", "eng"]),
|
|
52
|
+
"salary": pa.array([120.0, 95.0, 80.0, 110.0, 130.0], pa.float32()),
|
|
53
|
+
"age": pa.array([32, 28, 35, 29, 40], pa.int32()),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
result = (
|
|
57
|
+
LazyFrame(Scan(data))
|
|
58
|
+
.filter(col("age") > lit(28))
|
|
59
|
+
.groupby("dept")
|
|
60
|
+
.agg(
|
|
61
|
+
col("salary").sum().alias("total_salary"),
|
|
62
|
+
col("age").count().alias("headcount"),
|
|
63
|
+
)
|
|
64
|
+
.sort(col("total_salary"), descending=True)
|
|
65
|
+
.compute(device="gpu") # or "cpu"
|
|
66
|
+
)
|
|
67
|
+
print(result.to_pandas())
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
dept total_salary headcount
|
|
72
|
+
0 eng 345.0 3
|
|
73
|
+
1 mkt 110.0 1
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 📊 Performance — TPC-H at 1 M rows *(v0.3.0)*
|
|
79
|
+
|
|
80
|
+
MX CPU beats Polars on **20/22** queries. GPU advantage compounds at 10 M+ rows where kernel parallelism dominates PCIe upload cost.
|
|
81
|
+
|
|
82
|
+
| Query | MX CPU | MX GPU | Polars | CPU vs Polars |
|
|
83
|
+
|---|---:|---:|---:|---:|
|
|
84
|
+
| Q9 · Product profit (6-table join) | **0.6 ms** | 6.6 ms | 39.9 ms | **67×** |
|
|
85
|
+
| Q12 · 2-table join + agg | **0.5 ms** | 3.4 ms | 23.2 ms | **46×** |
|
|
86
|
+
| Q3 · 3-table join + agg | **2.6 ms** | 8.7 ms | 23.3 ms | **9×** |
|
|
87
|
+
| Q1 · Filter + 8 aggregations | **10.7 ms** | 42.1 ms | 33.3 ms | **3.1×** |
|
|
88
|
+
|
|
89
|
+
→ [Full 22-query tables (1 M + 10 M rows), methodology, and reproduce instructions](docs/benchmarks.md)
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 📚 Docs
|
|
94
|
+
|
|
95
|
+
| | |
|
|
96
|
+
|---|---|
|
|
97
|
+
| [**API Reference**](docs/api.md) | LazyFrame, expressions, SQL frontend, supported operations, running tests |
|
|
98
|
+
| [**Benchmarks**](docs/benchmarks.md) | Full TPC-H tables, kernel catalogue, limitations, roadmap, reproduce instructions |
|
|
99
|
+
| [**Architecture**](docs/vision-and-architecture.md) | Design philosophy, internal layers, how MAX Graph fits in |
|
|
100
|
+
| [**Contributing**](CONTRIBUTING.md) | Dev setup, writing Mojo kernels, adding queries |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 📦 Dependencies
|
|
105
|
+
|
|
106
|
+
| Package | Required | Purpose |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| `pyarrow >= 14` | ✅ | Column storage, zero-copy NumPy bridge |
|
|
109
|
+
| `numpy >= 1.24` | ✅ | Vectorized pre/post processing |
|
|
110
|
+
| `pandas >= 2.0` | ✅ | Reference implementations |
|
|
111
|
+
| `modular >= 26.4` | GPU only | MAX Engine runtime, Mojo GPU dispatch |
|
|
112
|
+
| `polars >= 0.20` | optional | Benchmark comparison |
|
|
113
|
+
| `sqlglot >= 25` | optional | SQL frontend parsing |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 📄 License
|
|
118
|
+
|
|
119
|
+
Apache 2.0 — see [LICENSE](LICENSE).
|