morsel’drive+parallelism:+a+ numa’aware+query+evaluation+...

16
MorselDrive Parallelism: A NUMAAware Query Evaluation Framework for the ManyCore Age Presented by Dennis Grishin

Upload: others

Post on 20-Aug-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Morsel-­‐Drive  Parallelism:  A  NUMA-­‐Aware  Query  Evaluation  

Framework  for  the  Many-­‐Core  AgePresented  by  Dennis  Grishin

Page 2: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

What  is  the  problem?

Efficient  computation  requires  distribution  of  processing  between  many  cores  and  associated  

memory.

Page 3: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Why  is  it  important?Rise  of  the  multi-­‐core  CPU  architecture

ABSTRACT

NUMA refers to the computer memory design choice available for multiprocessors. NUMA means that it will take longer to access some regions of memory than others. This work aims at explaining what NUMA is, the background developments, and how the memory access time depends on the memory location relative to a processor. First, we present a background of multiprocessor architectures, and some trends in hardware that exist along with NUMA. We, then briefly discuss the changes NUMA demands to be made in two key areas. One is in the policies the Operating System should implement for scheduling and run-time memory allocation scheme used for threads and the other is in the programming approach the programmers should take, in order to harness NUMA’s full potential. In the end we also present some numbers for comparing UMA vs. NUMA’s performance. Keywords: NUMA, Intel i7, NUMA Awareness, NUMA Distance

SECTIONS

In the following sections we first describe the background, hardware trends, Operating System’s goals, changes in programming paradigms, and then we conclude after giving some numbers for comparison.

Background

Hardware Goals / Performance Criteria There are 3 criteria on which performance of a multiprocessor system can be judged, viz. Scalability, Latency and Bandwidth. Scalability is the ability of a system to demonstrate a proportionate increase in parallel speedup with the addition of more processors. Latency is the time taken in sending a message from node A to node B, while bandwidth is the amount of data that can be communicated per unit of time. So, the goal of a multiprocessor system is to achieve a highly scalable, low latency, high bandwidth system. Parallel Architectures Typically, there are 2 major types of Parallel Architectures that are prevalent in the industry: Shared Memory Architecture and Distributed Memory Architecture. Shared Memory Architecture, again, is of 2 types: Uniform Memory Access (UMA), and Non-Uniform Memory Access (NUMA). Shared Memory Architecture As seen from the figure 1 (more details shown in “Hardware Trends” section) all processors share the same memory, and treat it as a global address space. The major challenge to overcome in such architecture is the issue of Cache Coherency (i.e. every read must

Figure 1 Shared Memory Architecture (from [1])

reflect the latest write). Such architecture is usually adapted in hardware model of general purpose CPU’s in laptops and desktops. Distributed Memory Architecture

In figure 2 (more details shown in “Hardware Trends” section) type of architecture, all the processors have their own local memory, and there is no mapping of memory addresses across processors. So, we don’t have any concept of global address space or cache coherency. To access data in another processor, processors use explicit communication. One example where this architecture is used with clusters, with different nodes connected over the internet as network. Shared Memory Architecture – UMA Shared Memory Architecture, again, is of 2 distinct types, Uniform Memory Access (UMA), and Non-Uniform Memory Access (NUMA).

Figure 2 Distributed Memory (from [1])

Figure 3 UMA Architecture Layout (from [3])

Non-Uniform Memory Access (NUMA) Nakul Manchanda and Karan Anand

New York University {nm1157, ka804} @cs.nyu.edu

ABSTRACT

NUMA refers to the computer memory design choice available for multiprocessors. NUMA means that it will take longer to access some regions of memory than others. This work aims at explaining what NUMA is, the background developments, and how the memory access time depends on the memory location relative to a processor. First, we present a background of multiprocessor architectures, and some trends in hardware that exist along with NUMA. We, then briefly discuss the changes NUMA demands to be made in two key areas. One is in the policies the Operating System should implement for scheduling and run-time memory allocation scheme used for threads and the other is in the programming approach the programmers should take, in order to harness NUMA’s full potential. In the end we also present some numbers for comparing UMA vs. NUMA’s performance. Keywords: NUMA, Intel i7, NUMA Awareness, NUMA Distance

SECTIONS

In the following sections we first describe the background, hardware trends, Operating System’s goals, changes in programming paradigms, and then we conclude after giving some numbers for comparison.

Background

Hardware Goals / Performance Criteria There are 3 criteria on which performance of a multiprocessor system can be judged, viz. Scalability, Latency and Bandwidth. Scalability is the ability of a system to demonstrate a proportionate increase in parallel speedup with the addition of more processors. Latency is the time taken in sending a message from node A to node B, while bandwidth is the amount of data that can be communicated per unit of time. So, the goal of a multiprocessor system is to achieve a highly scalable, low latency, high bandwidth system. Parallel Architectures Typically, there are 2 major types of Parallel Architectures that are prevalent in the industry: Shared Memory Architecture and Distributed Memory Architecture. Shared Memory Architecture, again, is of 2 types: Uniform Memory Access (UMA), and Non-Uniform Memory Access (NUMA). Shared Memory Architecture As seen from the figure 1 (more details shown in “Hardware Trends” section) all processors share the same memory, and treat it as a global address space. The major challenge to overcome in such architecture is the issue of Cache Coherency (i.e. every read must

Figure 1 Shared Memory Architecture (from [1])

reflect the latest write). Such architecture is usually adapted in hardware model of general purpose CPU’s in laptops and desktops. Distributed Memory Architecture

In figure 2 (more details shown in “Hardware Trends” section) type of architecture, all the processors have their own local memory, and there is no mapping of memory addresses across processors. So, we don’t have any concept of global address space or cache coherency. To access data in another processor, processors use explicit communication. One example where this architecture is used with clusters, with different nodes connected over the internet as network. Shared Memory Architecture – UMA Shared Memory Architecture, again, is of 2 distinct types, Uniform Memory Access (UMA), and Non-Uniform Memory Access (NUMA).

Figure 2 Distributed Memory (from [1])

Figure 3 UMA Architecture Layout (from [3])

Non-Uniform Memory Access (NUMA) Nakul Manchanda and Karan Anand

New York University {nm1157, ka804} @cs.nyu.edu

Uniform  Memory  Access  (UMA)

Non-­‐Uniform  Memory  Access  (NUMA)

Rise  of  the  NUMA  architecture

Page 4: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Why  is  it  hard?

How  to  distribute  work  evenly  between  many  out-­‐of-­‐order  cores?

How  to  maximize  NUMA-­‐local  execution?

Page 5: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Why  existing  solutions  do  not  work?

Plan-­‐driven parallelism:  query  fragmentation  at  compile  time into  big  fragments  and  initiation  of  

static  number  of  threads

Insufficient  load-­‐balancing  due  hard-­‐to-­‐predict  performance  of  out-­‐of-­‐order  CPUs.

Page 6: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

What  is  the  core  intuition  of  the  solution?

Morsel-­‐driven parallelism:  query  fragmentation  at  runtime into  small  fragments and  dynamic  

scheduling  of  threads

Runtime  scheduling  is  elastic  and  achieves  perfect  load-­‐balancing.

Page 7: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Solution  I  – three-­‐way  join

Morsel-Driven Parallelism: A NUMA-Aware QueryEvaluation Framework for the Many-Core Age

Viktor Leis⇤ Peter Boncz† Alfons Kemper⇤ Thomas Neumann⇤

⇤ Technische Universität München † CWI⇤ {leis,kemper,neumann}@in.tum.de † [email protected]

ABSTRACTWith modern computer architecture evolving, two problems con-spire against the state-of-the-art approaches in parallel query exe-cution: (i) to take advantage of many-cores, all query work mustbe distributed evenly among (soon) hundreds of threads in order toachieve good speedup, yet (ii) dividing the work evenly is difficulteven with accurate data statistics due to the complexity of modernout-of-order cores. As a result, the existing approaches for “plan-driven” parallelism run into load balancing and context-switchingbottlenecks, and therefore no longer scale. A third problem facedby many-core architectures is the decentralization of memory con-trollers, which leads to Non-Uniform Memory Access (NUMA).

In response, we present the “morsel-driven” query executionframework, where scheduling becomes a fine-grained run-time taskthat is NUMA-aware. Morsel-driven query processing takes smallfragments of input data (“morsels”) and schedules these to workerthreads that run entire operator pipelines until the next pipelinebreaker. The degree of parallelism is not baked into the plan but canelastically change during query execution, so the dispatcher can re-act to execution speed of different morsels but also adjust resourcesdynamically in response to newly arriving queries in the workload.Further, the dispatcher is aware of data locality of the NUMA-localmorsels and operator state, such that the great majority of execu-tions takes place on NUMA-local memory. Our evaluation on theTPC-H and SSB benchmarks shows extremely high absolute per-formance and an average speedup of over 30 with 32 cores.

Categories and Subject DescriptorsH.2.4 [Systems]: Query processing

KeywordsMorsel-driven parallelism; NUMA-awareness

1. INTRODUCTIONThe main impetus of hardware performance improvement nowa-

days comes from increasing multi-core parallelism rather than fromspeeding up single-threaded performance [2]. By SIGMOD 2014

Permission to make digital or hard copies of part or all of this work for personal orclassroom use is granted without fee provided that copies are not made or distributedfor profit or commercial advantage, and that copies bear this notice and the full ci-tation on the first page. Copyrights for third-party components of this work must behonored. For all other uses, contact the owner/author(s). Copyright is held by theauthor/owner(s).SIGMOD’14, June 22–27, 2014, Snowbird, UT, USA.ACM 978-1-4503-2376-5/14/06.http://dx.doi.org/10.1145/2588555.2610507 .

A16

1827

5

7

B8

3310

5

23

B83310

5

23

Cvxy

z

u

HT(S)HT(T)

A167102718575...............

Zacibejdf...............

RZa......

A16......

B8......

Cv......

Result

storeprobe(16)probe(10)

probe(8)

probe(27)store

Zb......

A27......

B10......

Cy......

morsel

morselDispatcher

Figure 1: Idea of morsel-driven parallelism: R 1A S 1B T

Intel’s forthcoming mainstream server Ivy Bridge EX, which canrun 120 concurrent threads, will be available. We use the termmany-core for such architectures with tens or hundreds of cores.

At the same time, increasing main memory capacities of up toseveral TB per server have led to the development of main-memorydatabase systems. In these systems query processing is no longerI/O bound, and the huge parallel compute resources of many-corescan be truly exploited. Unfortunately, the trend to move memorycontrollers into the chip and hence the decentralization of mem-ory access, which was needed to scale throughput to huge mem-ories, leads to non-uniform memory access (NUMA). In essence,the computer has become a network in itself as the access costs ofdata items varies depending on which chip the data and the access-ing thread are located. Therefore, many-core parallelization needsto take RAM and cache hierarchies into account. In particular, theNUMA division of the RAM has to be considered carefully to en-sure that threads work (mostly) on NUMA-local data.

Abundant research in the 1990s into parallel processing led themajority of database systems to adopt a form of parallelism in-spired by the Volcano [12] model, where operators are kept largelyunaware of parallelism. Parallelism is encapsulated by so-called“exchange” operators that route tuple streams between multiplethreads each executing identical pipelined segments of the queryplan. Such implementations of the Volcano model can be calledplan-driven: the optimizer statically determines at query compile-time how many threads should run, instantiates one query operatorplan for each thread, and connects these with exchange operators.

In this paper we present the adaptive morsel-driven query execu-tion framework, which we designed for our main-memory databasesystem HyPer [16]. Our approach is sketched in Figure 1 for thethree-way-join query R 1A S 1B T . Parallelism is achieved

select  *  from  R,  S,  T  where  R.A  =  S.A  and  S.B  =  T.B  

Page 8: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Solution  II  – build-­‐phaseFigure 2: Parallellizing the three pipelines of the sample query plan: (left) algebraic evaluation plan; (right) three- respectivelyfour-way parallel processing of each pipeline

HT(T)global

Hash Table

morsel

T

Phas

e 1:

pro

cess

T m

orse

l-wise

and

stor

e N

UM

A-lo

cally

Phas

e 2:

scan

NU

MA-

loca

l sto

rage

are

a an

d in

sert

poi

nter

s int

o HT

next

mor

sel

Storage area of

red core

Storage area of

green core

Storage area of

blue corescan

scan

Insert the pointer

into HT

...(T)v ...(T)v...(T)v

Figure 3: NUMA-aware processing of the build-phase

morsels; this way the succeeding pipelines start with new homoge-neously sized morsels instead of retaining morsel boundaries acrosspipelines which could easily result in skewed morsel sizes. Thenumber of parallel threads working on any pipeline at any time isbounded by the number of hardware threads of the processor. Inorder to write NUMA-locally and to avoid synchronization whilewriting intermediate results the QEPobject allocates a storage areafor each such thread/core for each executable pipeline.

The parallel processing of the pipeline for filtering T and build-ing the hash table HT (T ) is shown in Figure 3. Let us concentrateon the processing of the first phase of the pipeline that filters in-put T and stores the “surviving” tuples in temporary storage areas.

In our figure three parallel threads are shown, each of which op-erates on one morsel at a time. As our base relation T is stored“morsel-wise” across a NUMA-organized memory, the schedulerassigns, whenever possible, a morsel located on the same socketwhere the thread is executed. This is indicated by the coloring inthe figure: The red thread that runs on a core of the red socket isassigned the task to process a red-colored morsel, i.e., a small frag-ment of the base relation T that is located on the red socket. Once,the thread has finished processing the assigned morsel it can eitherbe delegated (dispatched) to a different task or it obtains anothermorsel (of the same color) as its next task. As the threads pro-cess one morsel at a time the system is fully elastic. The degree ofparallelism (MPL) can be reduced or increased at any point (moreprecisely, at morsel boundaries) while processing a query.

The logical algebraic pipeline of (1) scanning/filtering the inputT and (2) building the hash table is actually broken up into twophysical processing pipelines marked as phases on the left-handside of the figure. In the first phase the filtered tuples are insertedinto NUMA-local storage areas, i.e., for each core there is a sep-arate storage area in order to avoid synchronization. To preserveNUMA-locality in further processing stages, the storage area of aparticular core is locally allocated on the same socket.

After all base table morsels have been scanned and filtered, in thesecond phase these storage areas are scanned – again by threads lo-cated on the corresponding cores – and pointers are inserted intothe hash table. Segmenting the logical hash table building pipelineinto two phases enables perfect sizing of the global hash table be-cause after the first phase is complete, the exact number of “surviv-ing” objects is known. This (perfectly sized) global hash table willbe probed by threads located on various sockets of a NUMA sys-tem; thus, to avoid contention, it should not reside in a particularNUMA-area and is therefore is interleaved (spread) across all sock-ets. As many parallel threads compete to insert data into this hashtable, a lock-free implementation is essential. The implementationdetails of the hash table are described in Section 4.2.

After both hash tables have been constructed, the probing pipelinecan be scheduled. The detailed processing of the probe pipeline isshown in Figure 4. Again, a thread requests work from the dis-patcher which assigns a morsel in the corresponding NUMA parti-tion. That is, a thread located on a core in the red NUMA partitionis assigned a morsel of the base relation R that is located on the cor-

NUMA-­‐aware  hash  table  creation

• Table  partitioning   on  the  join  key  -­‐>  matching  tuples  usually  on   the  same  socket  -­‐>  less  cross-­‐socket  communication   for  joins

worst case a too large morsel size results in underutilized threadsbut does not affect throughput of the system if enough concurrentqueries are being executed.

4. PARALLEL OPERATOR DETAILSIn order to be able to completely parallelize each pipeline, each

operator must be capable to accept tuples in parallel (e.g., by syn-chronizing shared data structures) and, for operators that start a newpipeline, to produce tuples in parallel. In this section we discuss theimplementation of the most important parallel operators.

4.1 Hash JoinAs discussed in Section 2 and shown in Figure 3, the hash table

construction of our hash join consists of two phases. In the firstphase, the build input tuples are materialized into a thread-localstorage area2; this requires no synchronization. Once all input tu-ples have been consumed that way, an empty hash table is createdwith the perfect size, because the input size is now known pre-cisely. This is much more efficient than dynamically growing hashtables, which incur a high overhead in a parallel setting. In the sec-ond phase of the parallel build phase each thread scans its storagearea and inserts pointers to its tuples using the atomic compare-and-swap instruction. The details are explained in Section 4.2.

Outer join is a minor variation of the described algorithm. Ineach tuple a marker is additionally allocated that indicates if thistuple had a match. In the probe phase the marker is set indicatingthat a match occurred. Before setting the marker it is advantageousto first check that the marker is not yet set, to avoid unnecessarycontention. Semi and anti joins are implemented similarly.

Using a number of single-operation benchmarks, Balkesen et al.showed that a highly-optimized radix join can achieve higher per-formance than a single-table join [5]. However, in comparison withradix join our single-table hash join

• is fully pipelined for the larger input relation, thus uses lessspace as the probe input can be processed in place,

• is a “good team player” meaning that multiple small (dimen-sion) tables can be joined as a team by a probe pipeline ofthe large (fact) table through all these dimension hash tables,

• is very efficient if the two input cardinalities differ strongly,as is very often the case in practice,

• can benefit from skewed key distributions3 [7],• is insensitive to tuple size, and• has no hardware-specific parameters.

Because of these practical advantages, a single-table hash join isoften preferable to radix join in complex query processing. For ex-ample, in the TPC-H benchmark, 97.4% of all joined tuples arriveat the probe side, and therefore the hash table often fits into cache.This effect is even more pronounced with the Star Schema Bench-mark where 99.5% of the joined tuples arrive at the probe side.Therefore, we concentrated on a single-table hash join which hasthe advantage of having no hardware-specific parameters and notrelying on query optimizer estimates while providing very good (ifthe table fits into cache) or at least decent (if the table is larger thancache) performance. We left the radix join implementation, whichis beneficial in some scenarios due to higher locality, for future en-hancement of our query engine.2We also reserve space for a next pointer within each tuple for han-dling hash collisions.3One example that occurs in TPC-H is positional skew, i.e., in a1:n join all join partners occur in close proximity which improvescache locality.

d00000100

e10000010

f

hashTable 16 bit tag for early filtering

48 bit pointer

1 insert(entry) {

2 // determine slot in hash table

3 slot = entry->hash >> hashTableShift

4 do {

5 old = hashTable[slot]

6 // set next to old entry without tag

7 entry->next = removeTag(old)

8 // add old and new tag

9 new = entry | (old&tagMask) | tag(entry->hash)

10 // try to set new value, repeat on failure

11 } while (!CAS(hashTable[slot], old, new))

12 }

Figure 7: Lock-free insertion into tagged hash table

4.2 Lock-Free Tagged Hash TableThe hash table that we use for the hash join operator has an

early-filtering optimization, which improves performance of selec-tive joins, which are quite common. The key idea is to tag a hashbucket list with a small filter into which all elements of that partic-ular list are “hashed” to set their 1-bit. For selective probes, i.e.,probes that would not find a match by traversing the list, the filterusually reduces the number of cache misses to 1 by skipping thelist traversal after checking the tag. As shown in Figure 7 (top), weencode a tag directly into 16 bits of each pointer in the hash table.This saves space and, more importantly, allows to update both thepointer and the tag using a single atomic compare-and-swap oper-ation.

For low-cost synchronization we exploit the fact that in a join thehash table is insert-only and lookups occur only after all inserts arecompleted. Figure 7 (bottom) shows the pseudo code for inserting anew entry into the hash table. In line 11, the pointer to the new ele-ment (e.g, “f” in the picture) is set using compare-and-swap (CAS).This pointer is augmented by the new tag, which is computed fromthe old and the new tag (line 9). If the CAS failed (because anotherinsert occurred simultaneously), the process is repeated.

Our tagging technique has a number of advantages in compari-son to Bloom filters, which can be used similarly and are, for ex-ample, used in Vectorwise [8], SQL Server [21], and BLU [31].First, a Bloom filter is an additional data structure that incurs mul-tiple reads. And for large tables, the Bloom filter may not fit intocache (or only relatively slow last-level cache), as the Bloom fil-ter size must be proportional to the hash table size to be effective.Therefore, the overhead can be quite high, although Bloom filterscan certainly be a very good optimization due to their small size.In our approach no unnecessary memory accesses are performed,only a small number of cheap bitwise operations. Therefore, hashtagging has very low overhead and can always be used, without re-lying on the query optimizer to estimate selectivities. Besides join,tagging is also very beneficial during aggregation when most keysare unique.

The hash table array only stores pointers, and not the tuplesthemselves, i.e., we do not use open addressing. There are a num-ber of reasons for this: Since the tuples are usually much larger thanpointers, the hash table can be sized quite generously to at leasttwice the size of the input. This reduces the number of collisions

• Tagging  of  hash  bucket  lists  reduces  -­‐>  list  traversal  skipped   -­‐>  number  of  cash  misses  reduced  to  1

Page 9: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Solution  III  – probe-­‐phase

morsel

R

Storage area of

red core

HT(T) HT(S)

Storage area of

green core

Storage area of

blue core

next

mor

sel

...(R)v ...(R)v...(R)v

Figure 4: Morsel-wise processing of the probe phase

responding “red” NUMA socket. The result of the probe pipelineis again stored in NUMA local storage areas in order to preserveNUMA locality for further processing (not present in our samplequery plan).

In all, morsel-driven parallelism executes multiple pipelines inparallel, which is similar to typical implementations of the Vol-cano model. Different from Volcano, however, is the fact thatthe pipelines are not independent. That is, they share data struc-tures and the operators are aware of parallel execution and mustperform synchronization (through efficient lock-free mechanisms– see later). A further difference is that the number of threads exe-cuting the plan is fully elastic. That is, the number may differ notonly between different pipeline segments, as shown in Figure 2, butalso inside the same pipeline segment during query execution – asdescribed in the following.

3. DISPATCHER: SCHEDULING PARALLELPIPELINE TASKS

The dispatcher is controlling and assigning the compute re-sources to the parallel pipelines. This is done by assigning tasks toworker threads. We (pre-)create one worker thread for each hard-ware thread that the machine provides and permanently bind eachworker to it. Thus, the level of parallelism of a particular query isnot controlled by creating or terminating threads, but rather by as-signing them particular tasks of possibly different queries. A taskthat is assigned to such a worker thread consists of a pipeline joband a particular morsel on which the pipeline has to be executed.Preemption of a task occurs at morsel boundaries – thereby elimi-nating potentially costly interrupt mechanisms. We experimentallydetermined that a morsel size of about 100,000 tuples yields goodtradeoff between instant elasticity adjustment, load balancing andlow maintenance overhead.

There are three main goals for assigning tasks to threads that runon particular cores:

1. Preserving (NUMA-)locality by assigning data morsels tocores on which the morsels are allocated

2. Full elasticity concerning the level of parallelism of a partic-ular query

Figure 5: Dispatcher assigns pipeline-jobs on morsels tothreads depending on the core

3. Load balancing requires that all cores participating in a querypipeline finish their work at the same time in order to prevent(fast) cores from waiting for other (slow) cores1.

In Figure 5 the architecture of the dispatcher is sketched. Itmaintains a list of pending pipeline jobs. This list only containspipeline jobs whose prerequisites have already been processed. E.g.,for our running example query the build input pipelines are firstinserted into the list of pending jobs. The probe pipeline is onlyinserted after these two build pipelines have been finished. As de-scribed before, each of the active queries is controlled by a QEPob-ject which is responsible for transferring executable pipelines tothe dispatcher. Thus, the dispatcher maintains only lists of pipelinejobs for which all dependent pipelines were already processed. Ingeneral, the dispatcher queue will contain pending pipeline jobsof different queries that are executed in parallel to accommodateinter-query parallelism.

3.1 ElasticityThe fully elastic parallelism, which is achieved by dispatching

jobs “a morsel at a time”, allows for intelligent scheduling of theseinter-query parallel pipeline jobs depending on a quality of servicemodel. It enables to gracefully decrease the degree of parallelismof, say a long-running query Ql at any stage of processing in orderto prioritize a possibly more important interactive query Q+. Oncethe higher prioritized query Q+ is finished, the pendulum swingsback to the long running query by dispatching all or most cores totasks of the long running query Ql. In Section 5.4 we demonstratethis dynamic elasticity experimentally. In our current implemen-tation all queries have the same priority, so threads are distributed1This assumes that the goal is to minimize the response time of aparticular query. Of course, an idle thread could start working onanother query otherwise.

Morsel-­‐wise  probing

Page 10: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Solution  III  -­‐ dispatcher

Figure 4: Morsel-wise processing of the probe phase

responding “red” NUMA socket. The result of the probe pipelineis again stored in NUMA local storage areas in order to preserveNUMA locality for further processing (not present in our samplequery plan).

In all, morsel-driven parallelism executes multiple pipelines inparallel, which is similar to typical implementations of the Vol-cano model. Different from Volcano, however, is the fact thatthe pipelines are not independent. That is, they share data struc-tures and the operators are aware of parallel execution and mustperform synchronization (through efficient lock-free mechanisms– see later). A further difference is that the number of threads exe-cuting the plan is fully elastic. That is, the number may differ notonly between different pipeline segments, as shown in Figure 2, butalso inside the same pipeline segment during query execution – asdescribed in the following.

3. DISPATCHER: SCHEDULING PARALLELPIPELINE TASKS

The dispatcher is controlling and assigning the compute re-sources to the parallel pipelines. This is done by assigning tasks toworker threads. We (pre-)create one worker thread for each hard-ware thread that the machine provides and permanently bind eachworker to it. Thus, the level of parallelism of a particular query isnot controlled by creating or terminating threads, but rather by as-signing them particular tasks of possibly different queries. A taskthat is assigned to such a worker thread consists of a pipeline joband a particular morsel on which the pipeline has to be executed.Preemption of a task occurs at morsel boundaries – thereby elimi-nating potentially costly interrupt mechanisms. We experimentallydetermined that a morsel size of about 100,000 tuples yields goodtradeoff between instant elasticity adjustment, load balancing andlow maintenance overhead.

There are three main goals for assigning tasks to threads that runon particular cores:

1. Preserving (NUMA-)locality by assigning data morsels tocores on which the morsels are allocated

2. Full elasticity concerning the level of parallelism of a partic-ular query

DispatcherCode

disp

atch

(0)

(J 1, M

r1)

Pipe

line-

Job

J 1 on

mor

sel M

r1

on

(red

) soc

ket o

f Cor

e0

Pipeline-JobJ1

Pipeline-JobJ2

Mr1

Mr2

Mr3

Mg1

Mg2

Mg3

Mb1

Mb2

Mb3

(virtual) lists of morsels to be processed(colors indicates on what socket/core

the morsel is located)

Lock-free Data Structures of DispatcherList of pending pipeline-jobs

(possibly belonging to different queries)

Core0 Core Core CoreCore Core Core CoreDR

AM

Core8 Core Core CoreCore Core Core CoreDR

AM

Core Core Core CoreCore Core Core Core DR

AM

Core Core Core CoreCore Core Core Core DR

AM

Socket Socket

inter connect

SocketSocket

Example NUMA Multi-Core Server with 4 Sockets and 32 Cores

Figure 5: Dispatcher assigns pipeline-jobs on morsels tothreads depending on the core

3. Load balancing requires that all cores participating in a querypipeline finish their work at the same time in order to prevent(fast) cores from waiting for other (slow) cores1.

In Figure 5 the architecture of the dispatcher is sketched. Itmaintains a list of pending pipeline jobs. This list only containspipeline jobs whose prerequisites have already been processed. E.g.,for our running example query the build input pipelines are firstinserted into the list of pending jobs. The probe pipeline is onlyinserted after these two build pipelines have been finished. As de-scribed before, each of the active queries is controlled by a QEPob-ject which is responsible for transferring executable pipelines tothe dispatcher. Thus, the dispatcher maintains only lists of pipelinejobs for which all dependent pipelines were already processed. Ingeneral, the dispatcher queue will contain pending pipeline jobsof different queries that are executed in parallel to accommodateinter-query parallelism.

3.1 ElasticityThe fully elastic parallelism, which is achieved by dispatching

jobs “a morsel at a time”, allows for intelligent scheduling of theseinter-query parallel pipeline jobs depending on a quality of servicemodel. It enables to gracefully decrease the degree of parallelismof, say a long-running query Ql at any stage of processing in orderto prioritize a possibly more important interactive query Q+. Oncethe higher prioritized query Q+ is finished, the pendulum swingsback to the long running query by dispatching all or most cores totasks of the long running query Ql. In Section 5.4 we demonstratethis dynamic elasticity experimentally. In our current implemen-tation all queries have the same priority, so threads are distributed1This assumes that the goal is to minimize the response time of aparticular query. Of course, an idle thread could start working onanother query otherwise.

• Dispatcher  implemented  as  a  lock  free data  structure  and  executed  by  work  requesting  threads

• Maintains  a  list  of  pending  pipeline   jobs  whose  prerequisites  have  already  been  processed

• Segmentation  of  queries  upon  request  by  processing   thread

• NUMA-­‐locality awareness

• ”Work  stealing”  if  necessary

Page 11: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Solution  IV  – morsel  size

equally over all active queries. A priority-based scheduling com-ponent is under development but beyond the scope of this paper.

For each pipeline job the dispatcher maintains lists of pendingmorsels on which the pipeline job has still to be executed. For eachcore a separate list exists to ensure that a work request of, say, Core0 returns a morsel that is allocated on the same socket as Core 0.This is indicated by different colors in our architectural sketch. Assoon as Core 0 finishes processing the assigned morsel, it requestsa new task, which may or may not stem from the same pipeline job.This depends on the prioritization of the different pipeline jobs thatoriginate from different queries being executed. If a high-priorityquery enters the system it may lead to a decreased parallelism de-gree for the current query. Morsel-wise processing allows to re-assign cores to different pipeline jobs without any drastic interruptmechanism.

3.2 Implementation OverviewFor illustration purposes we showed a (long) linked list of morsels

for each core in Figure 5. In reality (i.e., in our implementation) wemaintain storage area boundaries for each core/socket and segmentthese large storage areas into morsels on demand; that is, whena core requests a task from the dispatcher the next morsel of thepipeline argument’s storage area on the particular socket is “cutout”. Furthermore, in Figure 5 the Dispatcher appears like a sep-arate thread. This, however, would incur two disadvantages: (1)the dispatcher itself would need a core to run on or might pre-empt query evaluation threads and (2) it could become a sourceof contention, in particular if the morsel size was configured quitesmall. Therefore, the dispatcher is implemented as a lock-free datastructure only. The dispatcher’s code is then executed by the work-requesting query evaluation thread itself. Thus, the dispatcher is au-tomatically executed on the (otherwise unused) core of this workerthread. Relying on lock-free data structures (i.e., the pipeline jobqueue as well as the associated morsel queues) reduces contentioneven if multiple query evaluation threads request new tasks at thesame time. Analogously, the QEPobject that triggers the progressof a particular query by observing data dependencies (e.g., build-ing hash tables before executing the probe pipeline) is implementedas a passive state machine. The code is invoked by the dispatcherwhenever a pipeline job is fully executed as observed by not beingable to find a new morsel upon a work request. Again, this statemachine is executed on the otherwise unused core of the workerthread that originally requested a new task from the dispatcher.

Besides the ability to assign a core to a different query at anytime – called elasticity – the morsel-wise processing also guaran-tees load balancing and skew resistance. All threads working on thesame pipeline job run to completion in a “photo finish”: they areguaranteed to reach the finish line within the time period it takesto process a single morsel. If, for some reason, a core finishesprocessing all morsels on its particular socket, the dispatcher will“steal work” from another core, i.e., it will assign morsels on a dif-ferent socket. On some NUMA systems, not all sockets are directlyconnected with each other; here it pays off to steal from closer sock-ets first. Under normal circumstances, work-stealing from remotesockets happens very infrequently; nevertheless it is necessary toavoid idle threads. And the writing into temporary storage will bedone into NUMA local storage areas anyway (that is, a red morselturns blue if it was processed by a blue core in the process of steal-ing work from the core(s) on the red socket).

So far, we have discussed intra-pipeline parallelism. Our par-allelization scheme can also support bushy parallelism, e.g., thepipelines “filtering and building the hash table of T ” and “filteringand building the hash table of S” of our example are independent

0.0

0.2

0.4

0.6

0.8

100 1K 10K 100K 1M 10Mmorsel size

time

[s]

Figure 6: Effect of morsel size on query execution

and could therefore be executed in parallel. However, the useful-ness of this form of parallelism is limited. The number of indepen-dent pipelines is usually much smaller than the number of cores,and the amount of work in each pipeline generally differs. Fur-thermore, bushy parallelism can decrease performance by reducingcache locality. Therefore, we currently avoid to execute multiplepipelines from one query in parallel; in our example, we first exe-cute pipeline T , and only after T is finished, the job for pipeline Sis added to the list of pipeline jobs.

Besides elasticity, morsel-driven processing also allows for asimple and elegant implementation of query canceling. A user mayhave aborted her query request, an exception happened in a query(e.g., a numeric overflow), or the system is running out of RAM.If any of these events happen, the involved query is marked in thedispatcher. The marker is checked whenever a morsel of that queryis finished, therefore, very soon all worker threads will stop work-ing on this query. In contrast to forcing the operating system tokill threads, this approach allows each thread to clean up (e.g., freeallocated memory).

3.3 Morsel SizeIn contrast to systems like Vectorwise [9] and IBM’s BLU [31],

which use vectors/strides to pass data between operators, there is noperformance penalty if a morsel does not fit into cache. Morsels areused to break a large task into small, constant-sized work units tofacilitate work-stealing and preemption. Consequently, the morselsize is not very critical for performance, it only needs to be largeenough to amortize scheduling overhead while providing good re-sponse times. To show the effect of morsel size on query per-formance we measured the performance for the query select

min(a) from R using 64 threads on a Nehalem EX system,which is described in Section 5. This query is very simple, so itstresses the work-stealing data structure as much as possible. Fig-ure 6 shows that the morsel size should be set to the smallest pos-sible value where the overhead is negligible, in this case to a valueabove 10,000. The optimal setting depends on the hardware, butcan easily be determined experimentally.

On many-core systems, any shared data structure, even if lock-free, can eventually become a bottleneck. In the case of our work-stealing data structure, however, there are a number of aspects thatprevent it from becoming a scalability problem. First, in our imple-mentation the total work is initially split between all threads, suchthat each thread temporarily owns a local range. Because we cacheline align each range, conflicts at the cache line level are unlikely.Only when this local range is exhausted, a thread tries to steal workfrom another range. Second, if more than one query is executedconcurrently, the pressure on the data structure is further reduced.Finally, it is always possible to increase the morsel size. This re-sults in fewer accesses to the work-stealing data structure. In the

• Morsels  should  be  large  enough   to  amortize  scheduling   overhead  while  providing   a  good  response   time

Execution  time  dependency  on  morsel  size

Page 12: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Experiment  results  I  -­‐ speedupProcessing  of  22  TPC-­‐H  queries

Page 13: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Experiment  results  II  -­‐ elasticityIntra-­‐ and  inter-­‐query  parallelism

Morsel-­‐wise  processing

Page 14: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Does  the  paper  prove  its  claims?

Yes.

Page 15: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Are  there  any  gaps  in  the  logic?

• Can  the  compilation  at  runtime  cause  a  significant  overhead?

• What  is  the  overhead  caused  by  the  dispatcher  in  morsel-­‐driven  parallelism?

• Can  all  types  of  queries  be  easily  broken  into  morsels?

Page 16: Morsel’Drive+Parallelism:+A+ NUMA’Aware+Query+Evaluation+ ...daslab.seas.harvard.edu/classes/cs265/files/... · memory location relative to a processor. First, we present a background

Possible  next  steps?

• Priority  based  scheduling.

• Hardware  specific  optimization.

• Real  world  testing.