A functional approach to heterogeneous computing in embedded systems
Doctoral thesis, 2020
In this thesis we explore a functional approach to heterogeneous system development as a means to address many of the modularity problems that are typically found in the application of low-level imperative programming for embedded systems. In particular, we explore a staged hardware software co-design language that we name Co-Feldspar and embed in Haskell. The staged approach enables designers to build their applications from reusable components and skeletons while retaining control over much of the generated source code. Furthermore, by embedding the language in Haskell we can exploit its type classes to write not only hardware and software programs, but also generic programs with overloaded instructions and expressions. We demonstrate the usefulness of the functional approach for co-design on a cryptographic example and signal processing filters, and benchmark software and mixed hardware-software implementations.
Co-Feldspar currently adopts a monadic interface, which provides an imperative functional programming style that is suitable for explicit memory management and algorithms that rely on a certain evaluation order. For algorithms that are better defined as pure functions operating on immutable values, we provide a signal and array library that extends a monadic language, like Co-Feldspar. These extensions permit a functional style of programming by composing high-level combinators. Our compiler transforms such high-level code into efficient programs with mutating code. In particular, we show how to execute an FFT safely in-place, and how to describe a FIR and IIR filter efficiently as streams.
Co-Feldspar’s monadic interface is however quite invasive; not only is the burden of explicit memory management quite heavy on the user, it is also quite easy to shoot on eself in the foot. It is for these reasons that we also explore a dynamic memory management discipline that is based on regions but predictable enough to be of use for embedded systems. Specifically, this thesis introduces a program analysis which annotates values with dynamically allocated memory regions. By limiting our efforts to functional languages that target embedded software, we manage to define a region inference algorithm that is considerably simpler than traditional approaches.
Author
Markus Aronsson
Chalmers, Computer Science and Engineering (Chalmers), Functional Programming
This performance comes at a cost of increased complexity, as programmers need to account for differences in each unit's programming practises and capabilities. These issues are further aggravated by the fact that embedded systems are predominantly developed with low-level languages like C and Assembler. While these are good for extracting maximum performance from a system, they provide little to no abstractions for easing development, and will inadvertently end up tying their code to whatever computing element it is supposed to run on.
In general, writing software for heterogeneous systems demands that we generalise functionality and abstract away from particular architectures. On the other hand, performance relies on the ability to tailor designs and configurations to a particular environment. While the desire for performance seems to go against the above desire for modular and generic programs, we note that such optimisations should primarily be considered late in development; a strong focus on performance during the initial development of a system is a kind of premature optimisation.
We therefore argue that the development of embedded heterogeneous systems can benefit from ideas in functional programming, since it provides the abstractions and modularity necessary to quickly build software in a modular manner without having to worry about implementation details. In particular, functional languages have:
- Functions that are higher-order and thus allow us to abstract over entire algorithms, not just values.
- Functions that are free from side effects, which is great when reasoning about a program's behaviour.
- Lazy evaluation, which avoids needless or intermediate values.
- A rich type system that allow us to write generic functions constrained only by the functionality they require.
These attributes allow us to delay many of a system's design choices until later stages of development, and promotes re-usable and modular programs. Then, once a satisfying design has been reached, we could use a compiler to turn its functions into optimized programs in, for example, C.
In response to challenges of heterogeneous systems, and the potential benefits of functional programming, we have construct a functional language that is specifically designed for the implementation digital signal processing algorithms way with predictable performance. The language allow users write to programs in a generic and compositional way, which in turn enable us to quickly explore different designs.
Subject Categories
Computer Engineering
Embedded Systems
Computer Systems
ISBN
978-91-7905-328-4
Doktorsavhandlingar vid Chalmers tekniska högskola. Ny serie: 4795
Publisher
Chalmers