174 Introduction to High Performance Computing for Scientists and Engineers
OpenMP loop startup overhead becomes negligible. The performance baseline with
t threads, P
s
(t), is then measured with static scheduling without a chunksize, in units
of million iterations per second (see the dotted line in Figure 7.4 for two threads on
two cores of the Xeon 5160 dual-core dual-socket node depicted in Figure 7.2). This
baseline does not depend on the binding of the threads to cores (inside cache groups,
across ccNUMA domains, etc.) because each thread executes only a single chunk,
and any OpenMP overhead occurs only at the start and at the end of the worksharing
construct. At large N, the static baseline should thus be t times larger than the purely
serial performance.
Whenever a chunksize is used with anyscheduling variant, assigning a new chunk
to a thread will take some time, which counts as overhead. The main panel in Fig-
ure 7.4 shows performance data for static (circles), dynamic (squares), and guided
(diamonds) scheduling when the threads run in an L2 cache group (closed sym-
bols) or on different sockets (open symbols), respectively. As expected, the over-
head is largest for small chunks, and dominant only for dynamic scheduling. Guided
scheduling performs best because larger chunks are assigned at the beginning of the
loop, and the indicated chunksize is just a lower bound (see Figure 6.2). The dif-
ference between intersocket and intra-L2 situations is only significant with dynamic
scheduling, because some common resource is required to arbitrate work distribu-
tion. If this resource can be kept in a shared cache, chunk assignment will be much
faster. It will also be faster with guided scheduling, but due to the large average
chunksize, the effect is unnoticeable.
If P(t,c) is the t-thread performance at chunksize c, the difference in per-iteration
per-thread execution times between the static baseline and the “chunked” version is
the per-iteration overhead. Per complete chunk, this is
T
o
(t,c) =
t
c
1
P(t,c)
−
1
P
s
(t)
. (7.2)
The inset in Figure 7.4 shows that the overhead in CPU cycles is roughly independent
of chunksize, at least for chunks larger than 4. Assigning a new chunk to a thread
costs over 200 cycles if both threads run inside an L2 group, and 350 cycles when
running on different sockets (these times include the 50 cycle penalty per chunk for
static scheduling). Again we encounter a situation where mutual thread placement,
or affinity, is decisive.
Please note that, although the general methodology is applicable to all shared-
memory systems, the results of this analysis depend on hardware properties and the
actual implementation of OpenMP worksharing done by the compiler. The actual
numbers may differ significantly on other platforms.
Other factors not recognized by this benchmark can impact the performance of
dynamically scheduled worksharing constructs. In memory-bound loop code, pre-
fetching may be inefficient or impossible if the chunksize is small. Moreover, due to
the indeterministic nature of memory accesses, ccNUMA locality could be hard to
maintain, which pertains to guided scheduling as well. See Section 8.3.1 for details
on this problem.