hyperion/10-linux/30-computer-arch/GPU CPU.md

6.9 KiB
Raw Blame History

Ты абсолютно прав насчет того, что GPU — это "много слабых процессоров", но твои догадки про отсутствие кэша и памяти не совсем верны. Давай разберем "кишочки" архитектурно, используя правильные термины.

Главное отличие можно описать одной фразой: CPU оптимизирован под Latency (задержку), а GPU — под Throughput (пропускную способность).

1. Архитектура кристалла (Die Layout)

Если посмотреть на фото кристалла под микроскопом, разница бросается в глаза:

  • CPU: Огромную часть площади занимает Control Unit (блок управления) и Кэш (L1/L2/L3). Сами вычислительные блоки (ALU — Arithmetic Logic Unit) занимают меньшую часть места.
    • Зачем: CPU — это менеджер-бюрократ. Его задача — выполнять сложные, запутанные инструкции, где много условий if/else. Он тратит миллиарды транзисторов на Branch Prediction (предсказание ветвлений) и Out-of-Order Execution (внеочередное исполнение), чтобы угадать, какую инструкцию ты захочешь выполнить следующей, пока текущая еще считается.[3][5]
  • GPU: Почти весь кристалл забит тысячами мелких ALU. Control Unit крошечный и тупой.
    • Зачем: GPU — это армия рабочих. Им не нужно гадать. Им дают команду: "Умножь эти 10 миллионов чисел на 2". Им не нужен сложный менеджмент, им нужна грубая сила.[1]

2. SIMD и "Проблема ветвлений"

Это, пожалуй, самое главное "кишечное" отличие.

  • CPU (SISD/MIMD): Каждое ядро может делать что-то свое. Одно ядро играет музыку, другое считает физику.
  • GPU (SIMT - Single Instruction, Multiple Threads): Ядра GPU сгруппированы в "пачки" (у NVIDIA это называется Warp, обычно 32 потока).
    • Как это работает: Блок управления посылает одну инструкцию сразу на 32 ядра. Все 32 ядра обязаны сделать одно и то же действие, но с разными данными.
    • Где GPU умирает: Если ты напишешь код с условием if (x > 0) { do_A() } else { do_B() }, и внутри одного варпа у половины потоков x > 0, а у другой нет, происходит Warp Divergence. Сначала половина ядер делает do_A, пока вторая половина простаивает и ждет, а потом наоборот. Производительность падает в разы. CPU такие ветвления щелкает как орешки.[6][3]

3. Миф про память и кэш

Твое предположение, что у GPU нет кэша и он не работает с памятью — неверно.

  • Память (VRAM): У GPU есть свой контроллер памяти, и он намного мощнее, чем у CPU.
    • Шина данных CPU: узкая (64-128 бит), но с низкой задержкой.
    • Шина данных GPU: огромная (128-384 бит и более, память GDDR6X). Это широченная труба. GPU может прокачивать терабайты данных в секунду.
  • Кэш: У GPU есть кэши L1 и L2, и даже Shared Memory (управляемый вручную кэш). Просто они работают иначе. Они нужны не для того, чтобы хранить данные долго (как у CPU), а чтобы "склеивать" (coalescing) запросы. Если 32 потока просят 32 соседних байта из памяти, GPU объединит их в один запрос. Если они просят данные вразнобой — GPU "захлебнется".[5][6]

4. Ответ на Rust-часть: "Графический инжиниринг"

Ты правильно уловил суть. Когда ты пишешь на Rust под GPU (будь то wgpu для графики или burn/candle для ML), ты занимаешься оркестрацией:

  1. Host Code (CPU/Rust): Ты подготавливаешь данные, загружаешь текстуры/веса в VRAM (через шину PCIe) и формируешь Command Buffer (список команд).
  2. Device Code (Shader/Kernel): Ты пишешь (или библиотека генерирует) маленькие программы (шейдеры на WGSL/GLSL или ядра CUDA), которые загружаются на GPU.
  3. Dispatch: Ты с CPU пинаешь GPU: "Выполни вот этот шейдер 1 миллион раз".

Твое взаимодействие "напрямую с видеокартой" заключается в правильном управлении памятью и создании таких структур данных, чтобы тысячи глупых ядер GPU могли читать их линейно, не прыгая по памяти (иначе потеряешь всю мощь).

Итог: GPU — это не просто много слабых CPU. Это архитектура, где пожертвовали управлением и логикой ради математической плотности и ширины канала памяти.

1 2 3 4 5 6 7 8 9 10