From a550343e58dbf8bfb649b74543f1ee9e00a93419 Mon Sep 17 00:00:00 2001 From: kferjaoui Date: Thu, 29 Oct 2026 12:19:04 +0100 Subject: [PATCH] Change to log-scale for the cuda cf spectra in exemplar notebook --- python/tests/ClusterFinderCUDA.ipynb | 1186 +++++++++++++------------- 1 file changed, 576 insertions(+), 610 deletions(-) diff --git a/python/tests/ClusterFinderCUDA.ipynb b/python/tests/ClusterFinderCUDA.ipynb index b2d3d3f6..bebd7290 100644 --- a/python/tests/ClusterFinderCUDA.ipynb +++ b/python/tests/ClusterFinderCUDA.ipynb @@ -1,615 +1,581 @@ - { - "cells": - [ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "title", + "metadata": {}, + "source": [ + "# ClusterFinder — CPU vs CUDA\n", + "\n", + "Two finders over the same frames and the same pedestal:\n", + "\n", + "| | |\n", + "|---|---|\n", + "| **`ClusterFinderMT`** + `ClusterCollector` | multithreaded CPU baseline |\n", + "| **`ClusterFinderCUDA.find_clusters_batched`** | batched across CUDA streams, over a pinned input buffer, so H2D / kernel / D2H overlap |\n", + "\n", + "**Part 1** times them. **Part 2** compares what they found." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "imports", + "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 boost_histogram as bh\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from tqdm import tqdm\n", + "\n", + "from aare import (File, ClusterFinderMT, ClusterCollector, ClusterFinderCUDA)" + ] + }, + { + "cell_type": "markdown", + "id": "md-config", + "metadata": {}, + "source": [ + "## Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "config", + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "id": "title", - "metadata": {}, - "source": [ - "# ClusterFinder — CPU vs CUDA\n", - "\n", - "Two finders over the same frames and the same pedestal:\n", - "\n", - "| | |\n", - "|---|---|\n", - "| **`ClusterFinderMT`** + `ClusterCollector` | multithreaded CPU baseline |\n", - "| **`ClusterFinderCUDA.find_clusters_batched`** | batched across CUDA streams, over a pinned input buffer, so H2D / kernel / D2H overlap |\n", - "\n", - "**Part 1** times them. **Part 2** compares what they found." + "name": "stdout", + "output_type": "stream", + "text": [ + "Image size: (400, 400) cluster (3, 3)\n", + "Pedestal frames: 600\n", + "Data frames: 100000 of 100000 in file\n" ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "imports", - "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 boost_histogram as bh\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "from tqdm import tqdm\n", - "\n", - "from aare import (File, ClusterFinderMT, ClusterCollector, ClusterFinderCUDA)" - ] - }, - { - "cell_type": "markdown", - "id": "md-config", - "metadata": {}, - "source": [ - "## Configuration" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "config", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Image size: (400, 400) cluster (3, 3)\n", - "Pedestal frames: 600\n", - "Data frames: 100000 of 100000 in file\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", - "pd = File(base / 'Cu_factor_10_pedestal_master_0.json')\n", - "\n", - "n_frames_pd = 600 # pedestal frames, taken from the head of the file\n", - "N = 100000 # data frames, read after those\n", - "cluster_size = (3, 3)\n", - "rows, cols = f.rows, f.cols\n", - "image_size = (rows, cols)\n", - "\n", - "N_SIGMA = 5\n", - "N_STREAMS = 4 # H2D / kernel / D2H overlap\n", - "BATCH_SIZE = 2000 # frames per find_clusters_batched call\n", - "\n", - "# CPU workers. ClusterFinderMT gives each thread its own ClusterFinder with its\n", - "# own pedestal, and data frames are handed out round-robin -- so at high thread\n", - "# counts each pedestal tracks on only 1/n of the frames while the CUDA finder's\n", - "# single pedestal sees all of them, and the cluster counts drift apart. Keep it\n", - "# low when comparing counts; raise it to measure CPU throughput.\n", - "N_THREADS = 24\n", - "\n", - "# Fixed per-frame output slot the kernel writes into, copied WHOLE on every D2H.\n", - "# Too low does not error -- it TRUNCATES. The CUDA cell prints the peak actually\n", - "# reached, which is how you size this for a new dataset.\n", - "CAP = 3000\n", - "\n", - "capacity = 3_000 # initial ClusterVector capacity, CPU side\n", - "N_BINS = 200\n", - "E_MIN, E_MAX = -2, 4000 # spectrum range, ADU\n", - "\n", - "print(f'Image size: {image_size} cluster {cluster_size}')\n", - "print(f'Pedestal frames: {n_frames_pd}')\n", - "print(f'Data frames: {N} of {f.total_frames} in file')" - ] - }, - { - "cell_type": "markdown", - "id": "md-build", - "metadata": {}, - "source": [ - "## Build the two finders" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "build", - "metadata": {}, - "outputs": [], - "source": [ - "cf_cpu = ClusterFinderMT(image_size, #only positional argument here i.e. need to use the keyword for next ones\n", - " cluster_size=cluster_size, \n", - " n_sigma=N_SIGMA,\n", - " capacity=capacity, \n", - " min_pedestal_samples=n_frames_pd, \n", - " n_threads=N_THREADS)\n", - "\n", - "sink = ClusterCollector(cf_cpu)\n", - "\n", - "cf_cuda = ClusterFinderCUDA(image_size, \n", - " cluster_size=cluster_size, \n", - " n_sigma=N_SIGMA,\n", - " max_clusters_per_frame=CAP, \n", - " n_streams=N_STREAMS, \n", - " min_pedestal_samples=n_frames_pd, \n", - " algorithm=\"fixed_window\", \n", - " time_kernels=False)" - ] - }, - { - "cell_type": "markdown", - "id": "md-ped", - "metadata": {}, - "source": [ - "## Pedestal\n", - "\n", - "Identical frames into both, so the implementation is the only thing that differs." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "train", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Pedestal (600 frames): 2.39s\n" - ] - } - ], - "source": [ - "pd.seek(0)\n", - "t0 = time.perf_counter()\n", - "for _ in range(n_frames_pd):\n", - " pd_img = pd.read_frame()\n", - " cf_cpu.push_pedestal_frame(pd_img.copy())\n", - " cf_cuda.push_pedestal_frame(pd_img.copy())\n", - "print(f'Pedestal ({n_frames_pd} frames): {time.perf_counter() - t0:.2f}s')" - ] - }, - { - "cell_type": "markdown", - "id": "md-io", - "metadata": {}, - "source": [ - "## Read the data frames\n", - "\n", - "Kept out of both timing loops: the two finders run over the same in-memory array." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "io", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Reading 100000 frames: 54.30s (1,842 FPS, 32.00 GB at 0.59 GB/s)\n" - ] - } - ], - "source": [ - "f.seek(0)\n", - "t0 = time.perf_counter()\n", - "data = f.read_n(N)\n", - "t_io = time.perf_counter() - t0\n", - "gb = f.bytes_per_frame * N / 1e9\n", - "print(f'Reading {N} frames: {t_io:.2f}s ({N / t_io:,.0f} FPS, '\n", - " f'{gb:.2f} GB at {gb / t_io:.2f} GB/s)')" - ] - }, - { - "cell_type": "markdown", - "id": "md-cpu", - "metadata": {}, - "source": [ - "## 1 — CPU, multithreaded" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "cpu", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████████████████████████████████████████████████████████████████████| 100000/100000 [00:23<00:00, 4235.66it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU MT (24 threads): 23.62s 4,235 FPS 233,104,694 clusters (2331.0/frame)\n" - ] - } - ], - "source": [ - "t0 = time.perf_counter()\n", - "# Pass the frame number: find_clusters(frame) defaults it to 0, and every\n", - "# resulting cluster is then stamped frame 0. Part 2 groups by it.\n", - "for i, frame in enumerate(tqdm(data)):\n", - " cf_cpu.find_clusters(frame, i)\n", - "t_cpu = time.perf_counter() - t0\n", - "\n", - "cf_cpu.stop(); sink.stop()\n", - "clusters_cpu = sink.steal_clusters()\n", - "\n", - "hist_cpu = bh.Histogram(bh.axis.Regular(N_BINS, E_MIN, E_MAX))\n", - "n_clusters_cpu = 0\n", - "for cv in clusters_cpu:\n", - " hist_cpu.fill(cv.sum())\n", - " n_clusters_cpu += cv.size\n", - "\n", - "print(f'CPU MT ({N_THREADS} threads): {t_cpu:.2f}s {N / t_cpu:,.0f} FPS '\n", - " f'{n_clusters_cpu:,} clusters ({n_clusters_cpu / N:.1f}/frame)')" - ] - }, - { - "cell_type": "markdown", - "id": "md-cuda", - "metadata": {}, - "source": [ - "## 2 — CUDA, batched + multi-streamed\n", - "\n", - "`register_input_buffer` page-locks the input once so H2D runs at full DMA\n", - "bandwidth instead of through the driver's staging buffer. It is paid once,\n", - "outside the loop, and released when the dataset is done." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "cuda", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CUDA batched: 3.35s 29,810 FPS 233,095,737 clusters (2331.0/frame)\n", - " input pinned in 0.84s, once, outside the loop\n", - " vs CPU: 7.04x\n", - " peak clusters in one frame: 2,545 of CAP 3,000\n" - ] - } - ], - "source": [ - "t0 = time.perf_counter()\n", - "cf_cuda.register_input_buffer(data)\n", - "t_pin = time.perf_counter() - t0\n", - "\n", - "clusters_cuda = []\n", - "t0 = time.perf_counter()\n", - "for start in range(0, N, BATCH_SIZE):\n", - " stop = min(start + BATCH_SIZE, N)\n", - " clusters_cuda.extend(\n", - " cf_cuda.find_clusters_batched(data[start:stop], first_frame=start))\n", - "t_cuda = time.perf_counter() - t0\n", - "\n", - "cf_cuda.unregister_input_buffer()\n", - "\n", - "hist_cuda = bh.Histogram(bh.axis.Regular(N_BINS, E_MIN, E_MAX))\n", - "energies = [np.asarray(cv.sum()).ravel() for cv in clusters_cuda if cv.size > 0]\n", - "if energies:\n", - " hist_cuda.fill(np.concatenate(energies))\n", - "n_clusters_cuda = sum(cv.size for cv in clusters_cuda)\n", - "\n", - "print(f'CUDA batched: {t_cuda:.2f}s {N / t_cuda:,.0f} FPS '\n", - " f'{n_clusters_cuda:,} clusters ({n_clusters_cuda / N:.1f}/frame)')\n", - "print(f' input pinned in {t_pin:.2f}s, once, outside the loop')\n", - "print(f' vs CPU: {t_cpu / t_cuda:.2f}x')\n", - "\n", - "# One ClusterVector per frame, so this IS the per-frame maximum.\n", - "peak = max((cv.size for cv in clusters_cuda), default=0)\n", - "print(f' peak clusters in one frame: {peak:,} of CAP {CAP:,}')\n", - "if peak >= CAP:\n", - " print(' !! CAP REACHED -- clusters were dropped; raise CAP and re-run.')" - ] - }, - { - "cell_type": "markdown", - "id": "md-summary", - "metadata": {}, - "source": [ - "## Summary" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "summary", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " s FPS us/frame clusters\n", - "CPU MT (24 thr) 23.62 4,235 236.2 233,104,694\n", - "CUDA batched 3.35 29,810 33.5 233,095,737\n", - "\n", - "speedup: 7.04x\n" - ] - } - ], - "source": [ - "print(f'{\"\":<22} {\"s\":>7} {\"FPS\":>10} {\"us/frame\":>10} {\"clusters\":>13}')\n", - "for name, t, n in (('CPU MT (%d thr)' % N_THREADS, t_cpu, n_clusters_cpu),\n", - " ('CUDA batched', t_cuda, n_clusters_cuda)):\n", - " print(f'{name:<22} {t:7.2f} {N / t:10,.0f} {t * 1e6 / N:10.1f} {n:>13,}')\n", - "print(f'\\nspeedup: {t_cpu / t_cuda:.2f}x')" - ] - }, - { - "cell_type": "markdown", - "id": "md-part2", - "metadata": {}, - "source": [ - "# Part 2 — Where the two disagree\n", - "\n", - "The two implementations are not bit-identical by construction: the CUDA finder\n", - "updates its pedestal once per frame, the CPU finder per pixel, so once the\n", - "pedestals drift apart a few pixels land on opposite sides of the threshold.\n", - "\n", - "Three views, cheapest first: the **spectra**, the **cluster sets**, and **where\n", - "in the run** the difference accumulates." - ] - }, - { - "cell_type": "markdown", - "id": "md-spec", - "metadata": {}, - "source": [ - "## Spectra\n", - "\n", - "Both curves should lie on top of each other; the ratio panel is the sensitive\n", - "view." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "spectra", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": - "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t/siyAMPPGACwvXr1/t8dnZz6NAh+f333+WKK67I85x+Hvq8BvZ169aVH3/80bPeW2pqqrk44X4+mIK8Xu9rwKwXJPzT5H5evyeadk2j/z7d286fP98EZYHKdOXKlU3zzDvuuEPS09NNGVX6/XX3K9YLE/ren376aRNk1alTx1yg0ee1HOsFAy3TWla1HGgwd+ONN/ocR4NQvQD0xBNPeMrGZZddJr169TJ5O378eHP8gQMHmmBVvzvucq9lXvenvw964UnzSr+7elHpk08+McGf6tmzp/k+6Hdb06vfR32szXUB2FSh6v8AIAq2bNlimlBde+21Yb/Gv7nm559/bvaht97Wr19v1r/66qvm8Y4dO8zjsWPHFqqJ3qhRo6ykpCTru+++81n/3//+N0/TMH1cunRpa9euXfm+nw0bNlgpKSnW3Xff7bN+3759VqVKlXyat2nzON3322+/7bNtp06drHr16nkeT58+3Ww3a9Ysn+007bp+4sSJnnU1atQwzWV//fXXPE3uXC6XtWbNGp/1HTp0yJPfmq4KFSqYprVuo0ePNvmln0Mw4X4mmkZNy6pVq/I0tStVqpR14MCBAn1GixYtMo+HDh1aqLLgLnOtWrXK89zw4cPNc/60HOp67/zQ91WiRAnr77//9qzT96jbaTNE9/tS7733nln//vvvW3YQrLnmpk2bTDr1s/CnTSX1OW2irR577DHzePPmzXm21SaYdevWDZmGgry+Tp06puz6++eff8w+Hn/8cfP466+/No/1O+RPt9Hn9DWhaJnRshPo96h27dqmaW9+zTi16W+fPn2sJk2a+Dyn+9Dfhf379+cpG2effbZpGu6m3ytd//3335vHWp7Kli1rdenSJU8z3MaNG1vnnXeeZ91JJ51kDRgwIGQ6AdgLzTXzoVfFu3TpYpoO6ZUvvRpfEO6mOv6LXg0HEDvaBKp27dqmhmzMmDHmSrjWeIVLr543atTINKnSJl3uRa+AB2ouqk2lypQpk+9+9eq57kevrnvvV2sKtFbKf796LP2N8q9h0Jo677Rq80PdznufmnatBfPfp75er9Z702aK+n69axGVDlThT2vUtm3bJu+88455rPmqtX9au+Dd3PV4PpOGDRtK48aNfdb93//9n2me6R61MdzPSAfdUNr89HhoLcnx0rRq7Y2b1jYprXHVpnT+670/50C8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uugiOfHEE800Bm3btpVDhw55nl+xYoVccskl5jkdYOjWW2+V/fv3F+jYnTt3NuuiHVgT5AEAACBhaeB07rnnymeffSZPPvmk/PDDD/Lxxx+bE/w777zTZ9uRI0fK5s2b5fvvv5du3bpJv379ZObMmRFJhwZCr776qs86DZw0Xe6h9HWbjRs3mvWajn//+9/SsGFDc9+93HfffWEfc9y4cXLTTTeZoNF9PF2efvppkw9Tp041edGnTx+f12nevP322/Lrr7/KrFmz5Pfff5err77a87zur2vXrvL+++/L2rVrzX4WLFhg8isUnT5Ag8MhQ4YE3eb//u//ZNWqVSZduuh9DfQC6dOnj5x11llh5YUGeHrs9u3by7fffivfffed+fy98+biiy+W008/XZYuXWqOvWbNGundu3eBj615/vzzz0tUWcgjPT3d0qzRW7vIzs62du/ebW5BfjsN5Zv8djLKN/mdCOX74MGD1k8//WQdOnTIijcdO3a0Tj31VGv//v15ntP35lajRg3r2Wef9Xm+Tp061rXXXmvuDx8+3GrcuHHAfeh55eeffx40Da1bt7Zuv/1265RTTrG++uorz/rHHnvM6tKli9mv7l/z++jRo57zwWDHDMf27dstl8tl/fjjjyG3e/vtt620tDRz3GDmzJlj9pWRkRF0m+eee86qWrVqWGnTvNI8885/pWVM13/zzTeedUuWLDHrfvnlF59tJ06caPL1008/Dbgvf82bN7cefPBBn3Xe+f3iiy9aFSpUsLKysjzPr1y50uz7t99+K9Cx//zzT7P+999/D5gW/R4F+z6FG6dQkwcAAICEpM0TtUZGa2y0iZ4/bZYXijZXPJ5h7r2lpaXJ9ddf71ObpzVgN998s0TDV199ZZpkNmjQIOR22lRTm0+mpKQEzcM333xTWrZsaZqSBqK1YO+++660bt36uNKstW3aRLN58+aedeeff75Zt3jxYs+6n376ydS6Tps2zVMTF4rOSae1czovnb6PihUrmrRqHrkdOXLEfEbe+3PPaee9XTjHrlGjhjnWl19+KdHCZOgA4G3dpyLTc/omSHKayJBN5A8AFFLDhz6Wo1la8VB0UpNdsmbkpWFtu27dOjPhdf369Qt0jMzMTHnjjTdMk8bbb79dIkWb+P3rX/+S5557TpYvX24CrMsuu6xA/ewK0kxVg5lQQZD2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SvHixU2+vvDCCz7PHz16VEaOHCm1a9c22zRu3Fg+/vhjn20efvhhT166l0qVKoU8rnf+u7yWhg0bFuh916xZ0+SlfoZ6697PnXfe6dlm2LBhMmjQIFsG1gR5ABDEmORxIo+UP7Y8fip5BQAO8+eff5pgRGvCnnzySfnhhx9MsNG2bVufE/qCuPTSS2Xz5s1m3xoQ6b769+8vnTt3lsxM33lYN2zYIEuWLJG77rpLJk+eXKjjLV68WH777Te55pprPOsWLVpkgry5c+fK8uXLTRo0cF25cqVnm7Jly5rAUI///fffy0033WQW72CwatWq8sQTT8iyZcvMctFFF0nXrl1lzZo1QdOzfv166dSpk1x44YXmeEOGDJF77rlHZs2a5dnmwQcflBdffFGef/55+emnn6Rfv35yxRVX+KRPaXCmeele9PMJ5bnnnvPZfuPGjeZ9eudNOO/7u+++k3/++ce8Xm/nz59v1nvv57LLLpP09PQ8wbMdMBk6AIQjK4N8AgAHuuOOO0wNzbfffmtqdbyDi5tvvrlQ+9TaQHeN06mnnirnnHOOnH/++dKuXTuZOnWq9O3b17Ptq6++aoK/22+/Xc477zwZO3asTzrCMWPGDFMbqDVibrofb48//rjMmTNHPvjgA2nSpIlZ510DqTQQfe211+Srr76SDh06mHUaGHp77LHHTO2e1jp6145501q76tWre9LQoEEDEyA+/fTTctVVV5l1WnOmgZYGg0rfvwZLzzzzjLzxxhuefaWkpORbe+etdOnSZnHT2tfdu3ebIM4tnPetNaCWZUlWVpapZR09erSpdWzdurXndbpe0z99+nTp2LGj2Ak1eQAS1o8pN5glmIFZ94gM256zJKcVadoAANG3a9cuU2unNXaBAittzhcpWgOmTRK9+3BpEKFB3g033GD609WtW1fefvvtAu9ba+20+WEo2qRw3759phYrEE2LNk/99ddfpVWrVgG30YBHA8oDBw6YZpvBaA2ZBp3eNHjSQE+baaojR474BKWqRIkSJtDypjWUVapUkVq1asm1114rf/zxhxTE5MmT5eKLL5YaNWoU+n1nZGSYwFODfr0g4E0D8y+//FLshpo8AAgiIytb6g7N6XfwY0pOe3tCPQAoIG3uHkzfBSKVG+fcn3G9yG/zAm/X6j8ire/Pub/idZEPBwbertKZIrd8FnbS1q1bZ07yNcAqCnocbR7otmDBAjl48KCn9kiDPQ1KvGudwqHNQjUQCkVryDQ46969u896bW6otY0adGnN1MSJE00zT2/aRFKDusOHD8tJJ50ks2fPljPOOCNkH0fti+hNH2tT1R07dkjlypXNex4zZowJrLSGTAMtrWnUQNKtefPmMm3aNBP8bt26VR599FFp2bKlaSp6yimn5JsvmzdvNs1l33rrrTzPhfO+vWsD9+zZY/r7+dN9aJNbDaLd/SHtwD4pAQAbSU12SVrysZ/IF7M6yyvZvk1WAADxTQM85V87E83jeR9LA7oePXqYJonquuuuk6VLl5papYI4dOhQnloxb9qcUAcxmTlzplSoUMHnuZIlS8qqVatMHzRtijlw4EBZuHChzzb16tUz22gTTW1W2atXL9OPLhT/PPXPa+07V6dOHRP4pqWlmT6JGtxqwOWmTSC1eeeZZ55pauM+/PBDs16bVoZj6tSppja2W7dueZ4L53276aA5mpZAgbTWPmqAp8GinVCTBwABrBl5qc/jukP1P5TIHeQWABSMNnkPx7VvhrfdOT1zlgjQIEODjp9//jlgIOAfFGjtjz+t4fHuAxaKHkebHbqbimoNkTZf1D5ublqTpUGF9gELV7ly5Uy/s0A0sOvTp4+88847JlDyp7VPp59+urmvo0xqGkeNGuXTb02DMPc22ixUAyMN0nTglEC0D53W5nnbtm2bCWbdNXDa503fv9YO7ty50wRQOlKlO38C0Sa1GvBpE878WJZl8rFnz54m/YV53+qvv/4yNa7BpkrQz/GEE04wwZ6dUJMHAACAhKT907TZ4IQJE0xTxkABnJvWOGlw4x9I6MiVWtOVHx29U5s9ugceefPNN83IlatXrzY1Su5FByvRmir/UThD0YFUAtWsaQ2eNjHU5oo6EmQ49D3lVyuV3zbatNM9GqXbvHnzTICoUxJ40xpIbfKo71dH39SRO4PRY2owps09w5nCYd26dSbADUew96SfhdZ+Bsu/H3/80QysYzfU5AFAGDq73B3B7TV6FgDg+GhfLO3npQNo6LxtOiecBhwapGgNmwYV6r777jPNFDXY00FFtInkSy+9JL///nueqRY0WNCaLK2V075kOriL1hLpKJo33nijp6nm1VdfLY0aNfJ5rQ4Q8sADD5imiaECHm8aqPo3YdQAT4+lNW46sqe7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AABQNGwf5Kk77rjDLIFMnTrV57HOpbdy5UpxGm1OOnz48DzNSkF+OwHlm/x2Mso3+e1klG/y28mKxfH5t60HXgEAAAAAFIw9JnwAAAAAAEQEQR4AAAAAOAhBHgAAAAA4CEFenJg4caLUqlVLihcvbuYO/PLLL2OdpLjz8MMPm8ntvZdKlSp5ntfuqbqNTi5ZokQJadOmjaxZs8ZnH0eOHJG7775bypUrJyeeeKJcfvnl8vfff8fg3djPokWLpEuXLib/NG/fe+89n+cjlb86NYpOq6JzxOii9/fs2SOJJr/87t27d57yfv755/tsQ36Hb9SoUdKsWTMpWbKkVKhQQbp162ZGcfZGGS/a/KaMR86kSZPkrLPO8swFplNWffTRR57nKdtFm9+U7ej+trhcLhkwYIDzy7cOvAJ7mzFjhpWammq9/PLL1k8//WT179/fOvHEE62//vor1kmLK8OHD7caNmxobd682bNs27bN8/wTTzxhlSxZ0po1a5b1ww8/WD169LAqV65s7d2717NNv379rFNPPdWaP3++tWLFCqtt27ZW48aNrczMTCvRzZ071xo6dKjJP/1pmT17ts/zkcrfSy+91GrUqJG1ePFis+j9zp07W4kmv/zu1auXySvv8r5z506fbcjv8HXo0MF69dVXrR9//NFatWqVddlll1nVq1e39u/f79mGMl60+U0Zj5z333/f+vDDD61ff/3VLEOGDDHnHZr/irJdtPlN2Y6Ob7/91qpZs6Z11llnmXNpN6eWb4K8OHDeeeeZwuWtfv361qBBg2KWpngN8vQLGUh2drZVqVIl80V3O3z4sFW6dGnrhRdeMI/37NljfoQ16HbbtGmTlZSUZH388cdF8A7ih3/QEan81Yscuu9vvvnGs82SJUvMul9++cVKVMGCvK5duwZ9Dfl9fPQCkeb7F198YR5Txos2vxVlPLrKlCljvfLKK5TtIs5vRdmOvH379ll16tQxQVrr1q09QZ6Tf7tprmlzGRkZsnz5cmnfvr3Pen2sk7yjYH777TdTHa9NX6+99lr5448/zPr169fLli1bfPJZ50Rp3bq1J5/1czh69KjPNrqvRo0a8VnkI1L5u2TJEtMEonnz5p5ttAmiruP7kNfChQtNU7e6devKLbfcItu2bfM8R34fn/T0dHNbtmxZyngM8tuNMh55WVlZMmPGDDlw4IBpRsjvd9HmtxtlO7LuvPNOueyyy+Tiiy/2We/k8h0Xk6Ensh07dpgfgIoVK/qs18daKBE+/eJNmzbNnPBu3bpVHn30UWnZsqVpd+3Oy0D5/Ndff5n7uk1aWpqUKVOGz6KAIpW/eqtBiz9dx/fBV8eOHeWaa66RGjVqmH9iw4YNk4suusj8s9J/YOR34Wnl6cCBA+Vf//qX+SdPGS/6/FaU8cj64YcfTJBx+PBhOemkk2T27NlyxhlneE5Q+f0umvxWlO3ImjFjhqxYsUK+++67hDo/IciLE9pJ1P+fnv86hKY/mm5nnnmm+XGtXbu2vPbaa54BKQqTz3wW4YtE/gbans8grx49enju64lx06ZNTcD34YcfypVXXkl+H4e77rpLvv/+e/nqq6/yPEcZL7r8poxHVr169WTVqlVmoIhZs2ZJr1695IsvvvA8T9kumvzWQI+yHTkbN26U/v37y7x588zghcE4sXzTXNPmdBSf5OTkPFcBtNmV/1UHFIyOjqTBnjbhdI+yGSqfdRttPqujJ/FZFEyk8le30VpYf9u3b+f7kI/KlSubIE/LO/ldeDq62vvvvy+ff/65VK1a1bOeMl60+R0IZfz4aE3F6aefbi4I6QiEjRs3lueee46yXcT5HQhlu/CWL19uziN0ZPqUlBSzaDA9btw4c999fuHE8xOCvDj4EdCCOX/+fJ/1+libGqLwdDjcn3/+2fx4ah89/YJ657N+ofWHwJ3P+jmkpqb6bLN582b58ccf+SzyEan81dpX7Zvz7bfferZZunSpWcf3IbSdO3eaK5pa3snvgtOrsVqj9O6778pnn31myjRlPHb5HQhlPPKfgf6f5Pe7aPM7EMp24bVr1840jdVaU/eigfX1119v7p922mnOPT+JyXAvKNQUCpMnTzaj9wwYMMBMofDnn3+SkwXw73//21q4cKH1xx9/mNGPdFhbHTLXnY86spKOpvTuu++aIXSvu+66gEPoVq1a1VqwYIEZQveiiy5iCgWvkatWrlxpFv1pGTNmjLnvnuojUvmrQxTr8Mc6apUuZ555ZkJOoRAqv/U5Le86hPP69eutzz//3GrRooUZ/pn8Lpzbb7/dlF/9DfGeluLgwYOebSjjRZfflPHIGjx4sLVo0SLze/H999+bIf115MB58+aZ5ynbRZfflO3oa+01uqaTyzdBXpyYMGGCVaNGDSstLc0655xzfIaRRnjc855owFylShXryiuvtNasWeN5XofR1WkWdCjdYsWKWa1atTJfdm+HDh2y7rrrLqts2bJWiRIlzJd3w4YNfASWZQIJDTb8Fx0KOpL5q3O9XX/99SZA10Xv7969O+E+g1D5rSfC7du3t8qXL2/Ku84vpuv985L8Dl+gvNZF53Jzo4wXXX5TxiPr5ptv9pxj6O9Gu3btPAGeomwXXX5Ttos+yMt26PmJS//Epg4RAAAAABBp9MkDAAAAAAchyAMAAAAAByHIAwAAAAAHIcgDAAAAAAchyAMAAAAAByHIAwAAAAAHIcgDAAAAAAchyAMAAAAAByHIAwAghtq0aSMul8ssq1ativln0bt3b0963nvvvVgnBwBQCAR5AIC44R2AeC+XXnqpxLNbbrlFNm/eLI0aNcrzXPv27SU5OVm++eabkPmRmpoqFStWlEsuuUSmTJki2dnZPtsGC9oGDBhgAk235557zqQFABC/CPIAAHFFAzoNQryX6dOnR/WYGRkZUd3/CSecIJUqVZKUlBSf9Rs2bJAlS5bIXXfdJZMnTw6ZH3/++ad89NFH0rZtW+nfv7907txZMjMzC5yW0qVLm7QAAOIXQR4AIK4UK1bMBCHeS5kyZXxqrF555RW54oorTPBUp04def/993328dNPP0mnTp3kpJNOMrVfPXv2lB07dnie15otDawGDhwo5cqVM7VjSvej+ytRooQJpl577TVzvD179siBAwekVKlS8t///tfnWB988IGceOKJsm/fvgK/11dffdUEa7fffrvMnDnTHCNYfpx66qlyzjnnyJAhQ2TOnDkm4Js6dWqBjwkAiH8EeQAAxxkxYoR0795dvv/+exPMXX/99bJr1y7znNZ6tW7dWs4++2xZtmyZfPzxx7J161azvTcN4LRm7euvv5YXX3zR1JRdffXV0q1bN9N37rbbbpOhQ4d6ttdA7tprrzWBmTd9rK8rWbJkgd6DZVnmtTfccIPUr19f6tatK2+//XZYr73oooukcePG8u677xbomAAAZyDIAwDElf/973+mBs57eeSRR/L0Vbvuuuvk9NNPl8cff9zUgH377bfmuUmTJpkaL12vwVOTJk1MH7bPP/9c1q5d69mHvvbJJ5+UevXqme1eeOEFc/+pp54ytxrQ6XG89e3bVz755BP5559/zGOtHdT03nzzzQV+nwsWLJCDBw9Khw4dzGMN9oI12QxE06yBKQAg8RDkAQDiijaT1Jo07+XOO+/02eass87yqWHTWrRt27aZx8uXLzcBnXeQqAGR+v333z2va9q0qc8+f/31V2nWrJnPuvPOOy/P44YNG8q0adPM49dff12qV68urVq1KvD71ICuR48enn56GrQuXbrUpCPcmkBtSgoASDy+PbwBALA5Ddq0li0UHWnSmwY77tEm9bZLly4yevToPK+rXLmyz3HyC5p0nT+tzRs/frwMGjTINLe86aabChxsadNSHQnz6NGjpubRLSsry9Q6Bkq7v59//llq1arleayBbnp6ep7ttD+hDrYCAHAOavIAAAlFm2quWbNGatasaYJF78U/sPOmtX3fffedzzrt0+dPm1XqqJjjxo0zx+nVq1eB0/jmm29K1apVZfXq1T41lmPHjjV9BfMbNfOzzz6TH374Qa666qqQ6dcgVWs2tfkpAMA5CPIAAHHlyJEjsmXLFp/Fe2TM/GjTTq0p0+aP2k/vjz/+kHnz5pl+c1pTFowOtPLLL7/IAw88YPru6SAo7tErvWvqdKTPK6+8Uv7zn/+YOe40WCtMU00drEXnzfNeNI1a8/bhhx/myY9NmzbJihUrTF/Drl27mlE5b7zxRs929913n9mv1jJq+jWA1BFEtYmqf3NXAEB8I8gDAMQVHQ1Tm1V6L//617/Cfn2VKlXMiJka0OmgJho86bxy2mQxKSn4v0Vt+qjTI+iIldrnT5tRukfX1GkMvPXp08fMrVeYAVe0Zk0DMO9aOO8mlxo4eg/A4s4PrZnUOfO0v6HWIuo0CjqJupuOHqpBqdYEat9C3Y8GeF9++aXUqFGjwOkEANiXywrUoQAAAOTrscceM6Nubty4MU9zSw0cdZTNtLS0kPvQOfl0OgdtimknWjs5e/ZsM2UEACC+UJMHAECYJk6caPq1aRNPHTlTp1Pw7nOnUx5oP7xRo0aZ5p35BXje+9VRPrUfXaz169fPpAUAEL+oyQMAIEz33nuvzJw50/Tp06kRevbsKYMHD/ZMc/Dwww+b2j2dMkGbS4YTLGlfukOHDpn7us9wA8No0akm9u7da+5rM9BQg9EAAOyJIA8AAAAAHITmmgAAAADgIAR5AAAAAOAgBHkAAAAA4CAEeQAAAADgIAR5AAAAAOAgBHkAAAAA4CAEeQAAAADgIAR5AAAAAOAgBHkAAAAAIM7x/+xXTgFvoafsAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, (ax_spec, ax_ratio) = plt.subplots(\n", - " 2, 1, figsize=(9, 6.5), sharex=True, gridspec_kw={'height_ratios': [3, 1]})\n", - "\n", - "edges = hist_cpu.axes[0].edges\n", - "cpu_vals, cuda_vals = hist_cpu.values(), hist_cuda.values()\n", - "\n", - "ax_spec.stairs(cpu_vals, edges, label=f'CPU MT ({n_clusters_cpu:,})',\n", - " color='C0', linewidth=1.4)\n", - "ax_spec.stairs(cuda_vals, edges, label=f'CUDA ({n_clusters_cuda:,})',\n", - " color='C1', linestyle='--', linewidth=1.4)\n", - "ax_spec.set_ylabel('Counts')\n", - "ax_spec.set_title(f'Cluster energy spectrum — {N:,} frames')\n", - "ax_spec.legend()\n", - "ax_spec.grid(alpha=0.2)\n", - "\n", - "with np.errstate(divide='ignore', invalid='ignore'):\n", - " ratio = np.where(cpu_vals > 0, cuda_vals / cpu_vals, np.nan)\n", - "ax_ratio.stairs(ratio, edges, color='C1', linewidth=1.2)\n", - "ax_ratio.axhline(1.0, color='gray', linewidth=0.5)\n", - "ax_ratio.set_ylabel('CUDA / CPU')\n", - "ax_ratio.set_xlabel('Energy [ADU]')\n", - "ax_ratio.set_ylim(0.9, 1.1)\n", - "ax_ratio.grid(alpha=0.3)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "md-sets", - "metadata": {}, - "source": [ - "## Cluster sets\n", - "\n", - "Every cluster is keyed by `(frame, x, y)`, so the two results can be differenced\n", - "directly — no per-frame Python loop.\n", - "\n", - "A cluster whose centre moved by one pixel was *relabelled*, not gained or lost,\n", - "so those are counted separately from genuine adds and drops." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "sets", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU 233,104,694 clusters\n", - "CUDA 233,095,737 clusters net -8,957 (0.0038%)\n", - "\n", - "exact-position mismatches CPU-only 167,059 CUDA-only 158,102\n", - " of which shifted by 1 px 126,836 126,667\n", - " genuine add / drop 40,223 31,435\n", - "\n", - "frames touched by a genuine difference: 48,682 of 100,000\n", - "[43.3s]\n" - ] - } - ], - "source": [ - "def cluster_keys(vectors):\n", - " \"\"\"One int64 key per cluster: frame * rows*cols + y * cols + x.\n", - "\n", - " Centres are unique within a frame, so keys are globally unique and the sets\n", - " below need only a sort, never a np.unique.\n", - " \"\"\"\n", - " n = len(vectors)\n", - " sizes = np.fromiter((cv.size for cv in vectors), np.int64, n)\n", - " frames = np.repeat(\n", - " np.fromiter((cv.frame_number for cv in vectors), np.int64, n), sizes)\n", - " xy = [np.asarray(cv) for cv in vectors if cv.size]\n", - " if not xy:\n", - " return np.empty(0, np.int64), frames\n", - " x = np.concatenate([v['x'] for v in xy]).astype(np.int64)\n", - " y = np.concatenate([v['y'] for v in xy]).astype(np.int64)\n", - " return frames * (rows * cols) + y * cols + x, frames\n", - "\n", - "\n", - "t0 = time.perf_counter()\n", - "k_cpu, fr_cpu = cluster_keys(clusters_cpu)\n", - "k_cuda, fr_cuda = cluster_keys(clusters_cuda)\n", - "\n", - "# Sort ONCE. np.setdiff1d and np.isin each re-sort their argument on every call,\n", - "# and the shift check below calls one eight times per direction -- about twenty\n", - "# sorts of a 27-million-element array. Two sorts plus binary search instead.\n", - "s_cpu = np.sort(k_cpu)\n", - "s_cuda = np.sort(k_cuda)\n", - "\n", - "\n", - "def present_in(vals, sorted_keys):\n", - " \"\"\"Which of `vals` appear in an already-sorted key array.\"\"\"\n", - " if sorted_keys.size == 0:\n", - " return np.zeros(vals.size, dtype=bool)\n", - " i = np.searchsorted(sorted_keys, vals)\n", - " np.clip(i, 0, sorted_keys.size - 1, out=i)\n", - " return sorted_keys[i] == vals\n", - "\n", - "\n", - "cpu_only = s_cpu[~present_in(s_cpu, s_cuda)]\n", - "cuda_only = s_cuda[~present_in(s_cuda, s_cpu)]\n", - "\n", - "\n", - "def drop_shifted(only, sorted_other):\n", - " \"\"\"Drop mismatches that have a counterpart within 1 px in the other set.\"\"\"\n", - " keep = np.ones(only.size, dtype=bool)\n", - " for dy in (-1, 0, 1):\n", - " for dx in (-1, 0, 1):\n", - " if dx or dy:\n", - " keep &= ~present_in(only + dy * cols + dx, sorted_other)\n", - " return only[keep]\n", - "\n", - "\n", - "cpu_real = drop_shifted(cpu_only, s_cuda)\n", - "cuda_real = drop_shifted(cuda_only, s_cpu)\n", - "touched = np.unique(np.concatenate([cpu_real, cuda_real]) // (rows * cols)).size\n", - "\n", - "print(f'CPU {k_cpu.size:>12,} clusters')\n", - "print(f'CUDA {k_cuda.size:>12,} clusters net {k_cuda.size - k_cpu.size:+,}'\n", - " f' ({abs(k_cuda.size - k_cpu.size) / k_cpu.size:.4%})')\n", - "print()\n", - "print(f'exact-position mismatches CPU-only {cpu_only.size:>8,} '\n", - " f'CUDA-only {cuda_only.size:>8,}')\n", - "print(f' of which shifted by 1 px {cpu_only.size - cpu_real.size:>17,} '\n", - " f'{cuda_only.size - cuda_real.size:>17,}')\n", - "print(f' genuine add / drop {cpu_real.size:>17,} {cuda_real.size:>17,}')\n", - "print(f'\\nframes touched by a genuine difference: {touched:,} of {N:,}')\n", - "print(f'[{time.perf_counter() - t0:.1f}s]')" - ] - }, - { - "cell_type": "markdown", - "id": "md-drift", - "metadata": {}, - "source": [ - "## Where in the run it accumulates\n", - "\n", - "Cumulative `CUDA − CPU` against frame index. A curve that rises and then flattens\n", - "means the two pedestals settled into agreement and the difference is a start-up\n", - "transient; a steadily sloping line would mean a persistent per-frame bias." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "drift", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": - "iVBORw0KGgoAAAANSUhEUgAAA3kAAAFeCAYAAAA4xtZyAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAayVJREFUeJzt3Qd0FNXbBvAnIfQeeu9FQamCSJOuFEURBQFB0U9EFKWDSG/+QVREmqKoICgWVIoCUpQi0kFRitI7UkJv2e88d5xkd7MJSdhkS57fOQPZ2bu7d2fuzsw7t4U4HA4HREREREREJCiE+joDIiIiIiIi4j0K8kRERERERIKIgjwREREREZEgoiBPREREREQkiCjIExERERERCSIK8kRERERERIKIgjwREREREZEgoiBPREREREQkiCjIExERERERCSIK8iSobNu2DU8//TSKFSuGdOnSIVOmTKhcuTL+97//4fTp01Hp7r//frMklUmTJmHGjBlJ9v6ByFvbJCQkBEOGDIl6zPfkun379rmkGzhwIAoXLoywsDBky5bNrLt27Rq6dOmCfPnyIVWqVKhYseJt50cCn3uZiq9Lly6Z161YsSLGc7GVS3H1ySefoE2bNihTpgxCQ0NRtGjRWDfRhQsX8MorryB//vzm+M7f75w5czym3bRpExo2bGjOAfz9P/roo/jnn3/ivfkT8vp3330XZcuWRdq0ac25Z+jQobh+/XqMdCdOnECnTp2QM2dOZMiQATVq1MBPP/0U7zx5OqalJL/88ovZxvv3749aF9sxneWI2zopeeM3vmfPHnTo0MHs1/Tp06NEiRLo0aMH/v3333i9fteuXWjVqhWyZ89uylT16tXx3XffxUjH4xTz6r7wd+SMxzJP6eyF29o2ffp0FChQABcvXkz095ck5hAJEtOmTXOEhYU5ypUr53jvvfccy5cvdyxevNgxatQoR7FixRwtW7aMSlu3bl2zJBXmISnfPxB5a5vwsDV48OCoxydOnHCsXbvWceXKlah18+bNM+lee+01x6pVqxzr1683699++22z/t1333WsWbPGsW3bttvOjwQ+9zIVXydPnoz1tZ7KpcTUsGFDR/ny5R3t27d3lCxZ0lGkSJFYN1OjRo0c2bJlc0yZMsWxbNkyx7PPPmu2/6xZs1zS/fnnn47MmTM7ateu7ViwYIHjq6++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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "first half: -3,925 second half: -5,032\n" - ] - } - ], - "source": [ - "cnt_cpu = np.bincount(fr_cpu, minlength=N)\n", - "cnt_cuda = np.bincount(fr_cuda, minlength=N)\n", - "cum = np.cumsum(cnt_cuda.astype(np.int64) - cnt_cpu.astype(np.int64))\n", - "\n", - "fig, ax = plt.subplots(figsize=(9, 3.6))\n", - "ax.plot(cum, color='C1', linewidth=1.2)\n", - "ax.axhline(0, color='gray', linewidth=0.5)\n", - "ax.set_xlabel('Frame')\n", - "ax.set_ylabel('cumulative CUDA - CPU')\n", - "ax.set_title(f'Cluster-count difference accumulating over {N:,} frames '\n", - " f'(final {cum[-1]:+,})')\n", - "ax.grid(alpha=0.25)\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "half = N // 2\n", - "print(f'first half: {cum[half - 1]:+,} second half: {cum[-1] - cum[half - 1]:+,}')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e7b0da01-1787-4260-890d-533accda0e17", - "metadata": {}, - "outputs": [], - "source": [] } ], - "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" - } + "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", + "pd = File(base / 'Cu_factor_10_pedestal_master_0.json')\n", + "\n", + "n_frames_pd = 600 # pedestal frames, taken from the head of the file\n", + "N = 100000 # data frames, read after those\n", + "cluster_size = (3, 3)\n", + "rows, cols = f.rows, f.cols\n", + "image_size = (rows, cols)\n", + "\n", + "N_SIGMA = 5\n", + "N_STREAMS = 4 # H2D / kernel / D2H overlap\n", + "BATCH_SIZE = 2000 # frames per find_clusters_batched call\n", + "\n", + "# CPU workers. ClusterFinderMT gives each thread its own ClusterFinder with its\n", + "# own pedestal, and data frames are handed out round-robin -- so at high thread\n", + "# counts each pedestal tracks on only 1/n of the frames while the CUDA finder's\n", + "# single pedestal sees all of them, and the cluster counts drift apart. Keep it\n", + "# low when comparing counts; raise it to measure CPU throughput.\n", + "N_THREADS = 24\n", + "\n", + "# Fixed per-frame output slot the kernel writes into, copied WHOLE on every D2H.\n", + "# Too low does not error -- it TRUNCATES. The CUDA cell prints the peak actually\n", + "# reached, which is how you size this for a new dataset.\n", + "CAP = 3000\n", + "\n", + "capacity = 3_000 # initial ClusterVector capacity, CPU side\n", + "N_BINS = 200\n", + "E_MIN, E_MAX = -2, 4000 # spectrum range, ADU\n", + "\n", + "print(f'Image size: {image_size} cluster {cluster_size}')\n", + "print(f'Pedestal frames: {n_frames_pd}')\n", + "print(f'Data frames: {N} of {f.total_frames} in file')" + ] }, - "nbformat": 4, - "nbformat_minor": 5 - } + { + "cell_type": "markdown", + "id": "md-build", + "metadata": {}, + "source": [ + "## Build the two finders" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "build", + "metadata": {}, + "outputs": [], + "source": [ + "cf_cpu = ClusterFinderMT(image_size, #only positional argument here i.e. need to use the keyword for next ones\n", + " cluster_size=cluster_size, \n", + " n_sigma=N_SIGMA,\n", + " capacity=capacity, \n", + " min_pedestal_samples=n_frames_pd, \n", + " n_threads=N_THREADS)\n", + "\n", + "sink = ClusterCollector(cf_cpu)\n", + "\n", + "cf_cuda = ClusterFinderCUDA(image_size, \n", + " cluster_size=cluster_size, \n", + " n_sigma=N_SIGMA,\n", + " max_clusters_per_frame=CAP, \n", + " n_streams=N_STREAMS, \n", + " min_pedestal_samples=n_frames_pd, \n", + " algorithm=\"fixed_window\", \n", + " time_kernels=False)" + ] + }, + { + "cell_type": "markdown", + "id": "md-ped", + "metadata": {}, + "source": [ + "## Pedestal\n", + "\n", + "Identical frames into both, so the implementation is the only thing that differs." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "train", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pedestal (600 frames): 1.48s\n" + ] + } + ], + "source": [ + "pd.seek(0)\n", + "t0 = time.perf_counter()\n", + "for _ in range(n_frames_pd):\n", + " pd_img = pd.read_frame()\n", + " cf_cpu.push_pedestal_frame(pd_img.copy())\n", + " cf_cuda.push_pedestal_frame(pd_img.copy())\n", + "print(f'Pedestal ({n_frames_pd} frames): {time.perf_counter() - t0:.2f}s')" + ] + }, + { + "cell_type": "markdown", + "id": "md-io", + "metadata": {}, + "source": [ + "## Read the data frames\n", + "\n", + "Kept out of both timing loops: the two finders run over the same in-memory array." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "io", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading 100000 frames: 50.61s (1,976 FPS, 32.00 GB at 0.63 GB/s)\n" + ] + } + ], + "source": [ + "f.seek(0)\n", + "t0 = time.perf_counter()\n", + "data = f.read_n(N)\n", + "t_io = time.perf_counter() - t0\n", + "gb = f.bytes_per_frame * N / 1e9\n", + "print(f'Reading {N} frames: {t_io:.2f}s ({N / t_io:,.0f} FPS, '\n", + " f'{gb:.2f} GB at {gb / t_io:.2f} GB/s)')" + ] + }, + { + "cell_type": "markdown", + "id": "md-cpu", + "metadata": {}, + "source": [ + "## 1 — CPU, multithreaded" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cpu", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|█| 100000/100000 [00:2\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU MT (24 threads): 25.73s 3,887 FPS 233,104,694 clusters (2331.0/frame)\n" + ] + } + ], + "source": [ + "t0 = time.perf_counter()\n", + "# Pass the frame number: find_clusters(frame) defaults it to 0, and every\n", + "# resulting cluster is then stamped frame 0. Part 2 groups by it.\n", + "for i, frame in enumerate(tqdm(data)):\n", + " cf_cpu.find_clusters(frame, i)\n", + "t_cpu = time.perf_counter() - t0\n", + "\n", + "cf_cpu.stop(); sink.stop()\n", + "clusters_cpu = sink.steal_clusters()\n", + "\n", + "hist_cpu = bh.Histogram(bh.axis.Regular(N_BINS, E_MIN, E_MAX))\n", + "n_clusters_cpu = 0\n", + "for cv in clusters_cpu:\n", + " hist_cpu.fill(cv.sum())\n", + " n_clusters_cpu += cv.size\n", + "\n", + "print(f'CPU MT ({N_THREADS} threads): {t_cpu:.2f}s {N / t_cpu:,.0f} FPS '\n", + " f'{n_clusters_cpu:,} clusters ({n_clusters_cpu / N:.1f}/frame)')" + ] + }, + { + "cell_type": "markdown", + "id": "md-cuda", + "metadata": {}, + "source": [ + "## 2 — CUDA, batched + multi-streamed\n", + "\n", + "`register_input_buffer` page-locks the input once so H2D runs at full DMA\n", + "bandwidth instead of through the driver's staging buffer. It is paid once,\n", + "outside the loop, and released when the dataset is done." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cuda", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CUDA batched: 5.54s 18,057 FPS 233,095,737 clusters (2331.0/frame)\n", + " input pinned in 0.82s, once, outside the loop\n", + " vs CPU: 4.65x\n", + " peak clusters in one frame: 2,545 of CAP 3,000\n" + ] + } + ], + "source": [ + "t0 = time.perf_counter()\n", + "cf_cuda.register_input_buffer(data)\n", + "t_pin = time.perf_counter() - t0\n", + "\n", + "clusters_cuda = []\n", + "t0 = time.perf_counter()\n", + "for start in range(0, N, BATCH_SIZE):\n", + " stop = min(start + BATCH_SIZE, N)\n", + " clusters_cuda.extend(\n", + " cf_cuda.find_clusters_batched(data[start:stop], first_frame=start))\n", + "t_cuda = time.perf_counter() - t0\n", + "\n", + "cf_cuda.unregister_input_buffer()\n", + "\n", + "hist_cuda = bh.Histogram(bh.axis.Regular(N_BINS, E_MIN, E_MAX))\n", + "energies = [np.asarray(cv.sum()).ravel() for cv in clusters_cuda if cv.size > 0]\n", + "if energies:\n", + " hist_cuda.fill(np.concatenate(energies))\n", + "n_clusters_cuda = sum(cv.size for cv in clusters_cuda)\n", + "\n", + "print(f'CUDA batched: {t_cuda:.2f}s {N / t_cuda:,.0f} FPS '\n", + " f'{n_clusters_cuda:,} clusters ({n_clusters_cuda / N:.1f}/frame)')\n", + "print(f' input pinned in {t_pin:.2f}s, once, outside the loop')\n", + "print(f' vs CPU: {t_cpu / t_cuda:.2f}x')\n", + "\n", + "# One ClusterVector per frame, so this IS the per-frame maximum.\n", + "peak = max((cv.size for cv in clusters_cuda), default=0)\n", + "print(f' peak clusters in one frame: {peak:,} of CAP {CAP:,}')\n", + "if peak >= CAP:\n", + " print(' !! CAP REACHED -- clusters were dropped; raise CAP and re-run.')" + ] + }, + { + "cell_type": "markdown", + "id": "md-summary", + "metadata": {}, + "source": [ + "## Summary" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "summary", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " s FPS us/frame clusters\n", + "CPU MT (24 thr) 25.73 3,887 257.3 233,104,694\n", + "CUDA batched 5.54 18,057 55.4 233,095,737\n", + "\n", + "speedup: 4.65x\n" + ] + } + ], + "source": [ + "print(f'{\"\":<22} {\"s\":>7} {\"FPS\":>10} {\"us/frame\":>10} {\"clusters\":>13}')\n", + "for name, t, n in (('CPU MT (%d thr)' % N_THREADS, t_cpu, n_clusters_cpu),\n", + " ('CUDA batched', t_cuda, n_clusters_cuda)):\n", + " print(f'{name:<22} {t:7.2f} {N / t:10,.0f} {t * 1e6 / N:10.1f} {n:>13,}')\n", + "print(f'\\nspeedup: {t_cpu / t_cuda:.2f}x')" + ] + }, + { + "cell_type": "markdown", + "id": "md-part2", + "metadata": {}, + "source": [ + "# Part 2 — Where the two disagree\n", + "\n", + "The two implementations are not bit-identical by construction: the CUDA finder\n", + "updates its pedestal once per frame, the CPU finder per pixel, so once the\n", + "pedestals drift apart a few pixels land on opposite sides of the threshold.\n", + "\n", + "Three views, cheapest first: the **spectra**, the **cluster sets**, and **where\n", + "in the run** the difference accumulates." + ] + }, + { + "cell_type": "markdown", + "id": "md-spec", + "metadata": {}, + "source": [ + "## Spectra\n", + "\n", + "Both curves should lie on top of each other; the ratio panel is the sensitive\n", + "view." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "spectra", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": + "iVBORw0KGgoAAAANSUhEUgAAA3kAAAKACAYAAAAhGrGwAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAlq5JREFUeJzt3Ql4E9XawPE3TVtAhMomgiziAgooLqCCVwUXEARxB68iKPiB4ILcq4JVSnHBFVFZFDfcRa+C3iuo4IaKKKAoAoooiCKyyybQNpnveU+ZkKTpnnYmk//veYZmmUxOTk7CvDnnvMdnWZYlAAAAAABPSHG6AAAAAACA+CHIAwAAAAAPIcgDAAAAAA8hyAMAAAAADyHIAwAAAAAPIcgDAAAAAA8hyAMAAAAADyHIAwAAAAAPIcgDAAAAAA8hyAPgGt99951cddVV0qxZM6latarsv//+cvzxx8v9998vmzdvDu3XsWNHs1WUiRMnypQpUyrs+EgctIVIt99+u3Tv3l0OPvhg8fl80q9fv0Lr7pdffpELL7xQDjjgAPNZPvvss+Xrr7+Oue+rr74qxx57rPncN2zYUIYOHSo7duwo8ftU0sfrbXqf7qP76mP0sbFoWc866yxTdn0N+lr0NZWEfl/17t1bDjzwQFNP559/folfCwDEA0EeAFd48skn5YQTTpD58+fLzTffLO+++65MmzZNLrnkEnn88celf//+lVYWTuxBW4jt4Ycflk2bNsl5550n6enphTaUDRs2yKmnnirLly+XZ555Rl577TXZvXu3+XHmxx9/jNj3pZdekssuu0zatWsnM2fOlKysLPMjiwZVJVGax+ttzz33nNlH99XH6GNffvnliP1++OEHU9acnBxTdn0N+lr0NelrK86dd95pvr+0vr744gvzQxUAVCoLABw2d+5cy+/3W+ecc461e/fuAvfv2bPHeuutt0LXTz/9dLNVlFatWsX9+MFg0Pr777+tRJFIZa1IpWkLOTk5Vm5uruVlgUAgdLl69epW3759Y+538803W2lpadaqVatCt23dutWqW7eudemll4Zuy8vLsxo0aGB17tw54vEvvfSSpacoM2bMKLI8pXn8O++8Y257+eWXI/Y9++yzrYYNG5pj2S655BJTVi2zTV+LvqZbbrnFKs5ZZ51lHXXUUcXup88Z6zsPAMqLnjwAjrvnnnvMkKbJkydLlSpVCtyvPQbac1CYjz/+2Dxe/4ZbtWqVuT186KUOt9JhVDpcS5+rfv36cuaZZ8qiRYvM/YcccogsWbJEPvnkE/NY3fQ227Zt2+Tf//63GVKq5dJhazr8a+fOnRHPrY+77rrrTC/kUUcdZZ5LexCKMnXqVGnfvr1Ur17dDBHr0qWLfPPNNxH76PA4vW/FihXSrVs3c7lx48byr3/9S/bs2ROxr/ZC3HXXXXLkkUea569Xr54ZDhvdE6GvT4fgvfnmm3LccceZYWzZ2dnmPq2Lzp07y3777WceP2TIEHnnnXci6lt7LVJTU+W3334r8JquvvpqqVOnjunFKUxx70l4GbV35JhjjjFlPPTQQ+XRRx8tcLySvkfBYFAee+wxM2SvWrVqZkjeySefLG+//XaxbcFucy+88IKpe30OLbu+L6NGjTL3RdN2qLdru4x+Xf/73/9M3Ws5tL3odfsxel3bxIknnigLFiwQJ6WklOy0Qd+nM844Q5o2bRq6rWbNmqYn7b///a/k5eWZ2+bNmydr16417TKc9uBr29bjFKU0j9fLepveF04f+8cff8iXX35prmvZtP4vuugiU2abvpZOnToVWSb7O2f27NmybNmyULvR9mLfp716+rnU9qlt5qOPPjKfD21H2hYzMjKkdu3a5rvgrbfeKvAc9nfLs88+Ky1atDBtpm3btqYuLMuSBx54wBxbX6u+B9omo2n59DOmr08/26eccop88MEHEfvo98T//d//me8X+/tD99PHAnC/VKcLACC5BQIB+fDDD81QTT2ZqGgaGOlz6olWkyZNZOPGjTJ37lz566+/zP16AnfxxRebEy0dtqnswPPvv/+W008/XX7//Xe57bbbTLChQcDIkSNl8eLF5uQn/OR++vTp8umnn5r7DzroIDM/p6hAV+c76Qmn/tUATU/WdHjYV199JS1btgztm5uba4JeHcKqJ4Zz5swxgZaWWZ/LDmB69uxpnv+WW26RDh06yK+//mqGqekwNA0W9OQwfP6RnpTqc+sJogYVevKsr1cvT5o0yZT/lVdeMSeY4QYOHCh33323PPHEE+bkNXxeks530v01KCvre2LToE+DNQ2itD51mN6NN95o6kqDutK+Rxowv/jii6YeR48ebQJCrQc7CCuqLdhGjBhhTsY1mNcAqKj3uDDffvutOU5mZqZ5Lg2wNRjS2/TE2/4R5NZbbzUB4cqVKyPeO7fZtWuX/Pzzz3LBBRcUuE/fD71fA/vmzZvL999/H7o9XFpamvlxwr6/MKV5vF7WgFl/kIguk32/fk607FrG6GPa+86aNcsEZbHadIMGDczwzMGDB8vWrVtNG1X6+bXnFesPE/raH3zwQRNkHXHEEeYHGr1f27H+YKBtWtuqtgMN5q688sqI59EgVH8Auvfee0Nt49xzz5W+ffuauh0/frx5/mHDhplgVT87drvXNq/H0+8H/eFJ60o/u/qj0nvvvWeCP9WnTx/zedDPtpZXP496XYfrAkgA5e4LBIBy+PPPP80Qqt69e5f4MdHDNT/66CNzDP0bbuXKleb2Z5991lzfuHGjuT5u3LgyDdEbM2aMlZKSYs2fPz/i9v/85z8Fhobp9YyMDGvz5s3Fvp7Vq1dbqamp1vXXXx9x+/bt262DDjooYnibDo/TY7/22msR+3br1s1q0aJF6Porr7xi9nvjjTci9tOy6+0TJ04M3da0aVMzXPbHH38sMOTO5/NZS5Ysibi9S5cuBepby3XggQeaobW2++67z9SXvg+FKel7omXUsixatKjAULuaNWtaO3fuLNV7NGfOHHM9MzOzTG3BbnOnnXZagfuysrLMfdG0Hert4fWhr6tatWrW77//HrpNX6Pup8MQ7delpk+fbm5/++23LTcobLjmmjVrTDn1vYimQyX1Ph2ire6++25zfe3atQX21SGYzZs3L7IMpXn8EUccYdputD/++MMc45577jHXP//8c3NdP0PRdB+9Tx9TFG0z2nZifR8ddthhZmhvccM4dehv//79reOOOy7iPj2Gfi/s2LGjQNs49thjzdBwm36u9PbvvvvOXNf2VLt2batHjx4FhuG2adPGOvHEE0O37b///tbQoUOLLCcA92K4JoCkoUOgDjvsMNNDNnbsWPNLuPZ4lZT+et66dWszpEqHdNmb/gIea7ioDpWqVatWscfVX8/1OPrrevhxtadAe6Wij6vP1aNHjwI9DNpTF15WHX6o+4UfU8uuvWDRx9TH66/14XSYor7e8F5EpYkqommP2vr16+X1118317VetfdPexfCh7uW5z1p1aqVtGnTJuK2f/7zn2Z4pp21saTvkSbdUDr8tDy0l6S8tKzae2PT3ialPa46lC769vD3OZbw113aLZ5iDVkt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0P2jRo2SY489tsCxNSGNPubjjz8u9Pk7duxo9rn33nsL3NetWzdznx5/1apVkpKSEipHrE33K03Aoa+9d+/e5vrmzZtNPbRo0cK8xiZNmsgNN9wgW7dujXjceeedZ+6rWrWqyQDZp08f+eOPP0L365ID55xzjjRs2DBUn9ddd50ZQVeUyZMnm7qoWbOmeS2xluPYsmWLeT4diaebXi5s2Y5NmzZJo0aNCj1WtC+++ELOOOMMqV69ulnGoFOnTrJr167Q/V9//bWcffbZ5j5NMPR///d/smPHjlI9d/fu3c1tFR1YE+QB8KzcgCU5gX2/lGkQp0MyY9Fhmhr82Vvz3FdleGBwJZYWAOAEDZxOOOEE+fDDD+X++++XxYsXy7vvvmtO8HVqT7jRo0fL2rVr5bvvvpPzzz9fBg0aJFOnTo1LOTQQevbZZyNu08BJy2Wn0td99DYtg27/+te/pFWrVqHruv373/8u8XM++uijctVVV5nA0X4+3R588EFTD1OmTDF10b9//4jHad289tpr8uOPP8obb7whP//8s1x88cWh+/V4PXv2lLfffluWL19ujjN79mxTX0XR5QM0OLztttsK3eef//ynLFq0yJRLN72sgV4s/fv3l2OOOaZEdaEBnj53586d5auvvpL58+eb9z+8bs466yw5/PDD5csvvzTPvWTJEunXr1+pn1vr/LHHHpMKZSW5rVu3WloN+tctgsGgtWXLFvMX1LkXVVYbb3nbW2YriyNum2FdOvwBa8/I2mbbMfJAK5HxvUKdex1t3Nk637Vrl7V06VLzN9F07drVOvjgg60dO3YUuE9fn61p06bWww8/HHH/EUccYfXu3dtczsrKstq0aRPzGHqu+dFHHxVahtNPP9269tprrTp16lifffZZ6Pa7777b6tGjhznuyJEjrdzc3Ij/Owt7zpLYsGGD5fP5rO+//77I/V577TUrPT3dPHdh3nrrLXOsnJycQvd55JFHrEaNGpWobFpXWmfh9a+0jent8+bNC932xRdfmNt++OGHiH0nTpxo6vWDDz6IeaxoJ510knX77bdH3KZ1bdf5E088YR144IFWIBAI3f/NN9+YY//000+leu5Vq1aZ23/++eeYZSnq81TS2IWePACe9U3qVWYrizS/T1L9vtDQTTthCwDAO3R4ovbIaI+NDtGLpsPyiqLDFcuT5j5c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t9xyi2RmZoYCvDfffNM8b7169UzeCe0s0WXIwuk+2pFywAEHSPXq1c259gsvvBCxjy5bdswxx5hj2MeZOXNmseX55JNPzIg8nVOm9fr4449H3K/JevT8/rDDDjP76LrZ7777bsQ+o0aNihgSrNtBBx1U5POG178vbGvVqlWpXvchhxxi6lLfQ/1rH0dHA9ruuOMOswqAGxPiOB7k6YciOgWvblOmTAnto79KrFq1ykzq1SUVTjvttHI/L8M1gcRUXzaZDQCAeNBzTA1GtCfs/vvvl8WLF5tgo1OnThEn9KVxzjnnyNq1a82xNSDSY914443SvXt3ycvbN+VA6Qi1L774Qq677jp5+umny/R8urTYTz/9JJdccknoNu0Y0SBPO0f0/FnLoIHrN998E9pHR85pYKjP/91338lVV11ltvBgsFGjRnLvvfeajhndzjjjDOnZs6csWbKk0PLoyLxu3brJqaeeap7vtttukxtuuCEiE/7tt98uTzzxhDz22GOm91FH6V1wwQUR5VManGld2pu+P0V55JFHIvb/7bffzOsMr5uSvG6d0vXHH3+Yx+tfe/pY+HHOPfdck6E/Onh2BSvJbd26VWdUmr9uEQwGrS1btpi/oM69qDxtfM/I2mZzMzeWke8V6tzraOPO1vmuXbuspUuXmr+JpmvXrtbBBx9s7dixo8B9+vpser44bdq0AvvceOON1umnnx663rdvX6tnz54F9vvggw/MMZ588smI20eNGmX17t3bWrZsmVWjRo2Y5VBaz7m5uTH/77z++uutiy++uNjX2rJlSys7O7vIfY477jjr9ttvL3KfWrVqWU899VSh999yyy3WkUceGXHbwIEDrZNPPjl0vUGDBtb48eMj9tF6u/zyy0PXs7KyrDZt2ljlMW3aNMvn81mrVq0q9esOr3N9nw877LAC9d+vXz+rT58+VjwV9XkqaezieE8eAHiRJodZkdVSmmfOlFYjI4efAADcYfPmzabXTnvsdNheNB3OFy/aA6ZDEnWooE1jx2effVauuOIKOfLII6V58+by2muvlfrY2munww+LYq+7pr1YsWhZdHjqjz/+WOioOc1K/+qrr8rOnTvNsM3CaA+ZDkEN16VLF9MTqMM0lY7Qi14eoFq1avLZZ59F3KY9lA0bNpRmzZpJ79695ZdffpHSePrpp+Wss84qdKpXSV53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Xm7nrlsMPZlt3LjRfODr168fcbte1waIktMP2fPPP29OdNetWyd33XWXdOjQwYyxtusyVj3/+uuv5rLuk56eLrVq1eK9KIN41bH+1YAlmt7GZ6Kgrl27yiWXXCJNmzY1/3HdcccdcsYZZ5j/oPQ/Leq87LTzdNiwYfKPf/zD/MdOO6/8+la08fhbvHixCTB2794t+++/v0ybNk1atmwZOjHle7zy6lzRxuPv1Vdfla+//lrmz5+fVOcrBHkupBNCo/+zi74NRdMvSdvRRx9tvkwPO+wwee6550KJKMpSz7wXpROPOo61P+9DbL169Qpd1hPjtm3bmoDvnXfekQsvvJA6L4frrrtOvvvuO/nss88K3Ec7r7z6po3HX4sWLWTRokUmQcQbb7whffv2lU8++SR0P+278upcAz3aeHz99ttvcuONN8r7779vEhoWxovtnOGaLqIZe/x+f4GIX4dbRf/CgNLRTEga7OkQTjvLZlH1rPvo8FnNlMR7UXrxqmPdR3tio23YsIHPRAk0aNDABHna7qnzstOMam+//bZ89NFH0qhRo9DttPPKre9YaOPlpz0Uhx9+uPlRSDMPtmnTRh555BHatwN1HgttvHwWLlxozis0W31qaqrZNKB+9NFHzWX7fMOL5ysEeS770GsjnDVrVsTtel2HGqLsNPXtsmXLzJelztHTD2N4PeuHVz/0dj3r+5CWlhaxz9q1a+X777/nvSiBeNWx9sDqvJyvvvoqtM+XX35pbuMzUbxNmzaZXzG13VPnpae/wGqP0ptvvikffvihade0c+fqOxbaeMW8D/p/Jt/jlV/nsdDGy+fMM880w2O159TeNLi+/PLLzeVDDz3Uu+crjqR7QbFLKDz99NMmU8/QoUPNEgqrVq2i1krhX//6l/Xxxx9bv/zyi8l0pClsNT2uXY+aRUkzJ7355psmXe5ll10WM11uo0aNrNmzZ5t0uWeccQZLKERlqvrmm2/Mpl8lY8eONZft5T7iVceakljTHWuWKt2OPvropF1Coag61/u03Wva5pUrV1offfSR1b59e5PymTovm2uvvda0Yf0uCV+W4u+//w7tQzuvvPqmjcffiBEjrDlz5pjvjO+++86k89eMge+//765n/ZduXVOG68cp4dl1/RyOyfIc6EJEyZYTZs2tdLT063jjz8+In00SsZe40QD5oYNG1oX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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, (ax_spec, ax_ratio) = plt.subplots(\n", + " 2, 1, figsize=(9, 6.5), sharex=True, gridspec_kw={'height_ratios': [3, 1]})\n", + "\n", + "edges = hist_cpu.axes[0].edges\n", + "cpu_vals, cuda_vals = hist_cpu.values(), hist_cuda.values()\n", + "\n", + "ax_spec.stairs(cpu_vals, edges, label=f'CPU MT ({n_clusters_cpu:,})',\n", + " color='C0', linewidth=1.4)\n", + "ax_spec.stairs(cuda_vals, edges, label=f'CUDA ({n_clusters_cuda:,})',\n", + " color='C1', linestyle='--', linewidth=1.4)\n", + "ax_spec.set_ylabel('Counts')\n", + "ax_spec.set_yscale('log')\n", + "ax_spec.set_ylim(bottom=10)\n", + "ax_spec.set_title(f'Cluster energy spectrum — {N:,} frames')\n", + "ax_spec.legend()\n", + "ax_spec.grid(alpha=0.2)\n", + "\n", + "with np.errstate(divide='ignore', invalid='ignore'):\n", + " ratio = np.where(cpu_vals > 0, cuda_vals / cpu_vals, np.nan)\n", + "ax_ratio.stairs(ratio, edges, color='C1', linewidth=1.2)\n", + "ax_ratio.axhline(1.0, color='gray', linewidth=0.5)\n", + "ax_ratio.set_ylabel('CUDA / CPU')\n", + "ax_ratio.set_xlabel('Energy [ADU]')\n", + "ax_ratio.set_ylim(0.9, 1.1)\n", + "ax_ratio.grid(alpha=0.3)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "md-sets", + "metadata": {}, + "source": [ + "## Cluster sets\n", + "\n", + "Every cluster is keyed by `(frame, x, y)`, so the two results can be differenced\n", + "directly — no per-frame Python loop.\n", + "\n", + "A cluster whose centre moved by one pixel was *relabelled*, not gained or lost,\n", + "so those are counted separately from genuine adds and drops." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "sets", + "metadata": {}, + "outputs": [], + "source": [ + "def cluster_keys(vectors):\n", + " \"\"\"One int64 key per cluster: frame * rows*cols + y * cols + x.\n", + "\n", + " Centres are unique within a frame, so keys are globally unique and the sets\n", + " below need only a sort, never a np.unique.\n", + " \"\"\"\n", + " n = len(vectors)\n", + " sizes = np.fromiter((cv.size for cv in vectors), np.int64, n)\n", + " frames = np.repeat(\n", + " np.fromiter((cv.frame_number for cv in vectors), np.int64, n), sizes)\n", + " xy = [np.asarray(cv) for cv in vectors if cv.size]\n", + " if not xy:\n", + " return np.empty(0, np.int64), frames\n", + " x = np.concatenate([v['x'] for v in xy]).astype(np.int64)\n", + " y = np.concatenate([v['y'] for v in xy]).astype(np.int64)\n", + " return frames * (rows * cols) + y * cols + x, frames\n", + "\n", + "\n", + "t0 = time.perf_counter()\n", + "k_cpu, fr_cpu = cluster_keys(clusters_cpu)\n", + "k_cuda, fr_cuda = cluster_keys(clusters_cuda)\n", + "\n", + "# Sort ONCE. np.setdiff1d and np.isin each re-sort their argument on every call,\n", + "# and the shift check below calls one eight times per direction -- about twenty\n", + "# sorts of a 27-million-element array. Two sorts plus binary search instead.\n", + "s_cpu = np.sort(k_cpu)\n", + "s_cuda = np.sort(k_cuda)\n", + "\n", + "\n", + "def present_in(vals, sorted_keys):\n", + " \"\"\"Which of `vals` appear in an already-sorted key array.\"\"\"\n", + " if sorted_keys.size == 0:\n", + " return np.zeros(vals.size, dtype=bool)\n", + " i = np.searchsorted(sorted_keys, vals)\n", + " np.clip(i, 0, sorted_keys.size - 1, out=i)\n", + " return sorted_keys[i] == vals\n", + "\n", + "\n", + "cpu_only = s_cpu[~present_in(s_cpu, s_cuda)]\n", + "cuda_only = s_cuda[~present_in(s_cuda, s_cpu)]\n", + "\n", + "\n", + "def drop_shifted(only, sorted_other):\n", + " \"\"\"Drop mismatches that have a counterpart within 1 px in the other set.\"\"\"\n", + " keep = np.ones(only.size, dtype=bool)\n", + " for dy in (-1, 0, 1):\n", + " for dx in (-1, 0, 1):\n", + " if dx or dy:\n", + " keep &= ~present_in(only + dy * cols + dx, sorted_other)\n", + " return only[keep]\n", + "\n", + "\n", + "cpu_real = drop_shifted(cpu_only, s_cuda)\n", + "cuda_real = drop_shifted(cuda_only, s_cpu)\n", + "touched = np.unique(np.concatenate([cpu_real, cuda_real]) // (rows * cols)).size\n", + "\n", + "print(f'CPU {k_cpu.size:>12,} clusters')\n", + "print(f'CUDA {k_cuda.size:>12,} clusters net {k_cuda.size - k_cpu.size:+,}'\n", + " f' ({abs(k_cuda.size - k_cpu.size) / k_cpu.size:.4%})')\n", + "print()\n", + "print(f'exact-position mismatches CPU-only {cpu_only.size:>8,} '\n", + " f'CUDA-only {cuda_only.size:>8,}')\n", + "print(f' of which shifted by 1 px {cpu_only.size - cpu_real.size:>17,} '\n", + " f'{cuda_only.size - cuda_real.size:>17,}')\n", + "print(f' genuine add / drop {cpu_real.size:>17,} {cuda_real.size:>17,}')\n", + "print(f'\\nframes touched by a genuine difference: {touched:,} of {N:,}')\n", + "print(f'[{time.perf_counter() - t0:.1f}s]')" + ] + }, + { + "cell_type": "markdown", + "id": "md-drift", + "metadata": {}, + "source": [ + "## Where in the run it accumulates\n", + "\n", + "Cumulative `CUDA − CPU` against frame index. A curve that rises and then flattens\n", + "means the two pedestals settled into agreement and the difference is a start-up\n", + "transient; a steadily sloping line would mean a persistent per-frame bias." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "drift", + "metadata": {}, + "outputs": [], + "source": [ + "cnt_cpu = np.bincount(fr_cpu, minlength=N)\n", + "cnt_cuda = np.bincount(fr_cuda, minlength=N)\n", + "cum = np.cumsum(cnt_cuda.astype(np.int64) - cnt_cpu.astype(np.int64))\n", + "\n", + "fig, ax = plt.subplots(figsize=(9, 3.6))\n", + "ax.plot(cum, color='C1', linewidth=1.2)\n", + "ax.axhline(0, color='gray', linewidth=0.5)\n", + "ax.set_xlabel('Frame')\n", + "ax.set_ylabel('cumulative CUDA - CPU')\n", + "ax.set_title(f'Cluster-count difference accumulating over {N:,} frames '\n", + " f'(final {cum[-1]:+,})')\n", + "ax.grid(alpha=0.25)\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "half = N // 2\n", + "print(f'first half: {cum[half - 1]:+,} second half: {cum[-1] - cum[half - 1]:+,}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7b0da01-1787-4260-890d-533accda0e17", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "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 +}