Introducing Eyot – A programming language where the GPU is just another thread

Eyote is a new language I’m building to make offloading work to the GPU as intuitive as spawning a background thread.

The Eyote source code is compiled transparently for both CPU and GPU, with communication between the two controlled by the runtime. Traditional GPU programming expects you to handle many tasks, such as allocating memory, compiling the kernel, scheduling tasks, etc. These have long been handled by a language runtime when writing code for a CPU, and Eyote extends that feature to code destined for GPUs as well.

The intended users are those in areas where GPUs or other accelerators are heavily used, for example game development, numerical analysis, and AI.

These are early days for Iyot. It’s not designed for real work, but you can experiment with it, and if you do, I’d love to hear your thoughts. Take a simple example (available in the playground)

fn square(value i64) i64 {
   print_ln("square(", value, ")")
   return value * value
}

cpu fn main() {
    // 1. call it directly
    print_ln("square(2) on cpu = ", square(2))

    // 2. call it as a worker running on cpu
    let cpu_worker = cpu square
    send(cpu_worker, [i64]{ 3 })
    print_ln(receive(cpu_worker))

    // 3. call it as a worker running on the gpu
    let gpu_worker = gpu square
    send(gpu_worker, [i64]{ 4, 5, 6 })
    print_ln(receive(gpu_worker))
}

First, it declares square Function that takes and returns a 64 bit integer. main Then calls it in 3 different ways which shows the distinguishing feature of Eyote

  1. square The function is called as you would expect, directly and on the CPU.
  2. A cpu worker is made from square Celebration (let cpu_worker = cpu square). This worker processes the values ​​sent to it send Work on a background CPU thread. After squaring the number, the worker returns it through a call receive
  3. This time a gpu worker built instead of CPU worker (let gpu_worker = gpu square). causes this square The function has to be compiled as a kernel, and run on the GPU, otherwise it functions identically. As you can see Iyot print_ln GPU-side work

Inspiration

I’ve worked on several projects where moving computation to the GPU presented an obvious path to improved performance that was ignored due to the difficulty of doing so. These projects were not only in obvious areas like computer vision or game development, but also in unlikely matches for desktop application development like GPU programming.

For example, when I worked on the macOS LaTeX editor, Texifier, I adjusted the venerable TeX typesetting system to output polygons directly to GPU memory instead of writing them to PDF. This reduced latency so much that we could update the output in real time. The feature was popular, but the difficulty of implementing it made me question whether the project was worth it.

With Eyote I want to create a language where working on the GPU is so deeply incorporated into the design of the language that it becomes trivial. For a long time we have thought of the CPU/OS combination as something that runs our code rather than as a device to be manipulated. Eyot simply extends it to the GPU. CUDA-like options already exist, but the intention with Eyot is to build the entire language around that model of GPU concurrency.

current situation

Progress has been slow because I work on it in my spare time (sponsors appreciated!), and I’ve recently had a break due to the arrival of a new baby, but my key roadmap items are:

  • rendering Eyote only provides access to the GPU for computational purposes at this level. Game development is a big goal of this project, so providing support is at the top of my wish list. I’m hoping to do this using Vulkan, and also replace OpenCL in favor of Vulkan Compute.
  • Syntax I have postponed development of eyot’s syntax so that I can experiment with CPU/GPU interaction without adding language features that would not be viable in both cases. The major missing syntax features for me are algebraic data types, lambdas and some kind of interface/attribute style polymorphism.
  • gpu memory management There is a lot of work here. vectors and strings can only be allocated CPU-side, this is something that should work on GPUs, I would also like the memory manager to be able to transparently move allocations to shared buffers if appropriate
  • Display adhere to the principle of Implement It, Make It Right, Make It Quick mantra, I’ll probably leave it for the immediate future, but it would be nice to put a real workload on Eyot soon and get them up to speed
  • standard library It doesn’t need improvement, I only have a few tasks, it needs to start…

It’s also useful to mention some things I won’t work on

  • automatic parallelization Eyote does not and will not automatically parallelize work across CPU/GPU cores. The intention is to be a convenient option for distributing work across processors, not to reduce control.
  • theoretically optimal performance Eyot is not intended as a total replacement for current GPGPU libraries, any more than it is intended as a total replacement for assembly over C and C++. I would consider significant performance deviation between Eyote code and equivalent C/Vulkan code to be a bug, but for me the ease of use is an acceptable price to pay for some performance penalties.
  • Being the next great general purpose language There will be as few syntax differences as possible between GPU and CPU, so the language design will be tied to GPU capabilities, which may restrict what I can add to Eyote’s syntax.

Thanks for reading. You can learn more about Eyote from its documentation and source code. If you want to try it out, there’s the playground, or you can install Eyote on your machine.



<a href

Leave a Comment