Energy Efficient Programming

Energy-efficient programming is crucial when considering how program execution, computation, and data processing affect the energy which is consumed during the process.

During computations, the processor typically consumes the majority of the energy. On average, the CPU consumes almost 90% of the energy, with the remaining energy consumed mainly by memory1). This is true regardless of the programming language type. It does not matter if the language is compiled or interpreted.

Energy efficiency is going to be a popular topic in research and among major players in the information technology industry. This goal can be achieved through improvements in hardware technology. Modern processors and system-on-chip integrated circuits (which serve as the processor in highly integrated gadgets like smartphones, tablets, IoT units, and similar devices) implement a range of power modes that allow them to shut down unused internal modules. Additionally, the operating system can adjust the clock frequency to meet the current software demand. These techniques drastically reduce the device's overall power consumption, but there is still potential for further improvement through efficient software implementation. The need to reduce energy consumption in consumer electronics can affect smartphone battery life. Users try to avoid CPU-intensive apps to get a bit more time from the phone's battery. Owners of big data centres and cloud computing systems pay attention to software energy efficiency, understanding that it impacts the carbon emissions of data centres 2).

The energy consumed by the computer running the software depends on the execution time, clock frequency and average power consumption of the hardware. It can't be expressed with a simple formula, but in general, all coefficients are directly proportional. If the power, time, or frequency increases, energy consumption also increases. It indicates where one can find reductions in the energy required to perform a task. It is worth noting that for the same code, the time and frequency are interdependent. If the system runs faster, the time of task execution will be shorter. This means that the code efficiency relies on the number of cycles the software requires to complete the task. This suggests that reducing the number of instructions can further lower energy consumption and make computation more environmentally friendly. There are two main possible approaches to reducing the number of instructions:

Code optimisation is implemented well in modern compilers. The machine code is generated using techniques that reduce the number of unnecessary instructions, such as loop unrolling. Compilers enable data parallelism through extensive use of vector operations. However, because they must be universal, the output code is always generic in some elements, and a good assembler programmer can identify places for improvement.

In certain computer systems, it is possible to reduce energy consumption by switching software implementation from continuous to interrupt-driven execution. In continuous execution, the software continually executes the infinite loop and reads data from the input elements at regular intervals. In an interrupt-driven approach, the processor enters the idle state when there is nothing to be done. Input devices signal when new data arrives, prompting the processor to wake up and execute the necessary code. In the Windows operating system, power management is implemented as part of the system's functionality, and user software can't control devices or their modes of operation. Devices are controlled using drivers provided by their vendors. Interrupt handlers are elements of these drivers.

The most important thing to consider when writing a program in any programming language is to cooperate with the processor and not work against it. This includes the proper placement of data in memory, taking into account both alignment and cacheability, avoiding conditional jumps, manually unrolling loops, and utilising the maximum possible register sizes available in the machine. These are just a few examples. As a rule, assembly language programming, because the user knows what they want to achieve, usually allows for better code optimisation than compiler-generated code. Of course, this comes at the cost of more time spent writing the program and the increased risk of errors. It also requires extensive knowledge and experience on the part of the programmer. However, it's essential to remember that a program written in assembly language does exactly what the programmer intended and is not dependent on fragments of code, sometimes completely unknown, when using external libraries.