Drivers
This page traces one submission from Rig.submit through a driver to the
hardware and back. What a driver must do, and what rig guarantees it, is in
rig_edge.mli: the facts a device declares, its
timeline word and how the word advances, the three C functions room,
submit and commit with the properties a driver keeps, and the counted
calls that its stop never overlaps.
The shape of a driver
A driver is a library that links rig.edge and never rig, as the preamble of
rig_edge.mli states. It allocates a device's
memory, loads code on it, and places work on its queues. rig reads the
device's facts once, when it opens, and calls three C functions of the
driver to run work, with the OCaml runtime released. Below, submit alone
names the driver's C function, and Rig.submit the OCaml call.
The device reports progress in its timeline word, which only the driver writes.
A store on a queue writes it, or the host writes it from a handler. A wait
reads the word directly, or through the driver's signaled where the word has
no host address. Three properties of a driver carry every rule of Rig's Order
section: the work handed to each queue runs in order, a value's work starts
after the previous value's work has completed, and the host learns through the
word which values have completed, or that the device faulted. Device order is
rule 1 of the Order section seen from the driver.
One submission
This traces a launch on an AMD GPU through Rig_amd, the driver that every
way of opening an AMD GPU builds its device with. Its word is host
memory that the GPU's release packet writes (Store), and whose submit
also commits. The steps before the driver's submit are the same for every
driver.
- Checks and claims.
Rig.submitchecks the run and its buffers, and takes a read claim on every allocation the work uses, so that no donation writes one in place while the submit runs. - Points to follow. It reads the stamps of every allocation the work
uses and collects the points the work must follow, by the rules of
Rig's Order section, with those of~waits, leaving out the points already reached. - Producers. A producer is a device whose point another device's work
waits for (
Rig_edge.waits). For each point of a producer,Rig.submitcommits the producer's work through the point. Where the device's facts say its queues can wait for that producer, it keeps the point for the driver'ssubmitto place as a queue wait, and otherwise it waits for the point on the host. - Room. In C, without running OCaml, it waits until no other call is
submitting or committing on the device, then calls the driver's
roomwith the parts, the run's blocks and the submission's scratch,RIG_SCRATCHbytes per part that the driver may write during the call (the C functions section ofrig_edge.mli). If the parts fit only later, it gives the device back, waits until the device has reached one more value, and callsroomagain. A driver may instead block in itssubmituntil the work fits, as Metal's does. - The value. It assigns v, one more than the device's submitted value,
and calls the driver's
submitwith v, the waits, the parts and their scratch, the run's blocks and the address of each of the run's buffers. No OCaml code runs between the two, so the driver receives v's work or the device is lost. - The driver's
submit.Rig_amdfirst decides, into the scratch, which of its rings runs each part. A large copy within the GPU's memory runs as a kernel on the compute ring, and every other part, the launch here, on its own queue's ring.roomdecided the same, to count the space each ring needs. On each queue the submission uses,Rig_amdplaces a wait for v - 1 where the other queue completed it, which keeps device order across its two queues, and on the compute queue the waits for other devices' words. For the launch it copies the parameters into memory of its own, adding each buffer's address at its refs, and places a dispatch packet. On the last queue it places a release that writes v into the timeline word. It then flushes the host's writes through the GPU's memory window, if anyMappedmemory is live on the device or mapped by it, sets each queue's write position and rings its doorbell, and returns that every value up to v is committed. - The stamps. Back in rig, whatever the driver's
submitreturned,Rig.submitadds(d, v)to the stamps of every allocation the work uses and, if the submission keeps a value, to the stamps that keep it. It then releases its claims and returns the point(d, v). It raisesRig.Lostinstead if the driver'ssubmitfailed, or if the device was lost beforeRig.submitreturns. - The hardware. The GPU runs the dispatch, then the release writes back its caches and stores v into the word.
- The wait.
Point.wait (d, v)reads the word. While it stands below v, the wait spins, then sleeps in the driver'ssleepuntil an event of the device or a timeout, and reads again. Once the word reads v or more, the wait returns, and the host follows the work. - Return. A later
Buffer.createon the device finds the collected memory whose points the word shows reached, and moves it to the cache (Rig's Reclamation section).
A driver whose submit does not commit splits step 6. Metal's submit
encodes the work into an open command buffer, which runs nothing until it is
committed. A wait commits it, and so does the driver itself when the GPU
runs short of work or the buffer holds enough values. Metal's completion
handler then writes the word (Host).
this page is tested with mdxedit this page ↗