Ik zie al een aantal pogingen tot uitleg, laat mij er ook één doen.
CPUs zijn alleskunners. Iedere core in een CPU ondersteund de volledige instructieset die die CPU kan uitvoeren. Bijv: iedere core in een moderne server CPU heeft een eigen AVX-unit, om in één keer een berekening op een vector van bijv 8 getallen te kunnen doen. En iedere core heeft een encryption unit. En een integer unit. Iedere CPU core heeft ook zijn eigen instruction unit, creert een eigen instruction pipeline, etc. Hierdoor kan iedere CPU core volledige onafhankelijk van andere CPU cores opereren. In een 4-core processor kan ik zonder problemen één core vermenigvuldigingen laten doen, één core een lijst laten sorteren, één core encryptie laten doen, en één core optellingen laten doen.
Daarnaast zijn delen van de CPU chip bijv bedoelt voor communicatie met PCI devices, etc. Ook dat moet een CPU dus allemaal kunnen.
GPUs zijn er veel meer op gericht om dezelfde operatie (bijv vermenigvuldigen) op héél veel data-elementen tegelijk te doen. In vaktermen heet dit SIMD: single instruction, multiple data (
https://en.wikipedia.org/wiki/SIMD). CPUs doen ook een béétje aan SIMD (neem de vector instruction units waar ik het zonet over had) maar opereren op relatief beperkte hoeveelheid data-elementjes (8 á 16 maximaal in één instructie). Een GPU heeft SMs: streaming multiprocessors. De A100 heeft er bijv 108 (
https://developer.nvidia....re-architecture-in-depth/). Iedere SM op deze chip heeft 64 FP32 cores: die dit zijn cores die alléén single-precision (32-bit) floating point operaties kunnen doen. Daarnaast heeft iedere SM ook nog wat double precision cores, tensor cores, etc. Alle cores binnen een SM kunnen tegelijkertijd maar één operatie doen, omdat iedere SM maar één instruction unit heeft. Dus óf ze zijn allemaal aan het vermenigvuldigen, óf allemaal aan het optellen, etc (vandaar: single instruction). Maar, ze kunnen dat wel op heel veel data elementen tegelijk (64 in dit geval). Met al die FP32 cores samen (bijna 7000 op een A100) kan een GPU in één clock cycle dus véél meer vermenigvuldigingen doen dan een CPU. Ze zijn dan ook heel goed in bijv. matrix-matrix vermenigvuldigingen, waarin je héél veel floating point vermenigvuldigingen wilt doen (en daarna een heel aantal floating point addities).
Ok, klinkt goed, maar waarom gebruiken we de GPU dan niet voor meer workloads? Nou, de clocksnelheid van een GPU is lager. Dus voor één enkele FP32 vermenigvuldiging zal de GPU trager zijn. Daar komt nog de communicatie tussen de CPU en GPU bij: die kost ook tijd. Tot slot zijn er heel veel workloads die niet deze enorme hoeveelheid parallele cores aan het werk kunnen houden, bijvoorbeeld omdat veel verschillende operaties sequentieel moeten gebeuren (stel dat operatie 2 de output van operatie 1 nodig heeft, dan kunnen die niet tegelijkertijd). Nog een leuk voorbeeld: wat als ik een vector 1,2,3...50 heb, en ik vervolgens alle getallen onder de 25 ga verdubbelen, en alle getallen boven de 25 halveren? Ik zet dan een if-statement in mijn code. Een CPU kan dat zonder problemen doen. Een GPU zal alle 50 operaties in één SM doen, maar voert
beide branches (zowel de 'if', als de 'else') op álle data uit, en selecteert dan de juiste output om terug te kopieren naar het geheugen. Dubbel werk dus! Code die veel brancht is dus in het bijzonder ongeschikt voor een GPU.