Reiner Pope – Chip design from the bottom up

Dwarkesh Podcast
22 May 2026 1h 20m
0:00 --:--
Episode Description
New blackboard lecture with Reiner Pope: how do chips actually work - starting with basic logic gates, and working up to why GPUs, TPUs, FPGAs, and the human brain each look the way they do.Reiner is CEO of MatX, a new chip startup (full disclosure - I’m an angel investor). He was previously at Google, where he worked on software efficiency, compilers, and TPU architecture.Watch this one on YouTube so you can see the chalkboard. Read the transcript.Sponsors* Crusoe was one of only five GPU cloud

Summary

This episode delves into the fundamental workings of AI chips, beginning with basic logic gates and the multiply-accumulate operation, which is central to matrix multiplication. It explores the efficiency gains from architectural innovations like systolic arrays, contrasting them with traditional CPU/GPU designs and highlighting the critical role of optimizing compute-to-communication ratios. The discussion also covers chip synchronization via clock cycles, the trade-offs between FPGAs and ASICs, and the impact of memory architectures like caches versus scratchpads on performance and determinism.

Chapters

Fundamentals of Chip DesignThe episode begins by introducing logic gates as the smallest units of chip design and the multiply-accumulate operation as the core primitive for AI chips, explaining its importance in matrix multiplication and the need for higher precision in accumulation.
Building a Multiply Accumulate CircuitThis segment details the construction of a multiply-accumulate circuit using AND gates for partial products and full adders (3-to-2 compressors) for summation, quantifying the gate count and demonstrating the efficiency of this combined operation.
Data Movement Costs and Systolic ArraysThe discussion shifts to the significant overhead of data movement from register files to ALUs in traditional GPUs and introduces systolic arrays as an optimization to reduce communication costs by baking matrix multiplication loops directly into hardware.
Clock Cycles and Chip SynchronizationThis chapter explains the concept of a global clock cycle, how it synchronizes parallel units across a chip, and the critical trade-offs between achieving high clock speed, managing logic delay, and the area cost of inserting pipeline registers.
FPGAs vs. ASICsThe episode compares FPGAs and ASICs, highlighting their respective costs, flexibility, and how FPGAs emulate ASIC programming models using reconfigurable lookup tables (LUTs) and multiplexers (MUXes).
Deterministic Latency and CPU CachesThis segment explores the sources of non-deterministic latency in CPUs, particularly due to cache systems, and contrasts this with scratchpad memory designs in TPUs that offer more predictable and deterministic performance.
GPU vs. TPU ArchitectureThe final chapter compares the high-level architectural organization of GPUs (many small, tiled Streaming Multiprocessors) and TPUs (fewer, coarser-grained Matrix Units), discussing the implications for data movement, scalability, and overall chip design philosophy.

Topics

AI chip designLogic gatesMultiply accumulateMatrix multiplicationFloating point arithmeticCircuit sizeData movementRegister filesSystolic arraysChip clock speedPipeline registersFPGA designASIC designCPU architectureGPU architectureTPU architectureCache memoryScratchpad memoryBranch predictionEnergy consumptionLow precision arithmetic

People

Rainer Pope (guest) Dwarkesh (host) Ron Minsky (mentioned) Dan Pontecorvo (mentioned) Clark (mentioned) John Von Neumann (mentioned)
Key Concepts (22)
Logic gates — Fundamental primitives of chip design like AND, OR, and NOT, which are connected by physical metal traces to perform computations.
Multiply Accumulate (MAC) — The fundamental primitive operation for AI chips, combining multiplication of two numbers with the addition of a third, crucial for matrix multiplication.
Precision in Accumulation — The necessity for higher precision in the accumulation step of multiply-accumulate operations because rounding errors accumulate quickly when summing many low-precision numbers.
Full Adder (3-to-2 compressor) — A logic gate that adds three single-bit numbers and produces a two-bit output (sum and carry), effectively compressing three input bits into two output bits.
Data Multiplier — A standard, area-efficient approach for implementing multipliers using full adders, where the number of full adders required scales with the product of the bit widths.
Quadratic Scaling with Bit Width — The principle that the circuit area required for multiplication scales quadratically with the bit width, making lower precision arithmetic significantly more favorable and efficient for neural networks.
Data Movement Cost — The significant circuit area and power consumed by moving data between different parts of a chip, such as from register files to logic units, which often outweighs the cost of the computation itself.
MUX (Multiplexer) — A circuit that selects one of several input signals and forwards the selected input to a single output line, constructed from AND and OR gates.
Systolic Array — A specialized hardware architecture that bakes entire matrix multiplication loops into fixed-function logic, reducing data movement costs by storing matrix weights locally and reusing them for many vectors.
Global Clock Signal — A synchronization mechanism in chips where all circuitry pauses and synchronizes at regular intervals (e.g., every nanosecond) to ensure operations proceed in lockstep.
Pipeline Register Insertion — An optimization technique in chip design where registers are strategically inserted into long logic paths to break them into smaller, faster segments, enabling higher clock speeds at the cost of increased area for storage.
Clock Domain Crossings — Specific points in a chip where signals transition between different clock domains, requiring careful design to manage potential non-determinism in timing and ensure data integrity.
FPGA (Field-Programmable Gate Array) — A reconfigurable integrated circuit that allows users to program its logic gates and interconnections in the field, offering flexibility for changing designs but at a higher cost and lower energy efficiency compared to ASICs.
ASIC (Application-Specific Integrated Circuit) — A custom-designed integrated circuit optimized for a particular application, offering superior performance and energy efficiency but with very high upfront design and manufacturing costs due to the need for a full tape-out.
LUT (Lookup Table) — A fundamental component in FPGAs that functions as a programmable gate, capable of implementing any Boolean function of its inputs by storing a truth table and looking up the corresponding output.
CPU Cache — A small, fast memory that stores copies of data from frequently used main memory locations, significantly speeding up CPU operations but introducing non-deterministic latency due to unpredictable cache hits or misses.
Scratchpad Memory — A type of memory architecture where software explicitly manages data movement between local, fast memory and off-chip memory, providing deterministic latency unlike CPU caches.
Branch Predictor — A component in CPUs that attempts to guess the outcome of conditional branches in advance to avoid pipeline stalls, crucial for maintaining high clock speeds but adding significant complexity and die area.
Dynamic/Switching Power — The primary component of energy consumption in a chip, resulting from the charging and discharging of capacitors when bits toggle between zero and one.
GPU Streaming Multiprocessor (SM) — A core processing unit in GPUs, characterized by a regular grid of many small, almost identical units, each containing vector units and often tensor cores.
TPU Matrix Unit (MXU) — A coarser-grained processing unit in TPUs, typically a large systolic array optimized for matrix operations, with fewer units compared to GPU SMs, allowing for larger systolic arrays.
Suspendable Systolic Array — A concept for systolic arrays that can dynamically adjust their size or behavior, allowing for both large-scale and small-scale operations, mentioned by MatX.
References (11)
Maddox company
NVIDIA company
ClusterMax report by SemiAnalysis article
Crusoe company
SemiAnalysis company
NVSentinel by NVIDIA software
Cursor tool
TSMC company
Jane Street company
Grok company
Factorio
Transcript (91 segments)
Speaker 1

I'm back with Rainer Pope who is the CEO of Maddox which is a new AI chip company. Last time we were talking about what happens inside a data center. Now I understand what happens inside an AI chip.

How does a chip actually work? Full disclosure, by the way, I am an angel investor in Maddox. So hopefully you have designed a good chip.

Also, you're listening to this on an audio platform, it's much preferable to watch this Blackboard lecture on a platform where you can see what's happening, so switch over to YouTube or Spotify.

Speaker 2

So I'll start with sort of the very smallest fundamental unit of of chip design, and we'll sort of build up into what an overall, like, actual production chip, what are the components of that. Yep. At the very bottom level of a chip, the primitives that we work with are logic gates, which are very simple things like and or not.

And then these are connected together by wires that have to be laid out physically as metal traces on a chip. The main function that AI chips want to compute is multiplication of matrices, and really inside that is the fundamental primitive is multiply accumulative, just like of pairs of numbers. So, we're going to demonstrate what that calculation looks like by hand, and then infer what a circuit would look like for that.

It'll turn out to be easiest if I do multiplication accumulative, something like a four bit number with another four bit number. And then we're going to the actual clearest primitive is actually multiply accumulate. So there's a multiply these two terms and then we're going to add in, so product of these two terms and then we're going to add in an eight bit number.

Speaker 1

And and can I ask a clarifying question?

Speaker 2

you know, whatever computation happens inside a computer? Yeah. So there there's a few reasons for this.

It it's a little bit more efficient, but the the reason it's natural for AI chips is that if you look what's happening during a matrix multiply, the what is matrix multiply? In very short, it is there's a for loop over I and over j and over k of output I k plus equals to input I j times other input j k. And so multiply accumulate happens at every single step of a matrix multiply.

Makes sense. And then the other observation is that the precision will almost always be higher in the accumulation step than in the multiplication step. This is maybe specific to AI chips, but you're you're multiplying low precision numbers, but then when you accumulate, errors accumulate quickly, and so you need more precision here.

So this is why we've chosen to do a four bit multiplication and an eight bit addition.

Speaker 1

Let me make sure I understood that. There's two ways to understand that.

Speaker 2

maybe that that part is like less intuitive to me, but it's maybe the same principle? It it is really the same principle. I guess the sort of I mean, I guess the the separate principle is that as you are summing up this number, you are summing up a whole bunch of numbers, and so you've got a lot of rounding errors accumulating.

Whereas in this case, there's, like, there's there's only one multiplication in that chain, so there's not a lot of rounding errors accumulating in the multiplication.

Speaker 1

Are you summing up a whole bunch of numbers? Is just two numbers? Just, I mean, the summation happens.

Speaker 2

j So, j many

Speaker 1

yeah, any errors accumulate. I see. Yes.

Yep. Makes sense. So how would we perform this calculation by hand?

Speaker 2

I mean, as a human, we would probably separate it into two, but we can sort of do it all in one using long multiplication. So the multiplication term first. We're going to multiply this number, this four bit number here, by every single bit position in the other four bit number.

So we write that out. First one zero zero one multiplied by this bit position. That is this number itself.

Then shift it across by one, we're multiplying by zero. That gives us an all zeros number. Shifted across even one more to multiply by this one, we get one zero zero one.

And then finally for this last last bit position, we get an all zeros number again. So this this sort of gives us a bunch of terms that we're gonna have to add for the for the modification. And then while we're doing that summation of this, we might as well add in the actual accumulated term as well.

So we just copy that directly across. So so this is the sum. It's a it's a five way sum that we're going to want to commute compute.

So firstly, what what logic gates did it take us to even get to this intermediate step? We needed to produce all 16 of these partial products. Mhmm.

How do I produce one of these partial products? So let's take this this number one for example here. It is one.

So what was it how do we produce this number by multiplying this number by this one over here? We can actually produce that by an AND gate. This number is one if both this bit is one and this bit is one.

Yep. If either of them is zero, then the multiplication of one times one of zero times anything is zero. So to produce all of this stuff, we ended up consuming 16 and gates.

Mhmm. Or in the general case, if I were doing a, like, a p bit multiply times a q bit multiply, then this will be like p times q, many ands. Exactly.

Finally I sum them. Actually most of the work is gonna happen in the summing. And so let me describe sort of the other logic gate that we use here.

AND is almost the simplest logic gate that exists on a chip, it's it's it's almost the smallest. At the other extreme, typically the very largest logic gate that you'll use is something called a full adder. And what this does is sort of it does coming from software, you might think that a full adder, it adds 32 bit numbers together.

In this case, it just adds three single bit numbers together. And so you can think of it as like adding zero, one, and one together. Now when I add these together, the result can be zero, one, two, or three.

So I can express that in binary using just two bits. So as input, it has three bits, and as output, it has two bits, which in this case, the number two in binary is one zero. So this is also known as a three to two compressor because it takes three bits of input and produces two bits of output.

Speaker 1

an x and a by value and then some carry that came in from like

Speaker 2

The sorry. The the the three inputs are all all bits that are in the same sort of bit position, like three bits that are in a column here. Yeah.

Yep. And then the two outputs, I have sort of drawn them vertically here and horizontally here to kind of match this vertical versus horizontal layout here, which is expressing that things that are in the same column are in the same bit position. Yeah.

Whereas things that are in adjacent columns, like this is a carry out, whereas this was the sum. So if the inputs in the full adder are, let's say, like, one zero one, then the output would still be one zero. If it was one one one, it'd be one one.

If was zero zero zero, it'd be zero zero. If was, like, zero one zero, it'd still be zero one. So yeah, it's just counting essentially the number of things and expressing that in binary.

So this circuit actually can sort of capture what we as humans naturally do when we're doing summing along the column. So I can show that sort of, I'll show sort of one iteration of using the full adder to sum. The way I sum here is going be a little bit unnatural for humans.

Humans, we would sort of sum along the column and then remember the carry. But instead of remembering the carry, we'll actually just explicitly write it out. So in this, we proceed from the rightmost column towards the left.

On the rightmost column we sum the one and the one. And that produces like a zero here and a carry of one. So we've sort of used this full adder circuit on this pair of bits and produced a pair of bits as output.

Now we can do the same thing with this column. We've got a column of one, two, three, four numbers. And so maybe we'll like take the first three of them, run a full adder on them, and that gives us a zero and a zero as output.

So the sum of these is zero zero. So that's the full adder applied to all of these bits. As I've used up bits, I'm gonna sort of just cross them out to indicate that I've handled them.

Let's just keep going a little bit more. So we'll go here. I take these three numbers, I add them.

That gives me a one and a zero. I've dealt with these three numbers. And now I take one, two, and I can even take these three numbers, for example, right now, and add them, and that gives me a one and a zero, and I've dealt with these numbers.

So I can sort of like, the way I should view this is that I have this whole grid of numbers that need to be added. I'm going to just keep applying full adders to all the bits that are here, constantly removing three numbers from a column and then writing out two numbers as output. Keep going with this over and over and over and again until I eventually get like some just one single number coming out here.

Something like that. This is probably the wrong sum. So this approach that I've described here, this is called a data multiplier.

And this is sort of like the standard for how you do area efficient multipliers using full adders. Let's try and quantify the circuit size of this just so we have got a sense of how big things are so we can compare to them later. How many full adders did I use?

I started with how many numbers? I have the 16 partial products, which is the product of all of these terms with all of these terms, plus the eight terms that I'm adding here. So I started off with 24 bits, and then I produced eight bits on the output eventually.

And in every step I was sort of crossing off three numbers and writing two numbers out a result. And so every single use of a full adder eliminates one of the bits here. And so how many full adders?

It must be the twenty four minuteus the eight. So there were 16 full adders in this circuit.

Speaker 1

in this circuit. Are you sure I understand the logic of that? So the input bits 24 is p times q plus p plus q.

That's right. And the output bits is just p plus q.

Speaker 2

p plus q equals p times q. That's right. So I think this explains sort of, or at least hints at, the second reason why we chose to do a multiply accumulate.

First reason being that's actually what shows up in matrix multiplication, but second reason being it gave us this very slick p times q, very simple algebra. Mhmm. So we've sort of described, like, this whole procedure, every single atomic step that I took here becomes a logic gate, and then sort of the wires connected together.

Like, when I had these three inputs that that I salvaged to produce these two outputs, like, if I think of mapping this to a physical device, there would be a wire that runs sort of connecting all three of these things together into a logic gate that produced this output. Okay. So this is the the main primitive at different bit widths that that is that is inside an an AI chip.

Speaker 1

how would you use that to run all the other operations you may want. This might be the wrong time to ask this question, but whenever NVIDIA reports that this chip can do x many f p four or half as many f p eight. It seems to imply that those circuits are fungible, that there's not as dedicated, like, f p four versus f p eight.

But the way you're you're mapping it out here, seems like you would need if it has to be mapped out in the logic, you would need a dedicated f p four multiply accumulate and then a dedicated f p eight accumulate.

Speaker 2

Basically, can you can you fudge them? As drawn, they're actually not particularly fungible. This is actually one of the main choices you have to make when designing a chip, which is how much of f p four, how much of f p eight do I have?

And then sometimes I'll make that consideration from the point of view of what do I think is the customer requirement. Another way to take an angle on that is to say what is the power budget for equalize the power budget between FP four and FP eight.

Speaker 1

and they just happen to be the case of like, it does two x as many f p four as f p eight.

Speaker 2

Why Like, is the ratio exactly 2x? Yeah. Exactly.

Yeah. So, part of it is I mean, surely that won't be exactly equivalent to die area. There's a data movement reason, actually, and we'll maybe come back to this when we sort of look through how it goes into and out of memories.

Speaker 1

actually makes that work out really really nicely. Actually, come to think of it, it's not just two x.

Speaker 2

quadratic. It's quadratic in fact. Yeah.

Speaker 1

The BitLink. So that's why smaller precision is like even more favorable than your This a really big reason.

Speaker 2

in fact NVIDIA made a change. Historically up until b 100 or b 200, every time you have the bit precision, you double the flop count. That ratio is exactly like for the reason you said, because of this quadratic scaling, that ratio is actually slightly wrong.

It should be like an even bigger you should get an even bigger speed up than you might otherwise think. NVIDIA's product specs have sort of started acknowledging that in b 300 and beyond, where the FP four is three times faster than the FP eight. Though it should be four x.

Yeah. What I've shown here is the simplest case of integer multiply. When you're dealing with floating point as you do in f b four and f b eight, there's this other term which is the exponent that just complicates So what can we see already from this?

Think the big observation you've made is that there's this quadratic scaling with bit width, which is very effective and is the single reason why low precision arithmetic has worked so well for neural nets. But the other thing we're going to do now is we're going to compare the area spent on the multiplication itself with all of the circuitry that is around it. So we'll walk back in time a little bit and see how did GPUs prior to Tensor Cores work, which is the same way as the way that CPUs worked, fact.

So which is like, where do we stick this multiply accumulate unit? Generically, I'll describe like a CUDA core or a CPU. You'll have some register file, which stores some number of entries.

Maybe maybe it's like eight eight entries of of, like, in this case, I guess, four bit numbers, but typically, like, 32 bit numbers or something like that of which are just numbers. So this is the like, inside the CUDA core, I'll have some register file and some depth, and then I will have my multiply accumulate circuit, multiply and accumulate circuit. And what it's gonna do, it's gonna, like, it's going to take three arbitrary registers from this register file, perform the multiply accumulate, and then write back to the register file.

So it's going to maybe write to this one, but was able to read from this one, this one, and another random one. So it'll take three inputs like this. So this is the core data path of many processes.

Most processes look like this. You've got some set of registers and then you've got some set of logic units or ALUs. We want to analyze the cost of the data movement from the register file to the ALU and back.

So ultimately there's going to be some circuit that says, well, I don't always have to select this guy. I might select any of the registers at any point in time. And so a first question is, how can I build a circuit?

The circuit that I'm going to look for is a MUX. So in this case, it's going to have eight inputs, one from each entry of the register file. And it's going have one output, which is actually producing this output.

And then what is the cost of this thing? All we have to build it out of is and and or, and so how do we build it? We do the dumbest thing possible.

We form a mask saying, okay, when we want to read the third entry, we're going to end every single entry with either one or zero based on whether that's what we want to read, and then we're going to or all of them together. Okay. Just to make sure I understand the basics.

What the MUX is doing is it's just like selecting. Just selecting. Just selecting an input.

Yeah. So, like, invisible to software is like you say I want input number three, that means there's a MUX here. Yep.

And so, like, what is the cost of this MUX? So an n input mux operating on p bits. Well, I'm going to so I have n n rows, that's this eight rows, and I've got, like, each row is p bits wide.

Well, I have to and every single bit. So I get n times p many and gates. Every single input, I have to say, am I gonna like mask it out or not?

And then and then I'm gonna or them all together. And so there's gonna be like n minus one times p many or gates, which is saying, I've got all of these different things, almost all of them are zeros, but I need to sort of collapse them down into into like, from my eight options down into one option.

Speaker 1

every step I need to or, like, one row into into an existing row. Got it. Yeah.

Speaker 2

a sort of like in and of itself, a quite complicated circuit. Yeah. I mean, this is the first step of all of the hidden data movement costs that are in the shop.

Yeah. Yeah. And so, like, the thing like, we're we're just gonna, like, compare, like, I have to pay this cost, and I've got one max here, and then in fact I have two more copies of that for each of the three inputs to my multiply accumulate operation.

And so I have this cost which is like like three times n times p and gates over here compared to this p times q, like, sort of gates in the actual circuit that I that is doing the thing I care about. And if we plug in actual numbers, like this n being eight, like, I get, like, 24 times p gates over just in the data movement compared to if q is four, four times p gates just in the adder multiply adder. And sorry, where is the three coming from?

Three different inputs here. Got it. Okay.

Speaker 1

is many, many times more expensive than the logic unit. In the most recent ClusterMax report, Semi Analysis ranked almost 100 different GPU clouds. Crusoe was one of only five that made the gold tier.

SemiAnalysis found that gold tier providers like Crusoe had a total cost of ownership that was 5% to 15% lower than silver tier ones, even when they had identical GPU pricing. This makes sense because total cost of ownership is downstream of a bunch of different things that don't necessarily show up in the sticker price but that Crusoe has optimized. Things like how well you detect faults and how quickly you replace failed nodes.

For example, Crusoe was one of the first clouds to adopt NVSentinel, NVIDIA's own GPU monitoring and self healing software, for enhanced GPU uptime, utilization, and reliability. This lets Crusoe make use of everything that NVIDIA has learned about why chips fail across all their different fleets and deployments so that Crusoe can catch faults earlier in the process. And once they identify a failure, Crusoe can swap in a healthy node in less than ten minutes.

Because they're not running bare metal, Crusoe doesn't have to spend time installing an operating system or configuring drivers. They can just spin up a new VM on an already running and prequalified host. If you want to learn more about this or the other reasons that Crusoe made Gold tier, go to crusoe.

ai/dwarkesh. It may be helpful to just see what a mux looks like, maybe like a two bit or a four bit mux. Yeah.

Great.

Speaker 2

So we'll take some inputs. We'll we'll have maybe like we'll just do a a two way mux. So we've got two different numbers.

We've got these two inputs, and then we have a so these are the inputs that are being selected between, and then we have a selector. Which says which can either be like, I want this one or it could be, I want the other one. So this is a one hot encoding.

So this is what we all start with. And then the output we want to produce, let's focus on this case. So this is the actual input we got.

We just want to produce this guy as the result. And so very laboriously what we do is we and this bit with all of these, and so that produces, like, and in this bit with this row. And likewise, we and this bit with this row that produces all zeros.

So this was the there's four here. There's four ands here. And then finally, we just OR these two together.

And this gives a one, we OR these two together, this gives a one. We OR these two together, it gives a zero. We all these two together, and gives a one.

And so this is the four ors. So, like, this actually ends up looking a little bit like addition, in fact. Like, we did exactly the set of same same set of ands here.

Sort of we've added all of these things together, but then instead of collapsing it by using these full adder circuits, just get a very simple collapsing with or gates.

Speaker 1

And how but that I guess that doesn't look like n times p.

Speaker 2

So so yeah. So this was this was with n equals two inputs. Ah, great.

In the general case, we will have n, sorry, this is n rows, and then we'll have p bits per row. So that gives us the the n pi n times p many and gates. So this circuit I've described here, almost all of the cost, like, seven eighths of the cost is in the reading and writing the register file, and only a tiny fraction of the cost is in the LogicUnit itself.

So this is the problem to solve. Essentially was the state of play prior to the Volta generation of NVIDIA GPUs. This kind of thing is what was inside the CUDA cores, and and this sort of problem statement is what motivated introduction of tensor cores, which are more generically called systolic arrays.

So if we think about how we're gonna solve this problem, we're spending almost all of our circuit area on something that we just really don't care about and is hidden to the software programmer, and the thing that we actually care about is not much of the area. Well, make this one bigger somehow while keeping this at the same size. That's the goal.

So the evolution was we had baked this much into hardware in this stage. This single line is a multiply accumulate, this single thing was baked into hardware. The idea of a systolic array is to sort of go two levels of loop up and bake this entire loop out here into hardware.

And so the idea being that if we have a much bigger granularity fixed function piece of logic, maybe the taxes we pay on the input and output are much smaller.

Speaker 1

up one step in the matrix multiply loop that there's some you can tilt the balance more towards compute than communication.

Speaker 2

That's right. So there's two effects that we're gonna take advantage of here. One is just that we can do more stuff before per every trip through our register file.

Mhmm. And then the other thing we're gonna take advantage of is, in fact, in some of this loop we can take advantage of, for example, some certain things staying fixed. Let's sort of Visually, we're going to look at this matrix multiplication.

So, portion of the loop corresponds to a matrix vector multiplication, in fact. So, we'll take a matrix and multiply it by a vector. So how do we do this?

We take every column gets multiplied by the vector and then sum. So we're going to sum sort of along columns. So this zero and three gets multiplied by the three and seven and gets summed, And then the one and two gets multiplied by the three and seven and gets summed.

So there is a multiplier accumulate associated with every single one of these entries in the matrix. So we'll just draw out these four multiplier accumulates.

Speaker 1

And just to make sure I understand why there's four multiplayer accumulates, so if each entry in the column that corresponds to the output vector is a dot product and in this case it'll be like two multiplications and then the addition of those two multiplications.

Speaker 2

Yeah. So the addition so really there's only one addition per dot product but like But we'd to start with initialization of zero. Yeah.

Yeah. So what we're gonna aim for is to have we want to have quadratically more compute. We do.

We have. We have got sort of x times y as much compute as as we had before. But we're gonna want to somehow aim for having only x times as much, like, communication.

And this is sort of the intention so that we get this advantage term going as y. So we've laid down the multiplications. We're going to want to bring in a vector of size two, so that sort of already is in line with our comms target.

That's fine. However, we need to somehow manage the communication of this matrix, which which which does which exceeds our budget of of x. And so the idea is that in an AI context, this matrix is actually going to stay fixed for a long period of time.

And so instead of bringing it in from the outside, so we've got some register file sitting over here, We don't want to have the amount of stuff coming out of this register file. This is the term that we want to go sort of as x in some sense. We don't want to bring this full matrix in from the register file every cycle because we don't have enough.

That would cost too much in terms of wiring from the register file. And so instead we're gonna store our key trick is that this matrix can be stored locally to the systolic array. And so we'll store these numbers zero, one, two, and three just like a gate called a register that like physically stores these numbers and we're gonna reuse these numbers over and over again for a for a large number of different different vectors.

Speaker 1

is you can store this like square quadratic thing directly where the logic is happening Mhmm. And which is like higher dimension than the or has an extra dimension compared to the inputs which you keep swapping in and out. That's right.

I mean, is the nature of what a matrix multiplication is, is that you do, a lot of multiplication to get one value out. Like a dot product is the result of a lot of multiplications.

Speaker 2

in before you get some value out of it. That's right. That's right.

So just to complete the picture here of concretely how that looks, I swapped the three and the two here. Three and two. So just like this zero and three is going to multiply by the three and the seven, and so we're going to form a dot product sort of along columns here.

So somehow we're going to feed a three and a seven in here. These participate in sort of this feeds into this multiplication and also feeds into this multiplication. Likewise the three feeds into here and also into here.

And then we're gonna sum sort of along here with like starting at the top of a column we feed in zeros and then coming out the bottom we get results coming out. So sort of just to visually see what we've got, there's a dot product that is performed along columns in a matrix and that sort of maps exactly to what is done spatially in the systolic array here. So this is one dot product summed vertically and this is a second dot product also summed vertically.

And then what is the data that needs to go into and out of the register file? We have x amount of data that's coming out here on the output, and we also have sort of this data coming from the input, x amount of data from the input. And so with respect to the input and output vectors at least, we've sort of met our goal of having only x as much data going in and out of the register file.

This leaves open the question of, like, I said that the weight matrix is stored locally in the systolic array, how did it get there in the first place? It's sort of like at some point you need to boot your chip and populate this data, and so where did that come from? The trick is just we just do it very slowly.

So we we very slowly trickle feed it in into the systolic array. The sort of the simplest strategy is that we we sort of run this daisy chain that says like feed a number into here, and then and then on the next clock cycle, it'll move down to the next entry with the systolic array. And so we can do that in every in every column in parallel, and that gives us sort of this is also gonna come from here, and this is gonna be another factor of approximately x units of bandwidth coming in.

Can you just would you mind repeating that sentence one more time? So we're sort of like, we know that we're going to be bringing in numbers only rarely into the matrix. And so we just want to come up with any construction at all such that the amount of wiring that actually feeds into sort of crosses this boundary of this systolic array, like this boundary right here, just we want to keep that bounded to x and not go And as x so a particularly simple strategy is that we sort of bring in a number into the top row of the systolic array.

That's what we can do in one clock cycle. And then for y consecutive clock cycles, we're gonna be bringing in the top row every time and then sort of shift all of the other rows down by one. And that keeps the wiring that needs to come from this expensive register file only down to a factor of x rather than x one.

I see. Okay.

Speaker 1

there's two questions in terms of communication. There's like communication time and then there's communication bandwidth. Yes.

And you're saying since we're only gonna be loading this in once, let's maximize let's minimize bandwidth. That's right. Because minimum bandwidth equals die area.

Mhmm. And let's just, like, load it in slowly over, like, smaller lanes because we're just gonna keep this value in there for a while. Exactly.

Interesting. So it's interesting to me that when we were talking last time about inference across many chips, the big high level thing we're trying to optimize for is increase the amount of compute per memory bandwidth, that is to say per communication. And here also we're trying to increase the amount of like actual multiplies or actual additions relative to transporting information from registers to the logic.

So in both cases, you're trying to maximize compute relative to communication.

Speaker 2

Yeah. This this shows up sort of all the way up and down the stack. This is sort of close to the bottom, sort of like to to the gates.

There's sort of a a version that's maybe even closer to the gates of just like even the precision of number format that you choose to use. We saw that same effect. There's like a square cube law or a like squared versus linear term going on both in just purely the precision of this ALU, but then also in terms of the size of the matrix.

Yeah.

Speaker 1

Very interesting.

Speaker 2

So this unit is sort of the next bigger unit we had, like the multiplication circuit, and then on top of that, we have a, like, a pretty large systolic array. I drew it as two by two, but in, like, for example, older TPUs, they were described as a 128 by a 128 of of this circuit shown here. And this circuit ends up being this is the the most efficient known mechanism for circuit for implementing a matrix multiply.

I see.

Speaker 1

sort of it seems obvious that you should try to maximize compute relative to communication. What are non obvious trade offs that actually you are you you know, keep you up at night about what should we do x or should we do y? And it's not obvious what the answer is.

Yeah.

Speaker 2

sizing decisions. And so already in what we've drawn so far, so AI chips all have this circuit in it. They have a systolic array, and then somewhere near it, a register file providing inputs and outputs.

The two sort of even within this scope sizing questions that you have are how big should I make my systolic array, and how big should I make the register file? And then the trade off for the size of the systolic array, actually, these two questions are coupled, is one way to think of it is to say, I'm gonna, like, have a budget for how much what percentage of my chip area I want to spend on data movement. So maybe I just say that I want this to be 10% and the systolic array to be 90%.

And then sort of I can size my register file. Bigger register files are more flexible. They allow me to run sort of more I can get more application level performance out.

Speaker 1

But then they sort of take away from this area spent on the system. Right? Yeah.

Makes sense. I recently ran an essay contest where I asked people to write about what I consider to be some of the biggest open questions about AI. The submission window closed last week, so I used Cursor to create a couple of different interfaces to help me review the entries.

One interface anonymizes submissions and hides unnecessary information. It lets me group responses by question, add notes, and record my scores. The other interface helps me review entrants who want be considered the researcher role that I'm hiring for.

The UI puts the applicant's essay right next to their resume and their personal website so that I can see everything at once. Cursor's Hardness is really good at helping these models see and improve their UIs. I watched it render these interfaces in the built in browser, take screenshots, click through sections, and keep iterating.

At this point, Cursor is where I do most of my work. Whether I'm reading and visualizing a bunch of research papers or coding up an interface to review applications or making flashcards for my Blackboard lectures, Cursor just makes it very easy for an AI to look at whatever I'm looking at and help me understand it and work with me on it. So whatever you're working on, you should do it in Cursor.

Go to cursor.com/dwarkesh. Where does the clock cycle of a chip come in?

What determines what that is?

Speaker 2

Yeah. And what is the clock cycle of a chip? So I guess at baseline it's sort of worth observing that chips are incredibly, incredibly parallel.

Right? You've got 100,000,000,000 transistors in a A key thing that you need to do whenever you have massive parallelism is you need to synchronize between the different parallel units. In software, typically, have these very expensive synchronization methods like a mutex.

So one thread will finish what it's doing. It will ink, like it will grab a lock somewhere stored in memory and then notify the other thread that it's done. On chips, take a very different approach and say that every nanosecond or so, all circuitry in the chip will kind of pause for a moment and then synchronize every so it actually synchronizes every single nanosecond or so.

And so that is the clock cycle. The entire chip, typically all in sort of one fell swoop, goes in lockstep to the next operation that happens. And so what this looks like in circuitry is that you will have it's typically drawn so the clock is sort of mediated by registers, which are these storage devices that we've drawn elsewhere.

And the way to think of it is that I have I have some storage which is storing like a bit, which might be zero or one. And then I have some sort of cloud of logic which maybe is like this systolic array or this multiplier or something like that. And then I've got some and that's gonna produce some output.

So my inputs, I've got a bunch of inputs feeding to this cloud of logic. And then eventually later there's gonna be some output register that this writes to. There is a global clock signal which drives all of these registers, and it says, at a certain instance in time when the clock strikes, whatever value happens to be on this wire at that instant, that's what's going to get stored in so the challenge here is I would like to have my clock speed run as fast as possible because if I can run at two GHz I can get twice as many operations done per second than if I run at one GHz.

But what that ends up meaning is that I'm very sensitive to the delay through this cloud of logic, because any computation that is gonna happen in here needs to sort of finish before the next clock cycle hits. Right.

Speaker 1

as short as possible. Interesting. And is there ever because the constraint here seems to be that if you add too much logic, then you might risk missing the clock cycle.

But if you don't add enough, then you're, you know, leaving potential compute on the table.

Speaker 2

or is it just like, no. Either it's gonna finish by clock cycle or not? Yeah.

In standard chip design, you you margin it such that I mean, is a probability, but it's like many, many standard deviations, like way standard deviations out such that for all intents and purposes, is a reliable part. It it will always meet the clock. There are some weird exceptions to that.

There are clock domain crossings where you go from one clock to the other clock, and then you actually do have to reason about this Interesting. The main path, you just like you margin it such that you'll get there like 25% of the clock cycle in advance.

Speaker 1

the clock, where the clock synchronize, I guess, where the registers are. This is not something you determined as a chip designer. This is sort of just like an artifact of, hey, I want whatever sequence of logic.

Speaker 2

that is like too long such that it makes the whole clock cycle of the entire chip longer than it has to be. Yeah. So this is actually a huge part of the work of designing a chip actually is inserting them.

So it is done in a combination of manually and automatically. So just to show the very sort of dumb version of what you can do here, you can take this logic and split it in half. And so say, actually instead of just one cloud of logic, I'm gonna have two smaller clouds of logic, which do the same thing, but split them up by a register.

Right. Feeding in like this. And this is, like like if you split it, like, in the middle, you can hit twice the clock frequency.

That's great. You get twice the performance at the cost of this extra register, and so at the cost of some more storage.

Speaker 1

And so stepping back, why do we need to synchronize the whole chip? Like, if you have like, if you imagine playing Factorio or something, there's no, like, global clock cycle. It's shit is done when it's done.

There's iron on the plate. You can take it if you want.

Speaker 2

Yeah. So taking that analogy, the the the the thing that you need to be mindful of is if I've got two different paths through some logic. So I have to do a computation like f here, and then computation g here, and then they're gonna come and meet for computation h somewhere here.

And so there's gonna be manufacturing variance here. In some chips, F will take a little longer, maybe in some chips G will take a little bit longer. And so if I've got some signal that's propagating through here, and the result from f and g have to sort of meet up at h, what can the the thing that can go wrong is that f can get there early and it meets like the previous value of g or the next value of g or something like that.

And h needs to know when to start. Exactly. Yes.

Speaker 1

and so this explains why different chips made at the same process node, the same like TSMC technology can have different clock cycles.

Speaker 2

it it slows down the whole ship's clock cycle. That's right. This optimization that I that I showed here, this is just the this is sort of pipeline register insertion, it's called.

Yeah. We've inserted in the middle of the pipeline register here. This is a sort of pure trade off between clock speed and area.

This is the easy case. There is a harder case too, which is sort of drawn it as a pipeline of logic here, but in other cases you may have some calculation which actually feeds back in on itself. So it runs some function f and then writes back to itself like this.

So, for example, this might be this addition, like you've got some number that you're adding into every clock cycle, and so this could be like a plus where adding in some number every clock cycle. So this little circuit, essentially, it's just gonna sum all of the numbers that are presented on on different clock cycles. And the challenge is if this plus takes too long, what can I do if I, like, split it in if I try and put a pipeline register, like, right in the middle of it, like like here in the middle of it, this will end up changing the computation that's done?

Instead of forming a running sum of everything that comes here, I will actually have two different running sums. I'll end up having a running sum of the even numbers and a running sum of the odd numbers.

Speaker 1

this is actually the thing that is the hardest thing to address and sets the clock cycle. I don't understand why it'd be a problem to have that. Or I'm not sure even what it would mean to have a register there.

Like, is sort of atomic operation, right? Well, so Plus is not really atomic.

Speaker 2

As you just demonstrated. Yeah. It took a whole lot of work to do a summation.

So, can take the early parts of that work and then stick a register in middle and then take the late parts of that work. Got it. Okay.

Yeah.

Speaker 1

PDK which says that I say, here's the primitives of logic that we can grant you in the in the chip and it's up to them to determine that no no primitive is bigger than, like, the clock cycle they're hoping a process node targets. But other than that, is there, like, what further optimize can't you just say, like, hey. Here's all the primitives from TSMC, and keep adding registers in between the primitives as much as is needed until you get to your desired clock cycle?

Yeah.

Speaker 2

the chip architect set the clock cycle. So just for for one example, the primitives you get from TSMC are on the order of like AND gates or full adders. They depends a lot on voltage and frequent and which library you choose and so on.

But generally, you can typically have about like 10 or 20 or 30 of these in a clock cycle sequentially. So these parameters are very, very fast, like ten picoseconds or something like that. And so as a logic designer, in principle if you literally just had register and then AND gate in a loop like that, you could get an insanely fast clock speed, like more than four or five, six gigahertz, something like that.

But if you take this really simple circuit and you look at the area you're spending here, this is called one gate equivalent in size, so unit of one in area, and this thing is unit of eight in area or something like that. And so this is just, again, almost all of your cost has been this synchronization or communication cost compared to the actual logic. And so this would be a case where you've gone too far.

You've made your clock speed really, really fast at the cost of spending almost all of your area on pipeline registers. Interesting.

Speaker 1

So what you're hinting at is a dynamic where you can have really fast clock speed but you're not getting that much work done. Yeah.

Speaker 2

or throughput rather. Yeah. The it hurts your throughput in fact because like like the the throughput of your chip you can think of as the product of how much I can get done per clock cycle, which is based on this area efficiency thing times how many clocks I get per second.

Speaker 1

where if you have a low batch size, then you can any one user can receive their next token really fast, but the total number of tokens that are processed in, say, an hour will be kind of lower than it could otherwise be. Yeah. Exactly.

You get you get less parallelism out if you if you drive your clock speed up clearly. Language models are starting to compete against the best human forecasters. I sat down with two senior Jane Streeters, Ron Minsky and Dan Pontecorvo, and asked, at some point, does AI just do what Jane Street does?

There's a world that we should take seriously, where know, we're gonna build large language models or some other AI systems that are, like, strictly smarter than all humans on the planet and more capable at all cognitive tasks. Trading in particular feels to me as, like, kind of AGI complete, sort of like NP complete, because at the end of the day, trading involves figuring out what things are worth, which means making predictions about the future. Jane Street isn't betting against AI.

They just signed a $6,000,000 compute deal. But Ron's view is that the edge keeps moving. I have never been more desperate to hire more engineers and more traders than I am today.

You you have the usual thing of, like, the other hard parts that we don't yet know how to automate. Well, that ends up being where the competitive edge lies. You can find these open positions and watch the full interview at janestreet.

com/dorkech. Okay. So I remember talking to an FPGA engineer at Chain Street, Clark, who actually helped me prep for your the the previous interview we did together.

And he was explaining why they use FPGAs. And I I imagine that for high frequency trading, the throughput is less important than latency. And so having very specific control over the clock cycle in a deterministic way is the most important thing.

I, maybe it'd be interesting to talk about how you why you can't just achieve that with an ASIC or why FPGA is the yeah.

Speaker 2

have deterministic clock cycles for like high high frequency trading? Yeah. So I mean, firstly, like, let's consider the sort of the business case for an FPGA versus an ASIC.

FPGAs and ASICs use largely the same conceptual model, which is that I have a series of gates built from ANDs, ORs, six ORs, those very small primitives, connected together with a fixed clock cycle, and connected together with wires that are running in a fixed clock cycle. So anything you can express in an FPGA, you can express in an ASIC too, and it'll be about an order of magnitude cheaper and better energy efficiency on an ASIC than an FPGA. The trade off is that the first FPGA costs you $10,000 whereas the first ASIC you make costs you $30,000,000 because it requires an entire tape out.

So the business use case for an FPGA would be that I want something that has this very deterministic latency fast runtime and high parallelism, but, you know, I I'm gonna change it very frequently. Can change what I do every month or something like that, and so then I don't wanna pay the tape tape out cost every time. Now how does an FPGA actually implement it sort of like it emulates the ASIC programming model, but in fixed piece of hardware.

And so how does that work actually? So what it has at the base is it's got the two components we just talked about. It's got these registers as storage devices, and then it's got these, these are called LUTs, lookup tables, which actually provide all of the gates.

And then we're gonna see even the sort of the third component. We then have sort of a swarm of these registers and lots. And all of these are available and then they are connected by sort of this big set of sort of MUXes.

So in front of every single one of these, we've got something like one of these MUXes, which selects one input from everywhere else, sort of selecting from all of these different things. We've got a whole bunch of different options feeding into all of these things. So so what what what this allows is essentially a when I program my FPGA, I can say that I'm gonna take all of these components and I'm gonna sort of superimpose on top of this a particular wiring which, like, goes through this lot and then feeds into this lot and then goes to this register and then feeds into this lot or something like that.

So what I've drawn in orange is you FPGA means Field Programmable Gate Array. The orange is what has been programmed in the field, whereas the white is all of the wires that must exist in the FPGA in order to make the device in the first place. What does it mean to be programmed into a field?

Like programmed in the field. So like the device is being deployed in a data center, it's sitting in the field and then you can come and program. Not field as an electric field.

No. Field as in like out there in the world field. Okay.

Speaker 1

so if I see look at the how the the field programming comes out of the first lookup table and goes in a second one.

Speaker 2

how yeah. How? Like like, where where are the wires that made that happen?

Guess this yeah. So I I I got a little bit, like, lazy in drawing all of these. Every single device here has a MUX sitting in front of it, which can select from all of the, like, nearby, circuits that are available.

And so the actual configuration of the FPGA is like amounts to it, it is the MUX control. So in this MUX here we have the data inputs, and then we have the control that selects. And so there's a little storage device sitting next to every single one of these MUXes saying this is where you're gonna source your input from.

Got it. And so programming it consists of configuring every single one of these Muxes. So that makes sense.

So what is happening inside of the lookup table? Yeah. So the purpose of the lookup table so it's gonna also have a little bit of control feeding, telling it what to do as well.

The purpose of the lookup table is to function to be able to configurably take the role of an AND gate, OR gate, XOR, any of those different things. So there's many ways you could consider doing that. The way it is done in sort of traditional FPGAs is to say it will support will be a lookup table will be it will have four bits of input, one bit of output.

How many different functions are there from four bits to one bit? There are 16 different functions. And so you can actually just tabulate this as 16 different numbers.

You've got a table of zero one one one zero zero one, 16 entries. And so what it does is this table is stored in this blue configuration bit, and then it views these four bits as binary, looks up the relevant row of the table, and emits that bit.

Speaker 1

So this is a truth table view of lookup tables essentially. Okay.

Speaker 2

take as input. Those are, like, two input functions. Yeah.

So sometimes we have, like, more complicated like, a three input function would be a three way XOR Right. Or a four way XOR. And in this case, how many it just depends how how big it is.

Typical size for LUTs is four input, which is sort of just a sweet spot between there's another computer communication trade off like here. Like, if it if it has too few inputs, then you need to use more LUTs. Yeah.

If it if it has too many. But basically, the lookup table is like a truth table. It's a truth table.

Yeah. And with a truth table, can program in any gate you want. That's right.

Yeah. And so it's a lookup table that just thinks like a programmable gate. That's right.

And so, I mean, one of the things you can do here is you can see why where the rule of thumb that an FPGA is like an order of magnitude more expensive than an ASIC comes from, is to count how many gates would be inside this lookup table. Yeah. So we can view this lookup table essentially as one of these MUXes.

And so it is a MUX with, has to select between 16 different values. And so it is a MUX with sort of n equals 16 options, p equals one bits. And so what we saw way earlier is that this circuit costs like n times p many gates.

And so it costs like n times p equals 16 and gates and also 16 oars.

Speaker 1

This circuit being the mux?

Speaker 2

Yeah. Exactly. The mux.

The mux is the core of The mux that goes into the lookup table. So the lookup table itself, can think of as being actually a big mux that selects from all 16 rows down to one output. Yeah.

Okay. See. That is the lookup table.

But the way you've drawn it here, there's a MUX and then a lookup table. It's it's MUXes all the way down. So, I mean, there's a there is a second MUX that is inside here.

This MUX is is this MUX. Got it. Okay.

Speaker 1

Where it came from in this sort of mess of of of gains. Right. And then the second mux is, okay.

Speaker 2

still a four bit value. Yeah. So I've selected four bits from the soup.

Right. And then and then I use those four bits to select which entry in the lookup table Yeah. I am gonna use.

Right. Okay.

Speaker 1

eight you're you're pulling from eight nearby registers as input. Mhmm. And so that's like a total of like 32 bits going in.

Mhmm. And then out of that, four bits come out.

Speaker 2

Those four bits go into the second mux, which is inside the lookup table. So actually, would say in yeah. In this case, these registers are single bit registers.

So if there are eight, like, eight nearby registers and lookup tables, then I have eight bits total coming in nearby. I select from eight down to four different values, so there's actually like four different MUXes, one associated with each of these input, like little marks associated with each of these input bits. Each of them is selecting one out of eight.

And where are those eight coming from?

Speaker 1

Nearby registers and other lots. And each register is one bit? Yes.

Yeah. And so I guess you AMD or whoever makes these FPGAs still has to be opinionated about what registers are connected with registers. And then you can program in the actual gates, they had a wire and the connection, like the communication topology.

Speaker 2

Right? Yeah. So there's there's sort of like you get flexibility in a local grain thing.

There's a sort of nearby neighborhood where you can select from, but then more grossly, like more coarsely, longer distant connections, they they form an opinion on that. Right. Yeah.

And the reason it's 10 x slower is why? So if you look at the cost of, like, building this lookup table, it's, like, 32 gates. Yep.

And then it can give me the equivalent of, like, what's one an interesting thing I can do here? I can do a four way AND gate. And so that's like, I am using 32 gates of lookup table to sort of implement, like, a four way AND means, like, what is a four way AND?

I would do, like, AND, AND, and then AND of AND. So to implement like, this is a a socket that I could implement in an ASIC directly using these three and gates. But using a lot, I can also implement it, but it's gonna take, like, these 32 gates instead of three.

Speaker 1

so the overhead is really coming from the, like, the fact that the lookup table the mux in the lookup table is there's a more concise way to describe a truth table than listing out every single possible combination of inputs,

Speaker 2

which is just to, like, write out the gate. Yeah. Like, to to, like, place down the polysilicon and the and the wires and so on.

Yeah. Yeah. Interesting.

Speaker 1

One important point he made to me is that the reason they prefer FPGAs to CPUs is because they get deterministic clock cycles. They know when a packet will come in and go out. Why is it not a guarantee in CPUs?

Speaker 2

So you can actually design a CPU that has deterministic latency as well. And in fact, like, the the processors that are inside a lot of AI chips actually also have deterministic latency too. Grok has advertised this.

TPUs have that in the core as well. The challenge is getting sort of deterministic latency and high speed at the same time. And so where does the nondeterminism in latency come from?

Nondeterministic latency comes from specific design choices in a CPU. It's actually possible to remove those design choices and make a CPU that has deterministic latency. Those are not very attractive in the market, and so people don't make those CPUs anymore.

But actually, in some sense, deterministic latency is maybe a sort of a simpler designing starting point, and then and then, like, some chip designers have added things in to to be nondeterministic. To take a concrete example of that, probably the most important example is on a CPU just like the CPU cache itself. So in a CPU, have the the CPU this is this is the CPU die itself, and then there's a memory off on the side.

This is the DDR memory off on the side. And then you have a cache system here. Inside it is the cache.

That sort of remembers recent accesses to DDR and stores them. And so I'm running through my CPU instructions, every time I have an instruction that accesses memory, it first checks in cache, was was the data stored in cache, and then if not, it goes it fetches out to DDR. Yep.

This is a huge optimization. The cache is like two orders of magnitude faster than DDR. If you never if you never use the cache, basically all programs would run a 100 times slower.

So the presence of a cache is absolutely necessary for a CPU to to run at reasonable speed, but whether or not you get a cache hit is dependent on the ambient environment of the CPU, like what other programs are running, what has run recently, what is the random number generator inside the cache system doing. And so that is a big source of nondeterminism the runtime of a CPU. So this is sort of the memory system for a CPU.

The big thing that you can do differently is instead of having the hardware say, I'm gonna read memory and then decide the hardware decides whether or not it comes from cache or not, you can actually bake this decision into software. So a different design philosophy is to, and you see this in maybe for example TPUs. The the TPU instead has I mean, I'll draw the same diagram, but I'll call it a scratch pad.

And so the the main difference is so this would be like a TPU and then like HBM, in this case, rather than DDR, but it's still an off chip memory. And instead of the software saying first access memory and then the hardware decides, you've got some instructions that go here. This is like one kind of instruction, And then a totally different kind of instruction that goes to HBM.

And so this style is generically known as Scratchpad instead of cache. The key distinction being that you have one kind of instruction that says read or write Scratchpad and a totally different instruction that says read or write HBM. So is is Scratchpad being the cache?

Yeah. This this thing here is the is the Scratchpad.

Speaker 1

Just to be clear. So stepping way back, people say computers have the, quote, unquote, John Von Neumann architecture where there's this serial processing of information. And maybe just because we've been talking about parallel accelerators, but I just don't like, the FPGA is super parallel.

Yeah. Yeah. The the kinds of AI.

Saw that TPUs are super parallel. Even CPUs are super parallel if you think about all the cores they have. And so is it actually like, in what sense is modern hardware actually the Von Neumann architecture?

Is it actually a fair way to describe modern hardware?

Speaker 2

I think it's a fair way to describe CPUs. Like, just the amount of parallelism. Like, on a CPU, the amount of parallelism you get is about a 100 cores times maybe, like, 16 way vector unit.

Speaker 1

about a thousand way parallelism on a CPU. Yeah. Is it one question is, what is the there is a die that is being used for the CPU.

Mhmm. And if there's fewer threads, just as a matter of, like, transistor voltages are, like, switching on and off, Is it just that there's like literally one control flow, like a small part of the die where like voltages are switching on and off?

Speaker 2

die area of a CPU if there's as opposed to If there's so few cores, am I spending all the there. Yeah. The cores are just much bigger and more complicated.

So, I so I guess we should compare a CPU core which takes up one hundredth of a die I mean, to a LUT. Like, a LUT is just only these 16 gates. Right.

So, like, it's clear why there are so many more LUTs in an FPGA than cores in a CPU. But then sort of maybe the the like, why are there more CUDA cores, for example, than than than CPU cores? Think would be like, why what's the difference between a CPU and a GPU or something like that would would would be a a big difference.

Inside the CPU, you have so one big use of the sort of the top unit uses of area inside a CPU are the cache. Very little is actually the ALUs, like mostly it's like these register files rather than the logic units. And then both of these things have equivalents in GPU, and so that's not a big difference.

But the thing that does not have an equivalent in a GPU is the sort of this branch predictor. And so there is a whole big area in the CPU which is sort of just a whole bunch of predictors that are saying when will my next branch be and where's the branch target for that. And so stripping a lot of that out as well as sort of making these register files tighter in a sense is driving a lot of where the GPU gains are And what is the purpose of the branch predictor to execute both branches at once, or what does it do?

So the issue is that when I've got a series of instructions like like instructions instructions instructions instructions, I if I have a branch like here, if this instruction is branch, The the actual processing step of processing an instruction takes a really long amount of time. It takes, like, maybe five nanoseconds or something like that. So, like, the time to actually notice that I've got a branch and then, like, evaluate the boolean whether it's true, and then update the program counter to the new target, and then read from the instruction memory for that.

That could take actually five nanoseconds to finish. And so in reality, this may finish somewhere down here. I don't want to but, like, I want to run a clock speed that is much faster than what five nanoseconds allows.

Like, five nanoseconds is 200 megahertz clock speed. I would like to run at one or two gigahertz or something like that. And so I need to run other instructions while the branch is is being evaluated.

And so I, like, I really just wanna keep running the following instructions that happened after me. But that might have been wrong. If the branch ended up being taken, then I need to know that instead of evaluating these instructions, actually need to jump to wherever the target is and run these instructions instead.

And so the purpose of the branch predictor is genuinely to predict based on before you even get to the destruction to be like five cycles earlier to predict there was gonna be a branch that's gonna happen.

Speaker 1

while you can do structured sparsity in these accelerators and then save yourself some area that you would have otherwise had to dedicate to these gates. In the brain, there's unstructured sparsity. Any neuron can connect to any other neuron and not in like ways where they'd have the column aligned or whatever.

Yeah. Then there's a fact that memory and computer are co located.

Speaker 2

is exactly the co location in some sense of the memory. That's right. That's right.

Yeah. Yes. Maybe maybe that actually isn't a big difference.

Speaker 1

And the other maybe a bigger a big difference is that the clock cycle on the brain is much slower than on on computers. And partly, that's to preserve energy because the faster the clock cycle, the bigger the voltage needs to be in order to identify or for the signal to settle and to, like, identify what state of transistor is that. That's right.

That's right. I don't know if you have other high level takes about, like, how any commentary on what, you know, what would the brain might be doing versus how these chips work? Yeah.

I mean, so let's take the clock speed one first actually. Yeah.

Speaker 2

Clock speed is quite high on a chip because that drives higher throughput. When we compare a GPU running some workload, it's running batch size thousand or something like that, whereas the brain is not running batch size thousand. There's only one of me.

And so you could sort of imagine saying, well, take a GPU and instead of running it at gigahertz, run it at megahertz or something like that. And that would start to look maybe a little bit more like sort of equivalent things that you're talking about in the brain. There is, in the way that silicon works, that does not give you an 1000x advantage in energy efficiency.

So what it ends up looking like is you like, you sort can of just end up running this circuit once to stabilization, and then it'll sit idle for a long period of time. It doesn't consume a lot of energy while it's sitting idle because most of the energy is consumed in sort of toggling bits from zero to one and back. So actually, let's let's talk about the energy consumption of of a circuit like this.

The way to think of a bit being stored is you've actually deposited some charge in in a capacitor somewhere, sitting somewhere in in the chip implicitly. So it it becomes charged when it is bit becomes a one, and then it becomes discharged when it next goes to a zero. Yeah.

And that cycle of, like, charging the capacitor and then dumping that charge out to ground, that is where the energy is consumed. This is called the dynamic or switching power. This is most of the energy consumption of a chip.

There is some other energy consumption just coming from the fact that insulators aren't perfect insulators, but we'll just discard Most of the energy consumption actually comes from just the charging and discharging of, like toggling from zero to one and back to zero. Right. So if you run a chip much slower and you only clock it once every thousand clock cycles or something, you will have a thousand times fewer transitions.

It'll be about a thousand times less energy consumption, but but like but not a substantial advantage in energy efficiency.

Speaker 1

Okay. So you described how a TPU works at a high level. What is the difference at a high level between how a GPU and a TPU work?

Speaker 2

Yeah. So I mean I think there's sort of a high level organization principle that is different. And then there's sort of inside the cores what are different.

But we'll look sort of outside the at the high level, so we'll take a GPU and a TPU and what does sort of the top level block structure look like. If you think of this as the whole chip in each case, the organization of the GPU is mostly a bunch of almost identical units, which are these these are the SMs. And then they've got an L2 memory in the middle, and then a bunch more of these SMs on the bottom.

And so there's sort of this fairly regular grid of cores. And then, like, if we look at a at a TPU in in comparison, you you end up with much coarser grained units of logic. And so you you end up with something like some large number of maybe like maybe just a few matrix units.

These are the these are the big, like, systolic arrays. And then in the middle, you've got some vector unit. And then you've got your matrix units at the bottom.

So now, sort of like matrix units with a vector unit in the middle, sort of this is the whole TPU chip. You can sort of think of scaling this thing down into a really tiny unit with a smaller matrix unit, smaller vector unit, and that is sort of what an SM is. So sort of at a very high level point of view, the GPU has a lot of tiny tiny TPUs sort of tiled across the whole Oh, interesting.

Speaker 1

So, like, you're suggesting the tensor core within a streaming SM is analogous to an MXU? Yeah. It's very very similar.

Yeah. I see. And so if you had more like more lack of structure, having a bunch of tiny TPUs makes a lot of sense.

Speaker 2

registers and work schedulers and things like that? Why don't we just like make a huge thing and like amortize those costs across the whole thing? And, I mean, I think this shows up in how large you can grow things.

We've we've sort of seen this theme, like, especially with the systolic array where largest systolic array amortizes the register file costs better. Yeah. This sort of design allows you to have larger systolic arrays.

This whereas the sort of GPU design constrains you to having small units of everything. There is a trade off, however. There ends up being, because of this sort of coarse grained separation of things there, you need to move a lot of data from the vector unit to the matrix units.

And so, like, you need to move a lot of data through a sort of, like, lines of parameter here. Whereas if you sort of look at the equivalent thing here, you've got vector units everywhere, and you need to move data through this line, through this line, through this line, through this line, through line, through this line.

Speaker 1

wiring instead in a GPU. Right. But also, might have to move across less area.

Speaker 2

Which, I mean, is also a saving. Like, it's an energy setting. So so data ends up moving like, if you can operate entirely within s an SM Yeah.

The data movement is much smaller. But then the moment you want to operate across SMs That's like, it it becomes sort of more more complicated and expensive.

Speaker 1

is to get the GPU like smaller structure of systolic arrays surrounded by SRAM, but also at the same time make it so that like the things you need in an SM to support the CUDA architecture but take a bunch space, you might discard.

Speaker 2

Yeah. We've talked publicly about something which we call a suspendable systolic array, which in some sense you can think of as big systolic arrays that can be small systolic arrays as well. Cool.

Speaker 1

Okay. I think it's a good note to close on. Rainer, thank you so much.

Thanks, Rakesh.

Shared via Hopper