129
12 мая 2026
Benchmark SAXPY на cuda-core v1.0.0: A100 vs RTX 4090 vs RTX 3090 — реальные цифры
Замерили реальную полосу пропускания памяти на A100 80GB, RTX 4090 и RTX 3090 через cuda-core v1.0.0. SAXPY 100M элементов, 5 прогонов — без маркетинга, только числа
После выхода cuda-core v1.0.0 мы решили проверить практическую сторону: насколько эффективно новый Python API использует GPU-память? Классический тест — SAXPY (Single-precision A·X Plus Y), операция вида out[i] = alpha * x[i] + y[i].
SAXPY читает два массива и пишет один — суммарно 3 операции с памятью на элемент. При известном размере массива легко посчитать эффективную полосу пропускания (GB/s) и сравнить с теоретическим пиком GPU.
Методология
Что меряем: эффективная пропускная способность памяти (Memory Bandwidth)
Формула: BW (GB/s) = 3 × N × 4 байта / время (секунды) / 1e9
Где:
- 3 — три обращения к памяти (read x, read y, write out)
- 4 байта — размер float32
- 5 прогонов, берём среднее и минимум (пиковое значение)
Прогрев (warmup): один запуск перед измерением — исключает эффекты холодного старта JIT и кэша L2.
Синхронизация: stream.sync() после каждого запуска — точное измерение именно времени выполнения ядра.
from cuda.core import (
Device, DeviceMemoryResource, DeviceMemoryResourceOptions,
Program, LaunchConfig, launch
)
from cuda.bindings import driver as cuda_driver
import numpy as np, time
SAXPY_SRC = r"""
__global__ void saxpy(float alpha, float* x, float* y, float* out, size_t n) {
size_t tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < n) out[tid] = alpha * x[tid] + y[tid];
}
"""
def bench(n, n_repeat=5):
d = Device(0); d.set_current()
stream = d.create_stream()
mr = DeviceMemoryResource(d.device_id, DeviceMemoryResourceOptions())
prog = Program(SAXPY_SRC, code_type="c++")
mod = prog.compile("cubin", ("saxpy",)) # v1.0.0: name_expressions обязателен
kernel = mod.get_kernel("saxpy")
nbytes = n * 4 # float32
x_buf = mr.allocate(nbytes, stream=stream)
y_buf = mr.allocate(nbytes, stream=stream)
out_buf = mr.allocate(nbytes, stream=stream)
# Инициализация нулями
cuda_driver.cuMemsetD32Async(x_buf.handle, 0, n, stream.handle)
cuda_driver.cuMemsetD32Async(y_buf.handle, 0, n, stream.handle)
stream.sync()
block = 256
grid = (n + block - 1) // block
cfg = LaunchConfig(grid=grid, block=block)
alpha = np.float32(2.0)
# Warmup
launch(stream, cfg, kernel, alpha, x_buf.handle, y_buf.handle, out_buf.handle, np.uint64(n))
stream.sync()
times_ms = []
for _ in range(n_repeat):
t0 = time.perf_counter()
launch(stream, cfg, kernel, alpha, x_buf.handle, y_buf.handle, out_buf.handle, np.uint64(n))
stream.sync()
times_ms.append((time.perf_counter() - t0) * 1000)
x_buf.close(); y_buf.close(); out_buf.close()
bytes_rw = 3 * nbytes # read x, read y, write out
avg_ms = sum(times_ms) / len(times_ms)
bw_gbs = bytes_rw / 1e9 / (avg_ms / 1000)
return avg_ms, bw_gbs
Полный код бенчмарка: github.com/IntelionCloud/research-examples/cuda-core/
Стенды
| GPU | Архитектура | Теор. BW | Драйвер | CUDA |
|---|---|---|---|---|
| A100 80GB PCIe | Ampere (sm_80) | 1935 GB/s | 580.126 | 12.x |
| RTX 4090 24 GB | Ada Lovelace (sm_89) | 1008 GB/s | 580.126 | 13.0 |
| RTX 3090 | Ampere (sm_86) | 936 GB/s | 535.288 | 12.2 |
cuda-core версия: 1.0.0 на всех стендах.
Результаты
A100 80GB PCIe — детальные данные
Компиляция ядра: 50.9 мс (первый запуск; из кэша — ~0.05 мс)
| Размер | avg, мс | BW avg, GB/s | BW peak, GB/s | % от пика |
|---|---|---|---|---|
| 1M | 0.016 | 734* | 918* | — |
| 5M | 0.047 | 1280 | 1312 | 68% |
| 10M | 0.088 | 1370 | 1440 | 74% |
| 50M | 0.389 | 1543 | 1557 | 80% |
| 100M | 0.758 | 1584 | 1595 | 82% |
*1M — попадает в L2-кэш A100 (40 MB). L2-эффект на 5M уже частичный.
Итог A100 80GB PCIe: 1584 GB/s при 100M элементах — 82% от теоретического пика 1935 GB/s.
RTX 4090 — детальные данные
Компиляция ядра: 15.5 мс (первый запуск; из кэша — ~0.05 мс)
| Размер | avg, мс | BW avg, GB/s | BW peak, GB/s | % от пика |
|---|---|---|---|---|
| 1M | 0.009 | 1285* | — | — |
| 5M | 0.018 | 3364* | — | — |
| 10M | 0.130 | 920 | 953 | 91% |
| 50M | 0.648 | 926 | 927 | 92% |
| 100M | 1.292 | 929 | 930 | 92% |
*1M и 5M попадают в L2-кэш GPU (72 MB у 4090) — показатели нереалистично высоки.
Итог RTX 4090: 929 GB/s при 100M элементах — 92% от теоретического пика 1008 GB/s.
RTX 3090 — детальные данные
Компиляция ядра: 26.4 мс
| Размер | avg, мс | BW avg, GB/s | BW peak, GB/s | % от пика |
|---|---|---|---|---|
| 1M | 0.025 | 473* | — | — |
| 5M | 0.083 | 724* | — | — |
| 10M | 0.153 | 783 | 786 | 84% |
| 50M | 0.716 | 838 | 839 | 90% |
| 100M | 1.416 | 848 | 851 | 91% |
Итог RTX 3090: 848 GB/s при 100M элементах — 91% от теоретического пика 936 GB/s.
Сравнение GPU
| GPU | Теор. BW | Замеренный BW | Эффективность | VRAM | Тип памяти |
|---|---|---|---|---|---|
| A100 80GB PCIe | 1935 GB/s | 1584 GB/s | 82% | 80 GB | HBM2e |
| RTX 4090 (тест: 24 GB) | 1008 GB/s | 929 GB/s | 92% | 24–48 GB | GDDR6X |
| RTX 3090 | 936 GB/s | 848 GB/s | 91% | 24 GB | GDDR6X |
A100 опережает RTX 4090 по абсолютной пропускной способности в 1.7× (1584 vs 929 GB/s) за счёт HBM2e. RTX 4090 и 3090 показывают более высокую эффективность (92% vs 82%) — у GDDR6X ниже латентность строчных операций, что хорошо для таких же шаблонов как SAXPY.
Для задач с терабайтами данных (обучение больших моделей, инференс с batch > 100) разрыв A100 vs RTX 4090 только растёт — HBM2e рассчитан на устойчивую высокую пропускную способность без троттлинга.
Эффект L2-кэша
На малых размерах измеренная полоса аномально высока — данные помещаются в L2-кэш GPU:
- A100 80GB L2: 40 MB
- RTX 4090 L2: 72 MB
- RTX 3090 L2: 6 MB
Примерные границы L2-эффекта (три массива × float32):
- 1M элементов = 12 MB → у всех трёх GPU в L2
- 5M элементов = 60 MB → у 4090 в L2, у A100 и 3090 — нет
Поэтому для надёжных цифр реальной пропускной способности VRAM нужны массивы 10M+ элементов (40 MB+).
Время компиляции
Одна из ключевых фич cuda-core v1.0.0 — InMemoryProgramCache. Как это работает на практике:
| A100 PCIe | RTX 4090 | RTX 3090 | |
|---|---|---|---|
| Первая компиляция | 50.9 мс | 15.5 мс | 26.4 мс |
| Из InMemoryCache | ~0.05 мс | ~0.05 мс | ~0.05 мс |
| Ускорение | 1018× | 310× | 528× |
A100 с sm_80 компилирует дольше всех — JIT генерирует больше инструкций для HBM. Но при повторных запусках разница исчезает: из кэша все получают одинаковые ~0.05 мс.
Почему у A100 эффективность ниже, чем у RTX 4090?
Важное уточнение: все три GPU в этом тесте использовали 100% своих SM. При 100M элементах и block=256 получается 390 625 блоков — с избытком хватает для загрузки 108 SM (A100), 128 SM (RTX 4090) и 82 SM (RTX 3090). SM-утилизация тут ни при чём.
Разные проценты отражают, насколько хорошо SAXPY-паттерн (простой последовательный стриминг) насыщает архитектуру памяти каждого GPU:
- GDDR6X (RTX 4090, RTX 3090) хорошо работает с последовательным доступом — 91–92%
- HBM2e (A100) спроектирован под массивно-параллельный доступ: тысячи одновременных разрозненных запросов, матричные операции. Один линейный SAXPY не насыщает все HBM-стеки одновременно — 82%
Это не значит, что A100 «менее эффективна» в целом. На transformer attention, крупных matmul и scatter/gather операциях картина будет другой. SAXPY — синтетический тест пиковой BW, а не задача, под которую A100 оптимизирован.
Выводы
-
A100 даёт в 1.7× больше абсолютной пропускной способности (1584 vs 929 GB/s). Для задач с большими батчами и длинными контекстами — выбор A100.
-
Проценты эффективности отражают совместимость паттерна доступа с архитектурой памяти, а не SM-утилизацию. Все три GPU в тесте полностью загружены.
-
InMemoryProgramCache критичен для продакшн-кода — 300–1000× ускорение при повторных компиляциях одного ядра.
-
Для надёжных цифр реальной BW нужны массивы > L2: 10M+ элементов (40 MB+).
Хотите запустить свои GPU-задачи? Арендуйте RTX 4090 или RTX 3090 в Intelion Cloud — оплата по минутам, без обязательств.
#GPU
#A100
#RTX 3090
#CUDA
#NVIDIA
#Python
#ML
#cuda-core
#SAXPY
#benchmark
#RTX 4090
#пропускная способность памяти
#GPU программирование
#[RTX 4090](https://intelion.cloud/gpus/nvd_rtx4090_48gb)
#[RTX 3090](https://intelion.cloud/gpus/nvd_rtx3090_24gb)