News for hackers. Stuff that matters.
Re:Implementing a GPU's Programming Model on a CPU by adrian_b on Saturday October 14, 2023 @09:07AM (#37880183)
This so-called GPU programming model has existed many decades before the appearance of the first GPUs, but at that time the compilers were not so good like the CUDA compilers, so the burden for a programmer was greater.

As another poster has already mentioned, there exists a compiler for CPUs which has been inspired by CUDA and which has been available for many years: ISPC (Implicit SPMD Program Compiler), at https://github.com/ispc/ispc .

NVIDIA has the very annoying habit of using a lot of terms that are different from those that have been previously used in computer science for decades. The worst is that NVIDIA has not invented new words, but they have frequently reused words that have been widely used with other meanings.

SIMT (Single-Instruction Multiple Thread) is not the worst term coined by NVIDIA, but there was no need for yet another acronym. For instance they could have used SPMD (Single Program, Multiple Data Stream), which dates from 1988, two decades before CUDA.

Moreover, SIMT is the same thing that was called "array of processes" by C.A.R. Hoare in August 1978 (in "Communicating Sequential Processes"), or "replicated parallel" by Occam in 1985 or "PARALLEL DO" by "OpenMP Fortran" in 1997-10 or "parallel for" by "OpenMP C and C++" in 1998-10.

Each so-called CUDA kernel is just the body of a "parallel for" (which is multi-dimensional, like in Fortran).

The only (but extremely important) innovation brought by CUDA is that the compiler is smart enough so that the programmer does not need to know the structure of the processor, i.e. how many cores it has and how many SIMD lanes each core has. The CUDA compiler distributes automatically the work over the available SIMD lanes and available cores and in most cases the programmer does not care whether two executions of the function that must be executed for each data item are done on two different cores or on two different SIMD lanes of the same core.

This distribution of the work over SIMD lanes and over cores is simple when the SIMD operations are maskable, like in GPUs or in AVX-512 a.k.a. AVX10 or in ARM SVE. When masking is not available, like in AVX2 or Armv8-A, the implementation of conditional statements and expressions is more complicated.

Re:Implementing a GPU's Programming Model on a CPU by kllrnohj on Saturday October 14, 2023 @09:41AM (#37880413)
DirectX 8 added programmable shaders as we mostly know it today in 2000 with directx 9's shader model 2.0 really solidifying things in 2002.

CUDA didn't show up until 2007.

Re:Implementing a GPU's Programming Model on a CPU by pjmlp on Sunday October 15, 2023 @03:51AM (#37887816)
Except that shaders predate DirectX 8 by several decades.

Two major examples,

https://en.m.wikipedia.org/wiki/TMS34010

https://en.m.wikipedia.org/wiki/RenderMan_Shading_Language

Also in DirectX 8, it wasn't as we know them today, because Assembly was the only programming language.

Nowadays CUDA does C, C++, Fortran, Python JIT in the box, and has partner collaborations for Haskell, Java, Julia, C#.

Re:Implementing a GPU's Programming Model on a CPU by mattpharr on Saturday October 14, 2023 @10:02AM (#37880546)
Also related as far as the programming model: C* on Connection Machines and the C dialect used on MasPar systems in the 1980s.

There is some discussion in the ispc paper: https://pharr.org/matt/assets/ispc.pdf

Re:Implementing a GPU's Programming Model on a CPU by mathisfun123 on Saturday October 14, 2023 @10:26AM (#37880695)
It's funny that you have this whole rant about the superfluousness of SIMT, how it's the same thing as SPMD and then you casually drop

> When masking is not available, like in AVX2 or Armv8-A, the implementation of conditional statements and expressions is more complicated.

which is exactly the difference between SPMD and SIMT, i.e why the new initialism was necessary: predicated execution. From Professional CUDA C Programming:

> A key difference is that SIMD requires that all vector elements in a vector execute together in a unifed synchronous group, whereas SIMT allows multiple threads in the same warp to execute independently. Even though all threads in a warp start together at the same program address, it is possible for individual threads to have different behavior.

This is implementated using predicated execution and instruction replay.

Re:Implementing a GPU's Programming Model on a CPU by tovej on Saturday October 14, 2023 @11:45AM (#37881388)
Are you even reading the text you cite? That compares SIMD to SIMT. SIMD, not SPMD. SIMD is a more restrictive hardware paradigm, SPMD is just a mutiple copies of a single program running on multiple processes/threads, i.e., exactly what CUDA does.

Most MPI-programs are SPMD, and really, the only conceptual difference between MPI and CUDA is that a thread's id is a point in a grid space that's relevant for scheduling and memory locality. Oh wait, that's true for MPI as well, only the scheduling and memory locality relates to CPU cores and nodes, instead of CUDAs SMPs and blocks.

The only real justification for a different programming model is that SIMT creates opportunities for implicit SIMD on a thread scheduling level if you've written your program in a way that the warps don't diverge.

Re:Implementing a GPU's Programming Model on a CPU by mathisfun123 on Saturday October 14, 2023 @11:57AM (#37881514)
> Are you even reading the text you cite?

Yes I have read it enough times that I knew exactly where it was in the book.

> That compares SIMD to SIMT.

Yes and so does the op I responded to.

> SIMD, not SPMD. SIMD is a more restrictive hardware paradigm,

Thanks but I was already aware. The op was the one that conflated SPMD and SIMD, not me.

> SPMD is just a mutiple copies of a single program running on multiple processes/threads, i.e., exactly what CUDA does.

CUDA is a C language extension that enables you to write host and device code in the same source. That's it. SIMT is the model of compute on NVIDIA SMs.

> The only real justification for a different programming model is that SIMT creates opportunities for implicit SIMD on a thread scheduling level if you've written your program in a way that the warps don't diverge.

No that's incorrect. SIMT is implemented using predicated execution and instruction replay exactly so that warps can diverge.

Again, it's amazing you guys are so sure that NVIDIA pulled a fast one on just the whole community/industry and didn't actually innovate but it turns out you're actually missing some pieces of the puzzle.

Re:Implementing a GPU's Programming Model on a CPU by tovej on Saturday October 14, 2023 @12:21PM (#37881758)
and again, did you even read my reply? You're disagreeing by stating my point back to me. The point about divergence is that IF the threads DONT diverge, you get SIMD scheduling, the GPU can schedule the equivalent of a SIMD OP across the warp.

Obviously they can diverge, because this is SPMD/SIMT

Re:Implementing a GPU's Programming Model on a CPU by tovej on Saturday October 14, 2023 @12:18PM (#37881726)
OP did not conflate them, SPMD and SIMT are the same model, they're just used in different contexts.
Re:Implementing a GPU's Programming Model on a CPU by mathisfun123 on Saturday October 14, 2023 @12:29PM (#37881834)
well i guess it's just your word against ... basically any other resource on the matter (in addition to just a common sense understanding) :shrug:
Re:Implementing a GPU's Programming Model on a CPU by tovej on Saturday October 14, 2023 @12:47PM (#37882039)
Ok dude, give me an actual argument. Tell me a substantial way that SIMT is different from SPMD
Re:Implementing a GPU's Programming Model on a CPU by raphlinus on Saturday October 14, 2023 @02:36PM (#37883021)
Subgroup operations[1]. In SIMT, they are fairly easily modeled[2] as communication between the different threads running on the same SIMD, and in most cases explicitly expose the predication mask. In fact, subgroupBallot(true) is a common idiom to extract that mask, and also to determine the subgroup size if run in subgroup uniform control flow. Generally they have good performance characteristics.

In SPMD, subgroups aren't easy to model, and would generally be emulated by inter-thread communication if it's important to match the semantics of a source program that includes them. Performance in that case would be terrible.

[1] In Vulkan, OpenGL, OpenCL, and WebGPU they are called "subgroups". In Nvidia including CUDA they are called "warps". In D3D and AMD they are called "waves". In Metal (often running on the same hardware) they are called "simdgroups". This fragmentation of terminology is part of the flavor of working with GPUs.

[2] "Fairly easily" by the standards of GPU infrastructure. In fact, the exact semantics have never been nailed down, and in particular "reconvergence" is poorly defined. Working through this is one of the things blocking subgroups in WebGPU (https://github.com/gpuweb/gpuweb/issues/4306). Even so, they're used commonly in practice, especially for things like fast matrix multiplication where you need to shuffle lots of data into place.

Re:Implementing a GPU's Programming Model on a CPU by tovej on Saturday October 14, 2023 @03:19PM (#37883393)
This is true to some extent, although certainly SPMD has subgroups and reduction operations on those are fairly common.

And you are essentially repeating my point from before, that the fact that an operation among the SIMT threads can be scheduled as one SIMD op is the only special behavior. My example was regular vectorized SIMD ops, but your example of reductions are essentially the same point. Shuffles and horizontal adds are present in SIMT just like they are in regular SIMD.

These same reductions exist in contexts where the model would traditionally be called SPMD. But because the concepts map onto a different level of the system we might not easily recognize them as the same. The same kind of subgrouping happens in a multinode SPMD context in terms of NUMA regions and nodes, and an MPI implementation can handle reductions on a within-node or within-NUMA-region group of ranks more efficiently than a group containing ranks assigned to multiple meaningful hardware regions.

So I agree with you that the one thing SIMT has to differentiate it from SPMD is the SIMD-like scheduling of multiple threads -- and this was exactly my point from before -- but even here we find that SPMD has the same concepts, just not as explicitly, because the stack typically used in SPMD is more flexible, and SIMT can take advantage of specialized hardware ops.

Optimizations like this do not necessarily mean that the model isn't SPMD though. It's still a single program (a kernel) processing multiple data (indexed by the thread id). The one key idea of SIMT is really all about the batch scheduling of threads, the fact that multiple threads from a warp can be executed on one SM partition (using CUDA terms here) using a single instruction and a mask.

SIMT emphasizes the GPU scheduler, but it still fits completely within SPMD. All SIMT technologies are SPMD technologies, but not all SPMD technologies are SIMT technologies. I'm not convinced there is enough new in SIMT to warrant the branding using a new architecture type in the taxonomy. They could have just as well emphasized the thread scheduling as an optimization in an SPMD context.

Re:Implementing a GPU's Programming Model on a CPU by dang on Saturday October 14, 2023 @02:51PM (#37883140)
Please don't respond to a bad comment by breaking the site guidelines yourself. That only makes things worse.

If you'd please review https://news.ycombinator.com/newsguidelines.html and stick to the rules when posting here, we'd appreciate it. Note this one:

"Please don't comment on whether someone read an article. "Did you even read the article? It mentions that" can be shortened to "The article mentions that.""

Re:Implementing a GPU's Programming Model on a CPU by tovej on Saturday October 14, 2023 @03:26PM (#37883462)
My bad, I'll do better.
Re:Implementing a GPU's Programming Model on a CPU by dang on Saturday October 14, 2023 @02:53PM (#37883157)
You've continued to post aggressively, attacking other users and generally posting in the flamewar style, even though we've asked you many times to stop. If this keeps up, we're going to have to ban you. I don't want to ban you, because you obviously have a lot of knowledge to share, but your aggressiveness destroys more than your knowledge contributes—a lot more, actually. Fortunately, there are plenty of other knowledgeable users here who treat their fellow users respectfully. Please be like them instead.

https://news.ycombinator.com/newsguidelines.html

Re:Implementing a GPU's Programming Model on a CPU by mathisfun123 on Saturday October 14, 2023 @04:53PM (#37884172)
It pointless trying to abide by your rules of decorum - I call a thing a rant - as if it isn't and that makes me aggressive? In reality you're just mad I pointed out your kafka-esque moderation policies.

> Please be like them instead.

Be an arrogant martinet? No thanks. But I'll stop posting so congrats on keeping your community homogeneously obnoxious (and ignorant).

Re:Implementing a GPU's Programming Model on a CPU by dang on Saturday October 14, 2023 @06:11PM (#37884715)
I don't remember anything you pointed out about moderation, and in any case we don't ban accounts for criticizing the mods.

This isn't a response to just one comment, let alone one word, but to the pattern of your comments in general: they stand out as nasty, abusive towards other commenters, and not in the intended spirit of the site; not just by a little, but a lot. It's not a borderline call.

Re:Implementing a GPU's Programming Model on a CPU by mathisfun123 on Saturday October 14, 2023 @06:31PM (#37884856)
there's a single questionable word in the flagged comment (the word `rant`) and it's not a borderline call? yup totally makes sense.
Re:Implementing a GPU's Programming Model on a CPU by dang on Sunday October 15, 2023 @04:25PM (#37893099)
You're continuing the pattern here.
Re:Implementing a GPU's Programming Model on a CPU by JonChesterfield on Saturday October 14, 2023 @11:55AM (#37881486)
SIMT and SIMD are different things. It's fortunate that they have different names.

A GPU is a single instruction multiple data machine. That's what the predicated vector operations are. 32 floats at a time, each with a disable bit.

Cuda is a single instruction multiple thread language. You write code in terms of one float and branching on booleans, as if it was a CPU, with some awkward intrinsics for accessing the vector units in the GPU.

That is, the programming model of a GPU ISA and that of Cuda are not the same. The GPU gives you vector instructions. Cuda gives you (mostly) scalar instructions and a compiler that deals with this mismatch, lowering branches to changes in exec mask and so forth.

With my numerical library hat on, I hate this. Programming a simd machine through a simt language means trying to get the compiler to transform the control flow into the thing you could easily write using vector instructions.

With my compiler implementer hat on, I hate this. It gives you two control flow graphs intertwined and a really bad time in register allocation.

It's not totally clear to me why simt won out over writing the vector operations. I'm certainly in the minority opinion here.

Re:Implementing a GPU's Programming Model on a CPU by pca006132 on Saturday October 14, 2023 @12:54PM (#37882102)
I guess that a lot of people are uncomfortable thinking about vector instructions, and dealing with masks manually? And for vector instructions you need to align things properly, pad the arrays such that they are of the right size, that people are not used to I guess.
Re:Implementing a GPU's Programming Model on a CPU by RevEng on Sunday October 15, 2023 @02:10PM (#37891948)
I agree. I work on numerical simulation software that involves very sparse, very irregular matrices. We hardly use SIMD because of the challenges of maintaining predicates, bitmasks, mapping values into registers, and so on. It's not bad if we can work on dense blocks, but dealing with sparsity is a huge headache. Now that we are implementing these methods with CUDA using the SIMT paradigm, that complexity is largely taken care of. We still need to consider how to design algorithms to have parallelism, but we don't have to manage all the minutiae of mapping things into and out of registers.

Modern GPGPUs also have more hardware dedicated to this beyond the SIMD/SIMT models. In NVIDIAs CUDA programming model, besides the group of threads that represents a vector operation (a warp), you also have groups of warps (thread blocks) that are assigned the same processor and can explicitly address a fast, shared memory. Each processor has many registers that are automatically mapped to each thread so that each thread has its own dedicated registers. Scheduling is done in hardware at an instruction level so that you can effectively single cycle context switches between warps. Starting with Volta, it will even assemble vectors from threads in any warps in the same thread block, so lanes that are predicated off in a warp don't have to go to waste - they can take lanes from other warps.

There are many other hardware additions that make this programming model very efficient. Similar to how C and x86 each provide abstractions over the actual micro ops being executed that hides complexity like pipelining, out of order execution, and speculative execution, CUDA and the PTX ISA provide abstractions over complex hardware implementations that specifically benefit this kind of SIMT paradigm.

Re:Implementing a GPU's Programming Model on a CPU by shihab on Saturday October 14, 2023 @01:03PM (#37882196)
I think it boils down to which GPGPU camp you are in, AI or HPC.

AI has relatively simple workflow, less thread divergence, so the SIMT abstractions add very little value. HPC workflow is on the hand lot more complex. Writing a good simulation program for example, is going to get inhumanly complex with just SIMD.

Re:Implementing a GPU's Programming Model on a CPU by alphablended on Sunday October 15, 2023 @04:41AM (#37888077)
> It's not totally clear to me why simt won out over writing the vector operations.

From the user side, it is probably simpler to write an algorithm once without vectors, and have a compiler translate it to every vector ISA it supports, rather than to deal with each ISA by hand.

Besides, in many situations, having the algorithm executed sequentially or in parallel is irrelevant to the algorithm itself, so why introduce that concern?

> I'm certainly in the minority opinion here.

There are definitely more userland programmers than compiler/numerical library ones.

Re:Implementing a GPU's Programming Model on a CPU by JonChesterfield on Sunday October 15, 2023 @01:16PM (#37891550)
I think it's easier to write the kernel in terms of the scalar types if you can avoid the warp level intrinsics. If you need to mix that with the cross lane operations it gets very confusing. In the general case volta requires you to pass the current lane mask into intrinsics, so you get to try to calculate what the compiler will turn your branches into as a bitmap.

So if you need/want to reason partly in terms of warps, I think the complexity is lower to reason wholly in terms of warps. You have to use vector types and that's not wonderful, but in exchange you get predictable control flow out of the machine code.

Argument is a bit moot though, since right now you can't program either vendor hardware using vectors, so you also need to jump the barrier to assembly. None of the GPUs are very easy to program in assembly.

Re:Implementing a GPU's Programming Model on a CPU by konstantinua00 on Sunday October 15, 2023 @12:10PM (#37890942)
> SIMT and SIMD are different things.

was anything said against that?

the comment said SIMT is same as SPMD

Re:Implementing a GPU's Programming Model on a CPU by hasmanean on Saturday October 14, 2023 @12:12PM (#37881657)
Subtle difference. A parallel_for can have asynchronous threads. They can all divergen and run independent instructions (due to if statements etc)

SIMT means multiple processors all executing the exact same instruction. One instruction decoder, but like 64 execution pipelines.

Re:Implementing a GPU's Programming Model on a CPU by adrian_b on Saturday October 14, 2023 @01:25PM (#37882399)
The same is true for CUDA/OpenCL kernels. They can include conditionals and they can execute independent instructions.

The difference is that because the software "kernels" (i.e. software threads) may be mapped by the compiler either on hardware threads or on hardware SIMD lanes, and this mapping is not controlled by the programmer, the divergent instructions will cause inefficient (serial) execution when they happen to be executed on SIMD lanes of the same core, so they must be avoided.

This however is only an optimization problem, if the speed would be irrelevant all the kernels could execute divergent instructions.

The reason for the existence of CUDA is to mask for the programmer the existence of the SIMD lanes and to allow programming as if the software threads would map only to hardware threads. Nevertheless, for optimum performance the programmer must be aware that this abstraction is not really true, so the programs should be written with awareness of the limitations introduced by SIMD.

Re:Implementing a GPU's Programming Model on a CPU by my123 on Saturday October 14, 2023 @02:04PM (#37882713)
> Nevertheless, for optimum performance

On conventional SIMT implementations (pre-Volta), the programmer also has to be aware of it to not cause deadlocks in the atomics across different lanes in the same warp.

On NV Volta onwards, each SIMT lane has its own instruction pointer with opportunistic reconvergence when possible.