Energy-efficient programming with Go and beyond
Greener Coding
Go has a reputation for producing energy-saving applications, but you still have to know what you are doing.
Applications use the processor in different ways, and those differences are sometimes reflected in the power bill. The programming language you choose has a significant influence on energy consumption. But developers still need to go the extra mile to leverage the language's capabilities.
At first glance, Go comes with everything you need for energy efficiency. It has a lean syntax, and smart Goroutines distribute parallel tasks efficiently to the processor cores, thus avoiding a bloated runtime environment that needs to manage complex class hierarchies or juggle classic threads. And the compiler translates the source code into a native and therefore fast program, which means the processor can go back to sleep sooner and save energy. On top of that, Go statically links all external modules into the finished binary, eliminating the administrative overhead of dynamic libraries during execution.
This contrasts strongly with Java, where a compiler converts the program into intermediate code, which is then executed by a virtual machine. This additional software layer slows down execution and costs unnecessary energy. The situation is even worse for interpreted languages: PHP and Python parse each line of code step-by-step during execution. Numerous optimizations and just-in-time compilers are intended to make the resulting applications faster, but there is still some loss, depending on the task. If you want to develop energy-efficient programs, you need to go for Go, right? Or maybe not? The following look at energy efficiency in Go is a useful entry point for examining some more general rules for more efficient coding.
SLE Research
Back in 2017, a team of researchers wanted to know which programming language produces particularly energy-efficient applications. They presented the results of their study at the International Conference on Software Language Engineering (SLE [1]). According to the study, compiling programming languages such as C and Go work far more efficiently than interpreted counterparts such as PHP or Python. The results are less clear for languages that generate intermediate code. Java programs, for example, run faster and in a more energy-efficient way on average than their Go counterparts (Figure 1). Surprisingly, the virtual machine doesn't seem to slow things down – at least not in the trial, which has a few bugs on closer inspection.
The SLE study serves as a wake-up call for those who think they are automatically writing more efficient code just by choosing Go. However, a closer look also points to the complexity of these energy efficiency issues – and the danger of making assumptions based on a single study.
Initially, the researchers used only one possible compiler or interpreter for each language. Another Go compiler named TinyGo harnesses the LLVM framework to create highly optimized machine code for microcontrollers [2]. The C code in the study was compiled exclusively using the GCC.
The Go compiler used was version 1.6, and this was already considered obsolete at the time of the study. Of course, the other compilers and interpreters have also been revised and further optimized in the meantime. For example, PHP 8 can handle significantly more concurrent requests than its predecessors.
No Clouds
The researchers used the Computer Language Benchmark Game (Figure 2) for their measurements. This benchmark [3] consists of 10 individual tests implemented in a total of 28 languages. Among other things, these small programs calculate Mandelbrot sets and binary trees. The study only investigated which languages perform these individual manageable calculations in an energy-efficient manner. In contrast to this, real applications need to solve completely different tasks. Encryption tools, for example, struggle with extremely tricky mathematical problems, whereas web servers merely push data packets across the network.
Complex Internet and cloud applications, such as the ownCloud Infinite Scale (oCIS [4]) file sharing platform implemented in Go, were not included in the tests. OCIS was created as a more powerful alternative to the classic ownCloud PHP application, which reached its limits when faced with higher loads and many simultaneous users. The oCIS developers made their own attempt to optimize oCIS, and in the meantime, they ended up learning a lot about how to optimize Go. Unlike the small benchmark programs, however, oCIS consists of numerous services that work together on a network. The oCIS developers had to take a slightly different approach to their assessment.
If an application solves a task as quickly as possible, the processor can switch back to one of its energy-saving modes faster. It is therefore not surprising that, in the SLE study, the compiler languages were also the most energy-efficient. The oCIS developers also currently assume that high-performance programs consume less energy. This assumption allows for a focus on performance measurements and optimizations for which established tools and processes exist.
Go helps its developers with a built-in profiler [5]. The profiler measures the execution times for code parts to detect inefficient operations. According to Klaas Freitag, CIO of ownCloud GmbH, the Go profiler is usually only suitable for tracking down bugs, especially in distributed systems. This is why the oCIS team used an in-house development for its performance measurements: a tool named cdperf
[6], which in turn harnesses the well-known k6
test tool [7] (Figure 3). The k6
test tool simulates multiple users accessing the file sharing platform simultaneously.
If so desired, the Go compiler can run customized benchmarks that you can use to determine the performance of code changes [8]. For example, if a function calculates the greatest common divisor, you could call a DIY benchmark individually for thousands of different pairs of numbers. If the benchmark delivers a shorter runtime after a code change, you have successfully optimized the task of computing the greatest common divisor. The benchmarks can be maintained along with the (unit) tests and included in the development from the beginning.
Know Your Language
Once you have identified inefficient parts of the program, you need to optimize the source code; more specifically, you need to find the most efficient algorithms. Many programming languages support efficient development by evaluating constructs. For example, the Go compiler can already evaluate constant expressions, which saves computation time later during execution. However, this feature requires the developers to correctly integrate the constant expressions into the source code.
Furthermore, Go is a typed language that distinguishes between floating point and integer numbers. Because many processors calculate faster with integers, you should give them preference if possible. This is especially true if you use them as loop counters. Speaking of loops: Classic brakers and power guzzlers include nested but actually superfluous loops, sprawling recursions, and unnecessary repetitions. If a program has to recalculate all the thumbnails every time the image gallery is called up, for example, this repetitive work eats up energy unnecessarily.
The Go developers provide many more tips for efficient programming [9] on a separate page (Figure 4). Comparable collections exist for other languages. In any case, you should not rush into every single file operation. From Freitag's point of view, such simple operations are already optimized. For example, PHP saves a file to disk just as quickly as a Go program would.
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.
-
SUSE Renames Several Products for Better Name Recognition
SUSE has been a very powerful player in the European market, but it knows it must branch out to gain serious traction. Will a name change do the trick?
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.