mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2026-10-31 21:51:28 +01:00
python: bind PixelHistogramCUDA
PixelHistogramCUDA_<input>_<storage> for uint16, float32 and float64 frames and the six storage types of PixelHistogram, behind an aare.PixelHistogramCUDA() factory. Frames are never converted: a wrong dtype raises TypeError, so a registered buffer is always the one copied. The GIL is released during GPU work. - C++: fill_histogram() and submit_batch() take const views, so read-only arrays (np.memmap mode="r") work; register_output_buffer() pins the destination of values(out). - Python: register_input_buffer()/register_output_buffer() keep their array alive; values(out=...) writes into a given array. With a pinned out, reading back a 640 MB histogram takes 28 ms instead of 230 ms. - Tests in test_PixelHistogramCUDA.py; PixelHistogramCUDA.ipynb compares CPU and GPU on 100k Moench frames (identical, ~13x faster on the GPU).
This commit is contained in:
1 parent
3621d77093
commit
ea32b530e8
8 files changed
+757
-10
No files matched your search
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9b1ef299",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# PixelHistogram — CPU vs CUDA\n",
|
||||
"\n",
|
||||
"Per-pixel histograms of a data file, filled by `PixelHistogram` on the CPU and\n",
|
||||
"by `PixelHistogramCUDA` on the GPU. Times both, then checks that the results are\n",
|
||||
"identical."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "6c8b158f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys; sys.path.append('/home/ferjao_k/aare/build')\n",
|
||||
"\n",
|
||||
"import time\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"from aare import File, PixelHistogram_u32, PixelHistogramCUDA"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "518fd5c4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"(100000, 400, 400) uint16 32.00 GB\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"base = Path('/mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/')\n",
|
||||
"f = File(base / 'Cu_factor_10_data_master_0.json')\n",
|
||||
"frames = f.read_n(100_000) # (n_frames, rows, cols), uint16\n",
|
||||
"n_frames, rows, cols = frames.shape\n",
|
||||
"\n",
|
||||
"n_bins, xmin, xmax = 1000, 3500, 7500 # 4 ADU per bin\n",
|
||||
"n_threads = 16 # CPU threads\n",
|
||||
"print(frames.shape, frames.dtype, f'{frames.nbytes / 1e9:.2f} GB')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7c40949d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## CPU"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "a418bbd4",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU: 21.75 s, 4,598 frames/s\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"cpu = PixelHistogram_u32(rows=rows, cols=cols, n_bins=n_bins, xmin=xmin, xmax=xmax,\n",
|
||||
" n_threads=n_threads)\n",
|
||||
"\n",
|
||||
"t0 = time.perf_counter()\n",
|
||||
"for frame in frames:\n",
|
||||
" cpu.fill_async(frame.astype(np.float64)) # the CPU binding takes float64\n",
|
||||
"values_cpu = cpu.values()\n",
|
||||
"t_cpu = time.perf_counter() - t0\n",
|
||||
"print(f'CPU: {t_cpu:.2f} s, {n_frames / t_cpu:,.0f} frames/s')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0b95f098",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## GPU"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "a60415d8",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GPU fill: 1.512 s, 66,119 frames/s, 21.2 GB/s\n",
|
||||
"GPU values: 0.032 s\n",
|
||||
"GPU total: 1.545 s, speed-up 14.1x\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"gpu = PixelHistogramCUDA(rows=rows, cols=cols, n_bins=n_bins, xmin=xmin, xmax=xmax,\n",
|
||||
" dtype=frames.dtype, storage_dtype=np.uint32, batch_size=128)\n",
|
||||
"gpu.register_input_buffer(frames) # pin once, before the timed loop\n",
|
||||
"values_gpu = np.empty((rows, cols, n_bins), dtype=np.uint32)\n",
|
||||
"gpu.register_output_buffer(values_gpu)\n",
|
||||
"\n",
|
||||
"t0 = time.perf_counter()\n",
|
||||
"gpu.fill_histogram(frames)\n",
|
||||
"gpu.flush() # fill_histogram only queues the work\n",
|
||||
"t1 = time.perf_counter()\n",
|
||||
"gpu.values(out=values_gpu) # transpose + copy back to the host\n",
|
||||
"t2 = time.perf_counter()\n",
|
||||
"\n",
|
||||
"t_gpu = t2 - t0\n",
|
||||
"print(f'GPU fill: {t1 - t0:.3f} s, {n_frames / (t1 - t0):,.0f} frames/s, '\n",
|
||||
" f'{frames.nbytes / (t1 - t0) / 1e9:.1f} GB/s')\n",
|
||||
"print(f'GPU values: {t2 - t1:.3f} s')\n",
|
||||
"print(f'GPU total: {t_gpu:.3f} s, speed-up {t_cpu / t_gpu:.1f}x')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "43fff4d8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Compare"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "014cfc32",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"identical: True\n",
|
||||
"counts: 15997375206 15997375206\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print('identical:', np.array_equal(values_cpu, values_gpu))\n",
|
||||
"print('counts: ', values_cpu.sum(), values_gpu.sum())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "a0571bd1",
|
||||
"metadata": {},
|
||||
"outputs":
|
||||
[
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1200x400 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = gpu.bin_centers()\n",
|
||||
"row, col = rows // 2, cols // 2\n",
|
||||
"\n",
|
||||
"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n",
|
||||
"ax1.step(x, values_cpu[row, col], where='mid', label='CPU')\n",
|
||||
"ax1.plot(x, values_gpu[row, col], 'rx', ms=5, label='GPU')\n",
|
||||
"ax1.set_xlim(x[values_cpu[row, col].argmax()] + np.array([-100, 100]))\n",
|
||||
"ax1.set(title=f'pixel ({row}, {col})', xlabel='ADU', ylabel='counts')\n",
|
||||
"ax1.legend()\n",
|
||||
"\n",
|
||||
"ax2.step(x, values_cpu.sum(axis=(0, 1)), where='mid', label='CPU')\n",
|
||||
"ax2.plot(x, values_gpu.sum(axis=(0, 1)), 'rx', ms=5, markevery=10, label='GPU (every 10th bin)')\n",
|
||||
"ax2.set_yscale('log')\n",
|
||||
"ax2.set(title='all pixels', xlabel='ADU', ylabel='counts')\n",
|
||||
"ax2.legend()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.15"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in new issue
Block a user