Conceptio › Archive › arXiv CS
arXiv CS open access

GPU implementation of a resource-constrained virtual machine

2026 · arxiv_cs
arXiv CS · Papers · 2026
Open Source ↗Direct PDF ↓
clouddistributed-computingparallel-computing
Conceptio Open Archive

Analyze & explore related research in Conceptio

Connect this record directly into your research workflow or AI agent. Explore citations across open repositories, query full text, and export structured proof bundles.

GPU implementation of a resource-constrained virtual machine Simone Li 2827442L@student.glasgow.ac.uk University of Glasgow Glasgow, UK

Vladislav Brusokas Andrei Ghita Shuxuan Li 2840479B@student.glasgow.ac.uk 2660223G@student.glasgow.ac.uk 2782934L@student.gla.ac.uk University of Glasgow Glasgow, UK

arXiv:2608.16387v1 [cs.DC] 17 Aug 2026

Abstract One of the main reasons compute hardware becomes obsolete is software bloat: resource requirements increase for every iteration of a software product. Resource constrained VMs are one way to combat software bloat as they post a hard limit on the resources and so force the programmer to be frugal. In this paper we explore the deployment of one such resource constrained VM, Uxn, on GPU. We show that for competitive performance it is essential to make use of the GPU data parallelism. We present an OpenMP-style parallelism API for Uxntal, the stack-based assembly-style language for the Uxn platform. We demonstrate that exemplar code using our API can run at comparable performance even on an integrated GPU. Specifically, our evaluation results show that using this approach improves performance on the compute-intensive Stencil benchmark with 19× and frame rate on the graphics-intensive Bunnymark benchmark with 7×. In practice, all laptops and desktops and even mobile devices have a GPU and our work shows that they can be used to execute frugal workloads effectively.

1

Introduction

Growing awareness of the contribution of emissions from computing to climate change [1] has sparked interest in ways to reduce emissions from computing. Frugal computing advocates for treating computational resources as finite and precious, to be utilised only when necessary, and as frugally as possible [2]. It implies that computing needs to have the lowest possible energy consumption and – importantly – use the currently available hardware technologies. Since emissions from production of end-user hardware far exceed the emissions from computing itself, extending the lifetimes of hardware devices is important to curb emissions from computing. Permacomputing, in analogy with permaculture, considers that computing hardware should be designed for longevity and software designed for resilience in case of (catastrophic) failure of the supporting infrastructure such as the internet, hardware manufacturers, software developing companies, etc. Software should also be understandable and maintainable by a single person, which requires simplicity [3]. In this work we used the Uxn VM [4], developed by Hundred Rabbits (100R), an artist collective that explores low-tech solutions. Uxn is designed for sustainability and portability and is an 8-bit LOCO ’26, Lancaster and Online 2026.

Wim Vanderbauwhede wim.vanderbauwhede@gla.ac.uk University of Glasgow Glasgow, UK

single-threaded virtual CPU. Uxn memory is comprised of 64K of addressable memory (RAM), two 256 byte stacks (return stack, working stack), and 256 bytes of device data. Uxn is programmable in Uxntal, a stack-based assembly language. It is inspired by other stack-based languages (Forth [5]) and by the assembly languages used in gaming consoles. It defines its own graphical system and uses sprite-based and pixel-based graphics to run small graphical applications. Uxn supports up to 16 different input/output (I/O) devices; standard devices include screen, audio, mouse, console, controller, file and datetime [4]. These devices have their own address space and the virtual machine communicates with these through dedicated instructions. Events initiated by the I/O devices are dealt with via event handlers ("vectors" in Uxn). Personal computing devices (desktops, laptops, phones, tablets) produced within the last five to ten years all contain both a CPU and a GPU. GPUs are powerful, massively parallel computational devices. The embodied carbon of the GPU is as significant as that of the CPU, so if we wish to use computing devices carbon-efficiently, we need to find ways to make full use of the GPU. But GPUs are not designed for general-purpose computing. The challenge we aim to address in our research is how to achieve acceptable performance for programs running on a resource-constrained virtual machine implemented on a GPU device. We have used the Uxn/Uxntal/Varavara system to do so. The standard Uxn implementation by 100R uses the GPU for graphics rendering through the SDL2 library, however, all computation is performed entirely on the CPU.

2

Methodology

We implemented Uxn on GPU using the Vulkan API for both compute and graphics. with regard to direct memory access, unifying shaders and concurrent event handling. Uxn works well for lightweight graphical applications so specific demanding applications were required for benchmarking. We benchmarked the performance of the CPU and baseline GPU implementation, with as metrics Frames per Second (FPS) and total runtime. We then compared the performance of the optimised GPU implementation to the baseline GPU implementation.

2.1

GPU programming

We implemented Uxn using the cross-platform Vulkan SDK which allows to combine both compute and graphics. The SDK consists of a C/C++ API for CPU programming and a domain-specific language, GLSL, for the code running on the GPU (known as "shaders"). The

LOCO ’26, Sept 10–11, 2026, Lancaster and Online

Li et al.

Algorithm 1 Example use of the parallelisation API used in the Bunnymark benchmark ;sprite/length LDA2 #0000 parallel-bounds parallel-do &loop ( -- ) EQU2k ?&bail DUP2 <draw-bunny> INC2 !&loop &bail ( -- ) POP2 POP2 end-parallel-do

either read data from the CPU or write data to the CPU. The exception is the Screen device, because drawing of pixels and sprites is part of the computation.

2.3 Figure 1: Flow chart showing the control flow and interactions between CPU and GPU. Blocks with a bold outline are executed on the GPU.

CPU-side API handles data movement between the host memory and the GPU memory and schedules the code to be run on the GPU.

2.2

Uxn Implementation

The aim of our work was to implement the entire Uxn virtual machine and as much as possible of the I/O device functionality on the GPU, thus minimising CPU-to-GPU transfer. However, this approach does not entirely eliminate the need for transfer because the pipeline is CPU-controlled. 2.2.1 Overall program structure. Fig. 1 shows the control flow of the host program and the interactions between CPU and GPU. The structure is complex as the code must deal both with I/O events generated on the host side (keyboard, mouse and the main clock event that governs the frame rate), and with I/O calls from the VM on the GPU (to write to the Console device and to draw on the screen). As mentioned above, Uxn is event-driven, so the I/O devices can register an event handler (called "vector") which will be triggered when an I/O event occurs. Therefore the main flow is (1) determine the next vector to be executed; (2) compute and render on the GPU; (3) draw to the screen using the GPU. On every event that requires hand-over between the CPU and the GPU, the VM state must be copied to the host to ensure that it is preserved, as Vulkan does not guarantee that any state on the GPU is preserved between calls. 2.2.2 Uxn VM core on GPU. We implemented the core of the Uxn VM, the actual bytecode interpreter which evaluates the instructions, using GLSL. The main loop of the VM is a direct port from the C code of the 100R implementation. The changes in this part relate mainly to the memory handling and the I/O device implementations, because the GPU can’t handle I/O directly. Devices only

Single-threaded performance

Porting a single-threaded VM like Uxn to a GPU poses many performance challenges. Fundamentally, whenever an I/O instruction is encountered, the virtual machine must give control back to the CPU. This requires the entire state to be copied back and forth. Furthermore, GPUs are not optimised for control flow nor for integer operation on small integers.

2.4

Using GPU parallel threads

2.4.1 Rationale. Single-threaded (“sequential”) performance is slow compared to the 100R CPU version. This is not surprising as GPU are designed for data parallelism. To exploit this without creating a complex parallel programming API (such as e.g. the POSIX pthreads API) for Uxntal, we opted for a very simple mechanism for parallelisation of dependency-free loops, inspired by the OpenMP [6] “parallel do” pragma. All programmer needs to do is to tags a loop and identify the loop bounds. This is necessary because Uxntal is an assembly language and there are not syntactic constructs to indicate loop structures. 2.4.2 Design and implementation. Because of the limited functionality, the API is very minimal. We provide three Uxntal subroutines: parallel-bounds, parallel-do and end-parallel-do. These functions are simple wrappers around calls to a new I/O device that handles the parallelism (the “Parallel” device). We assume that the initial loop bounds are on the stack, as is common practice in Uxntal. The parallel-bounds call returns the corresponding per-thread loop bounds. The parallel-do call instructs the “Parallel” device to enable use of parallel threads. Code listing 1 shows the parallelisation of the core loop of one of the benchmarks (discussed in Section 2.5). The only change to the code is the addition of the three subroutine calls (indented). On Uxn implementations that don’t have the Parallel device, these calls have no effect. Uxn communicates with external systems ("devices") via a 256byte device page, providing 16 bytes of addressable space ("ports") for up to 16 devices. The Parallel device occupies one such slot. It uses one byte to indicate that the VM is in a parallel section (the

GPU implementation of a resource-constrained virtual machine

LOCO ’26, Sept 10–11, 2026, Lancaster and Online

Algorithm 2 Stencil calculation do t = 1,te p(i,j,k) = ( ( p(i+1,j,k) + p(i-1,j,k) + p(i,j+1,k) + p(i,j-1,k) + p(i,j,k+1) + p(i,j,k-1) )/6 + p(i,j,k) )/2 end do

Figure 2: Screenshot of the Uxn version of the snake game in action control port), and a short (2 bytes) for each of the loop bounds (the upper and lower ports). Loop bounds are written to the respective ports, and setting the control byte marks the start of parallel execution. The device then distributes the loop iterations among invocations. A fixed number of threads are dispatched at the start of shader execution. For the sequential part of the program, the main thread performs the evaluation while the worker threads stay idle. The worker threads operate on local stacks but on shared memory (the Uxn VM RAM). The local loop bounds and the thread IDs are pushed onto the per-thread stacks. Thread IDs allow thread-local state within the parallelised loop despite the shared RAM. When the worker threads terminate, the main thread inherits the program counter of the worker thread with the highest ID and resumes the sequential execution.

Figure 3: Screenshot of bunnymark in action

2.5

Benchmarks

Uxn is predominantly made for lightweight graphical applications, and the GPU version performs well on this type of applications, especially those involving a lot of user interaction and not very demanding computation or graphics. Therefore, to evaluate the performance relative to the reference CPU implementation, we used specialised programs for benchmarking. An example of a lightweight graphical application where the baseline GPU implementation worked very well is Snake [7], implemented in Uxntal in the snake.tal program [8]. In this game the player controls a snake on a grid. The aim is to move the snake so it can eat fruits that appear randomly on the screen. With each eaten fruit the snake’s tail grows; however if the snake’s head collides with the snake’s tail then the player loses. This game is a good test for the performance of the overall virtual machine: it requires keyboard or mouse support for controlling the snake as well as support for the datetime device which is used for a random number generator that determines the placement of the fruits. To benchmark the performance of the CPU and baseline GPU implementation and assess the performance of the optimised GPU implementation using specialised programs, we used two main metrics: • Performance – Frames per Second (FPS): the virtual machine should be able to produce frames at a steady rate, even at high workloads. • Performance – Total Runtime: for programs with a set amount of workload, the total runtime is used to compare performance.

We used two specialised benchmark programs, Stencil and Bunnymark. 2.5.1 Compute-only benchmark: Stencil. The aim of the Stencil benchmark is to evaluate pure compute performance without any graphics. The stencil.tal program implements a 3-D stencil calculation as used in finite difference based differential equation solvers, performed in a time loop. This program is computationally and memory intensive, and provides clear runtime duration for a set amount of work, comparable between implementations. The pseudocode is shown in Listing 2 2.5.2 Compute and graphics benchmark: Bunnymark. Bunnymark [9] is a popular testbench to assess raw graphics performance. The bunnymark.tal program [8]allows to create or remove jumping bunnies on the screen, displayed as sprites, via key presses or mouse clicks. The path of the bunny is a parabola reflecting the jumping movement and impact of gravity. For every frame, for each bunny, calculations are performed to determine the next position based on the current position and the direction of movement, and the bunny is subsequently redrawn. The more bunnies there are, the higher the load on the system, and the frame rate (frames per second, FPS) is calculated and displayed by the program itself.

2.6

Test platforms

In keeping with the typical use of Uxn and the frugal computing philosophy, the main test platforms used in the evaluation were two laptops from 2019. Their specifications are shown in Table 1.

LOCO ’26, Sept 10–11, 2026, Lancaster and Online

Li et al.

Table 1: Test platforms used in the evaluation TongFang PF4MN2F (“TF”) OS Type Clock speed (GHz) CMOS node Die area (mm2 ) Thermal Design Power (W)

Ubuntu 22.04 Intel CPU Intel GPU Core i7-10510U UHD Graphics 630 (4 cores) (24 CUs) 1.8–4.9 0.35–1.15 14 nm 126 + 37 25

NVIDIA GPU GeForce MX250 (3 CUs) 1.52–1.58 14 nm 74 25

MacBookPro16,1 (“MBP”) macOS 12.7.6 Intel CPU AMD GPU Core i7-9750H Radeon Pro 5500M (6 cores) (22 CUs) 2.6–4.5 1.0–1.45 14 nm 7 nm 149 158 45 85

Table 2: Summary of Stencil benchmark results, 16 iterations. “Seq” = sequential version on GPU; “Par” = parallel version on GPU; Ref = reference version on CPU GPU

Seq/Ref slowdown

Par/Seq speedup

Par/Ref slowdown

Par Elapsed time (s)

Ref Elapsed time (s)

TF NVIDIA TF Intel MBP AMD

95× 69× 53×

19× 18× 19×

5× 4× 3×

1.23 0.92 1.26

0.24 0.24 0.44

The clock speed lists two values. The highest value is the boost or turbo boost frequency. Both platforms also include an Intel UHD Graphics integrated GPU, but the current implementation only supports this device on the TF. On both platforms we used the Vulkan SDK v1.4 and gcc/g++ version 13.

3

Evaluation

We compared the performance of the GPU implementation against the 100R implementation of Uxn, both for sequential and parallel versions of the benchmarks.

3.1

Stencil

A summary of the Stencil benchmark results is shown in Table 2. The key observation is that the parallel version is almost twenty times faster than the sequential version on all platforms, despite the very different GPUs. On the integrated GPU on TF, this is still 4× slower than the reference; on the discrete GPU on MBP, it is only 3× slower. The difference is caused by the better performance of the 100R Uxn VM implementation on the TF CPU compared to the MBP CPU. This is interesting as the TF CPU has a much lower base clock speed (1.8 GHZ vs 2.6 GHz). Another interesting observation is shown in Fig. 4. It shows that for long running tasks, the CPU utilisation for the reference implementation tends to 100%, but for the GPU implementaton it tends to 0%. This confirms that the workload is indeed entirely offloaded to the GPU. The difference in the utilisation between TF and MBP is likely caused by the difference in CPU scheduling, and therefore CPU time accounting, between the Darwin OS kernel of macOS and the Linux kernel.

3.2

Bunnymark

Bunnymark assesses the performance of the frame rate (FPS) as a function of the number of bunnies. Fig. 5 shows the GPU sequential and parallel performance and the performance of the reference

Figure 4: CPU utilisation for the benchmark running on the GPU and on the CPU, as a function of the number of iterations implementation. On the integrated GPU on TF, the optimised sequential version manages an acceptable 40 FPS for 32 bunnies. The parallel version on TF tracks the reference version until 256 bunnies and performs very well (>30FPS) up to 2048 bunnies. On MBP, the optimised sequential version also manages 40 FPS for 32 bunnies. Performance of the parallel version is on par with the reference version, maintaining 50 FPS for up to 2048 bunnies. The performance of the sequential programs on the GPU implementation is in line with our earlier observation that most Uxn applications run fine on the sequential version because they are not very demanding. Parallelisation results in an improvement of 8× in FPS @ 512 bunnies for the integrated GPU on TF and 7× for the discrete GPU on MBP.

4

Discussion

Many aspects conspire to make the current implementation of the Uxn VM slow on the GPU: the VM needs frequent data movement and control hand-over between CPU and GPU because of I/O handling; the interpreter is single-threaded and control flow dominated; and the VM compute consists entirely of integer operations. The compute-only benchmark shows that pure compute using a single thread is 50× to 100× slower on GPU than on CPU. Data movement also causes slowdown because we need to copy memory between the host and the GPU memory, whereas the entire state of the Uxn VM on CPU fits easily in the cache. Furthermore, the GPU runs

GPU implementation of a resource-constrained virtual machine

Figure 5: Bunnymark performance at a lower clock speed than the CPU. On TF, the observed CPU clock speed while running the reference implementation is 2.3 GHz; the observed GPU clock speed while running the integrated GPU implementation is 1.13 GHz, so a ratio of 2. On the MBP, the CPU clock runs at 2.2 GHz. The AMD GPU has a clock speed of at most 1.45 GHz so the ratio is around 1.5. All these aspects combine to result in very slow single-threaded performance for heavy workloads. As shown above, exposing the GPU data parallelism to the programmer results in considerable improvement in performance, both for compute and graphics, across all tested platforms. Using diagnostic tools (powertop, intel-gpu-top and nvidia-smi on TF, powermetrics on MBP) we have ascertained that the parallelism does not result in appreciably higher power consumption. This is because, although the GPUs have hundreds to thousands of hardware threads, they are grouped in far fewer compute units (e.g. 3 on TF, 24 on MBP), and therefore even a single thread fully occupies such a unit. For graphical applications, the aim is to compute in less than a frame period. If the computation is performed in parallel, it finishes sooner, so the energy consumption is reduced proportionally. On TF integrated GPU, there is a considerable energy saving from parallelisation as we speed up the computation 18× using parallelism at no observed increase in power consumption. We have further ascertained that running the Uxn VM on the GPU has a comparable power consumption to running it on the CPU (between 1× and 2×). This may seem slightly odd because running a single-threaded VM on a multicore CPU should result in only a single core being occupied, and therefore the total power consumption should be proportionally lower. However, the idle power consumption is still considerable, and although the GPU spends more time doing the same work, the GPU implementation does not actually execute considerably more instructions: the main additional work is moving the data between the host and GPU memory, and the state of the Uxn VM is a very small amount of data. Therefore the power consumption is comparable. So overall, our results show that it is possible to obtain comparable performance at comparable power consumption for applications that can be parallelised, although for most cases the performance is slightly lower and the power consumption slightly higher. It should be noted that in any case, the energy consumption of Uxn applications is low because for a typical interactive application with simple graphics, most of the time the process will be waiting for I/O operations as human input is very slow compared to the clock speed. Therefore, if we consider a laptop as a platform for running

LOCO ’26, Sept 10–11, 2026, Lancaster and Online

Uxn, rather than e.g. to watch streaming video, the environmental impact is mostly caused by its production, and in particular by the chip manufacturing process. According to a report from 2019 by the European Environmental Bureau (EEB) [10], for a laptop running average work workloads, “manufacturing, distribution and disposal account for about 52% of a notebook’s total climate impact”. This proportion has risen to 65% in 2025. The EEB calculates that to limit the Global Warming Potential, we should use our laptops for 20 to 44 years, whereas the current average lifetime is 4.5 years. Making better use of the available hardware is one way to achieve this, and that is our main motivation to make Uxn run on GPUs, not because of Uxn specifically but because resource constrained VMs are one way to combat the software bloat which is one of the main reasons compute hardware becomes obsolete.

5

Conclusion

We have presented the GPU implementation of a resource-constrained virtual machine, the Uxn VM, and a simple OpenMP-style parallelism API for Uxntal, the stack-based assembly language for this platform. Even without making use of the GPU hardware parallelism, the GPU implementation can run most Uxn programs with the same performance as the reference CPU implementation, but we have found that single-threaded GPU performance is intrinsically much worse than that of the CPU. To make optimal used of the GPU, using data-parallel computation is essential. We have shown that our simple approach to parallelise dependency-free loops results in very considerable performance improvements without increasing power consumption. On all test platforms, the resulting performance on the Bunnymark benchmark was comparable with the CPU implementation, with comparable power consumption. In future work we will further optimise the performance and investigate if there are specific use cases where Uxn on the GPU outperforms the CPU. The source code for this work has been released under an open source license and can be found at [11].

References [1] Charlotte Freitag, Mike Berners-Lee, Kelly Widdicks, Bran Knowles, Gordon S Blair, and Adrian Friday. The real climate and transformative impact of ict: A critique of estimates, trends, and regulations. Patterns, 2(9), 2021. [2] Wim Vanderbauwhede. Frugal computing–on the need for low-carbon and sustainable computing and the path towards zero-carbon computing. arXiv preprint arXiv:2303.06642, 2023. [3] V.-M. Heikkilä. Permacomputing update 2021, 2021. URL http://viznut.fi/textsen/permacomputing_update_2021.html. [4] D. Lu Linvega. Hundred rabbits, . URL https://wiki.xxiivv.com/site/hundred_ rabbits.html. [5] Charles H Moore and Geoffrey C Leach. Forth–a language for interactive computing. Amsterdam: Mohasco Industries Inc, 1970. [6] Leonardo Dagum and Ramesh Menon. Openmp: an industry standard api for shared-memory programming. IEEE computational science and engineering, 5(1): 46–55, 1998. [7] Quinn Myers. An oral history of snake on nokia, 2019. URL https://melmagazine. com/en-us/story/snake-nokia-6110-oral-history-taneli-armanto. [8] D. Lu Linvega. Hundred rabbits, . URL https://git.sr.ht/~rabbits/uxn-games/. [9] Iain Lobb. Display list vs. blitting - the results!, nov 2010. URL https://blog. iainlobb.com/2010/11/display-list-vs-blitting-results.html. [10] EEB. Coolproducts don’t cost the earth – full report, 2019. URL www.eeb.org/ coolproducts-report. [11] Simone Li, Andrei Brusokas, Vladislav Ghita, Shuxuan Li, and Wim Vanderbauwhede. Uxn on GPU. URL https://codeberg.org/wimvanderbauwhede/uxngpu.

Related documents

Record · ID 459609 · SHA-256 add66dac16b813a7
Retrieved via Conceptio: every document is proof-bundled with source, license, and retrieval metadata.
Bring this data into your agent: Connect via MCP or API · 20 free credits to start · no card required
Read the Docs → · View CLI source on GitHub · Conceptio Open Knowledge Archive