Lably
Skip to content

Automatic parallelization

Compiler transformation of sequential programs for parallel execution

  • 8 min read
  • 7 chapters

Related on Lably

Through Control flow

Automatic parallelization attempts to reduce the amount of explicit parallel programming required of the programmer. To do so, a compiler must determine whether operations can execute concurrently without changing the behavior of the program and whether executing them in parallel is likely to improve performance. This involves analyses such as dependence analysis, alias analysis and data-flow analysis, together with program transformations that expose or increase usable parallelism.

Loops have historically been an important target for automatic parallelization, particularly in numerical programs with regular array accesses. Automatic parallelization is therefore closely related to automatic vectorization, loop transformation, and other compiler techniques for exploiting parallel hardware.

Overview

Consider a sequential loop in which corresponding elements of two arrays are added:

<span id="mwLg"></span><span class="k" id="mwLw">do </span><span class="n" id="mwMA">i</span><span class="w" id="mwMQ"> </span><span class="o" id="mwMg">=</span><span class="w" id="mwMw"> </span><span class="mi" id="mwNA">1</span><span class="p" id="mwNQ">,</span><span class="w" id="mwNg"> </span><span class="n" id="mwNw">n</span> <span class="w" id="mwOA"> </span><span class="n" id="mwOQ">z</span><span class="p" id="mwOg">(</span><span class="n" id="mwOw">i</span><span class="p" id="mwPA">)</span><span class="w" id="mwPQ"> </span><span class="o" id="mwPg">=</span><span class="w" id="mwPw"> </span><span class="n" id="mwQA">x</span><span class="p" id="mwQQ">(</span><span class="n" id="mwQg">i</span><span class="p" id="mwQw">)</span><span class="w" id="mwRA"> </span><span class="o" id="mwRQ">+</span><span class="w" id="mwRg"> </span><span class="n" id="mwRw">y</span><span class="p" id="mwSA">(</span><span class="n" id="mwSQ">i</span><span class="p" id="mwSg">)</span> <span class="k" id="mwSw">enddo</span>

Each iteration writes to a different element of z and, assuming the arrays do not overlap in a way that introduces a dependence, does not require the result of another iteration. The iterations can therefore potentially execute concurrently. A loop for which all iterations of a given invocation can execute concurrently is commonly called a DOALL loop.

By contrast:

<span id="mwVg"></span><span class="k" id="mwVw">do </span><span class="n" id="mwWA">i</span><span class="w" id="mwWQ"> </span><span class="o" id="mwWg">=</span><span class="w" id="mwWw"> </span><span class="mi" id="mwXA">2</span><span class="p" id="mwXQ">,</span><span class="w" id="mwXg"> </span><span class="n" id="mwXw">n</span> <span class="w" id="mwYA"> </span><span class="n" id="mwYQ">z</span><span class="p" id="mwYg">(</span><span class="n" id="mwYw">i</span><span class="p" id="mwZA">)</span><span class="w" id="mwZQ"> </span><span class="o" id="mwZg">=</span><span class="w" id="mwZw"> </span><span class="n" id="mwaA">z</span><span class="p" id="mwaQ">(</span><span class="n" id="mwag">i</span><span class="w" id="mwaw"> </span><span class="o" id="mwbA">-</span><span class="w" id="mwbQ"> </span><span class="mi" id="mwbg">1</span><span class="p" id="mwbw">)</span><span class="w" id="mwcA"> </span><span class="o" id="mwcQ">*</span><span class="w" id="mwcg"> </span><span class="mi" id="mwcw">2</span> <span class="k" id="mwdA">enddo</span>

contains a loop-carried dependence: iteration i reads a value produced by iteration i - 1. Executing the iterations simultaneously without an additional transformation would therefore change the program's behavior.

A parallelizing compiler consequently has to address two distinct questions:

  • Legality: can a transformation execute computations in parallel while preserving the semantics of the original program?
  • Profitability: if the transformation is legal, is parallel execution expected to improve performance?

The distinction is important because parallel execution has overhead. Work may need to be divided among threads, processors may need to synchronize or communicate, and memory-system effects can reduce the speedup obtained from concurrent execution. A transformation can therefore be legal without being profitable.

Some dependences can be modified or eliminated by program transformations. Automatic parallelization can therefore involve both detecting parallelism already present in a program and restructuring computations to expose additional parallelism.

Sign in to keep reading

6 more chapters are free with a Lably account.

More in Computing and communication