Laptop vs. desktop for compiling Haskell code
I’ve been using various laptops as daily drivers for the last 12 years, and I’ve never felt they were inadequate — until this year. There were a few things that made me put together a desktop PC last month, but a big reason was to improve my Haskell compilation experience on big projects.
So let’s test how fast Haskell code compiles on a laptop vs. a desktop.
|CPU||Intel Core i7-6500U||AMD Ryzen 7 3700X|
|Base clock||2.5 GHz||3.6 GHz|
|Boost clock||3.1 GHz||4.4 GHz|
|Number of cores||2||8|
|Memory speed||2133 MT/s||4000 MT/s|
I picked four Haskell packages for this test: pandoc, lens, hledger, and criterion. An individual test consists of building one of these packages or all of them together (represented here by a meta-package called
The build time includes the time to build all of the transitive dependencies. All sources are pre-downloaded, so just the compilation is timed.
The compilation is done using stack (current master with a custom patch), GHC 8.8.4, and the lts-16.26 Stackage snapshot, with the default flags.
The build time of each package (including the
all meta-package) is measured 3 times, with all tests happening in a random order. There is a 2 minute break after each build to let the CPU cool down.
The CPU frequency governor is set to
performance while compiling and to
powersave during the cooling breaks.
To calculate the average level of parallelism achieved on each package, I divide the user CPU time by the wall-clock time (as reported by GNU time’s
%e, respectively), using the data from the desktop benchmark (as it has more potential for parallelism).
The full benchmark script is available here.
I also measured the average power drawn by both computers, both when running the benchmark and in the idle state. As my power meter only reports the instantaneous power and cumulative energy, I measured the cumulative energy (in W⋅h) at several random time points and fitted an ordinary least squares linear regression to find the average power.
The first result is that I had to take the laptop outside the house (0°C) to even be able to finish this benchmark; otherwise the computer would overheat and shut down. While the laptop was outside, the CPU temperature would rise up to 74°C. The desktop, on the other hand, had no issue keeping itself cool (< 60°C) under the room temperature with only the stock coolers.
And here are the timings.
We can also see how well the desktop/laptop speed ratio is predicted by the parallelism achieved for each package.
The average power (where averaging also includes the cooling breaks) drawn during the benchmark was 19W for the laptop and 65W for the desktop.
The average idle power was 3W for the laptop and 37W for the desktop.
The overheating laptop issue is real and has happened to me numerous times while working on real projects, forcing me to limit the number of threads and making the compilation even slower. This alone was worth getting a desktop PC.
There’s a decent increase in the compilation speed, but it’s not huge. The average time ratio (1.65) is much closer to the ratio of clock frequencies (1.42–1.44) than to the difference in the combined power of all cores. Also, the laptop/desktop ratio grows slowly with the level of parallelism. My interpretation of this is that the (dual-core, 4 threads) laptop is capable of exploiting most of the parallelism available when building these packages.
So the way things are today, I’d say a quad-core or probably even a dual-core CPU is enough for a Haskell developer to compile code.
That said, I hope that our build systems become better at parallelism over the coming years.
In terms of power efficiency, the laptop is a clear winner: twice as power-efficient for compilation (after adjusting for the speed difference) and 13 times as power-efficient when idle.
I also played a bit with overclocking the desktop’s CPU. I’m not an experienced overclocker and didn’t dare to go to the extreme settings, but moderate overclocking (raising the clock speed to 3.8 GHz or enabling MSI Game Boost) actually resulted in longer compile times. My understanding is that overclocking affects all cores, while CPU’s default “boosting” logic (which is disabled by overclocking) can significantly boost the clock frequency of one or two cores when needed. The latter seems to be a much better fit for a compilation workload, where most of the cores are idle most of the time.
Thanks to Félix Baylac-Jacqué for educating me about the modern PC parts.