GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry...

10
GLOpenCL: OpenCL Support on Hardware- and Software-Managed Cache Multicores Konstantis Daloukas Department of Computer and Communications Engineering University of Thessaly Volos, Greece [email protected] Christos D. Antonopoulos Department of Computer and Communications Engineering University of Thessaly Volos, Greece [email protected] Nikolaos Bellas Department of Computer and Communications Engineering University of Thessaly Volos, Greece [email protected] ABSTRACT OpenCL is an industry supported standard for writing pro- grams that execute on multicore platforms as well as on accelerators, such as GPUs or the SPEs of the Cell B.E. In this paper we introduce GLOpenCL, a unified develop- ment framework which supports OpenCL on both homo- geneous, shared memory, as well as on heterogeneous, dis- tributed memory multicores. The framework consists of a compiler, based on the LLVM compiler infrastructure, and a run-time library, sharing the same basic architecture across all target platforms. The compiler recognizes OpenCL con- structs, performs source-to-source code transformations tar- geting both efficiency and semantic correctness, and adds calls to the run-time library. The latter offers functional- ity for work creation, management and execution, as well as for data transfers. We evaluate our framework using benchmarks from the distributions of OpenCL implementa- tions by hardware vendors. We find that our generic system performs comparably or better than customized, platform- specific vendor distributions. OpenCL is designed and mar- keted as a write-once run-anywhere software development framework. However, the standard leaves enough room for target platform specific optimizations. Our experimenta- tion with different, customized implementations of kernels reveals that optimized, hardware mapped implementations are both possible and necessary in the context of OpenCL – especially on non-conventional multicores – if performance is considered a higher priority than programmability. Categories and Subject Descriptors D.1.3 [Programming Techniques]: Concurrent Program- ming—Parallel Programming ; D.3.4 [PROGRAMMING LANGUAGES]: Processors—Code generation, Compilers, Optimization, Run-time environments General Terms Design, Experimentation, Languages, Measurement, Perfor- Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. HiPEAC 2011 Heraklion, Crete, Greece Copyright 2011 ACM 978-1-4503-0241-8/11/01 ...$10.00. mance Keywords OpenCL, Compilers, Runtime, Hardware-managed cache mul- ticores, Software-managed cache multicores 1. INTRODUCTION During the last few years, we have witnessed a paradigm shift towards parallel computing. Technology advances have enabled the integration of multiple cores in a single die, thus enabling the development of a plethora of computation sub- strates for parallel, high performance, computing. Architec- tures such as homogeneous or heterogeneous multicores and manycores, and, more recently, GPUs have allowed the time- and power-efficient execution of computationally intensive applications at a minimum expense. However, applications need to be rewritten in order to expose their inherent paral- lelism and exploit capabilities of multicore and accelerator- based architectures. Developing parallel programs is a far more complex undertaking than sequential programming, as the programmer is responsible for coping with hurdles such as race conditions, synchronization issues, communication, work management and scheduling, as well as with the pecu- liarities of each parallel architecture. In order to enable the efficient development of applica- tions, a multitude of programming models have been pro- posed, with the purpose of relieving the programmer from the duty of handling – at least some of – these issues thus allowing her to focus on algorithmic issues rather than tech- nicalities. These models include PThreads [15], OpenMP [20], UPC [24] or Cilk [4] for homogeneous and heteroge- neous multicores, the Cell SDK [10] and CellSs [21] for the Cell B.E., as well as CUDA [18] and the AMD/ATI Stream SDK [2] that target GPUs. None of the aforementioned models targets both homoge- neous and heterogeneous multicores, as well as accelerator- based systems at the same time, mainly due to their vast architectural differences. For example, applications that tar- get the Cell B.E. are mainly developed using the IBM SDK, thus making their porting to other architectures a tedious task. There is, thus, strong demand for a programming model that enables application development without prior knowledge of the computing substrate where the applica- tion will be executed. Such a programming model would en- hance portability, provided that it would allow applications to be transferred and efficiently executed on different archi- tectures without requiring rewriting or widespread modifica-

Transcript of GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry...

Page 1: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

GLOpenCL: OpenCL Support on Hardware- andSoftware-Managed Cache Multicores

Konstantis DaloukasDepartment of Computer andCommunications Engineering

University of ThessalyVolos, Greece

[email protected]

Christos D. AntonopoulosDepartment of Computer andCommunications Engineering

University of ThessalyVolos, Greece

[email protected]

Nikolaos BellasDepartment of Computer andCommunications Engineering

University of ThessalyVolos, Greece

[email protected]

ABSTRACTOpenCL is an industry supported standard for writing pro-grams that execute on multicore platforms as well as onaccelerators, such as GPUs or the SPEs of the Cell B.E.In this paper we introduce GLOpenCL, a unified develop-ment framework which supports OpenCL on both homo-geneous, shared memory, as well as on heterogeneous, dis-tributed memory multicores. The framework consists of acompiler, based on the LLVM compiler infrastructure, and arun-time library, sharing the same basic architecture acrossall target platforms. The compiler recognizes OpenCL con-structs, performs source-to-source code transformations tar-geting both efficiency and semantic correctness, and addscalls to the run-time library. The latter offers functional-ity for work creation, management and execution, as wellas for data transfers. We evaluate our framework usingbenchmarks from the distributions of OpenCL implementa-tions by hardware vendors. We find that our generic systemperforms comparably or better than customized, platform-specific vendor distributions. OpenCL is designed and mar-keted as a write-once run-anywhere software developmentframework. However, the standard leaves enough room fortarget platform specific optimizations. Our experimenta-tion with different, customized implementations of kernelsreveals that optimized, hardware mapped implementationsare both possible and necessary in the context of OpenCL –especially on non-conventional multicores – if performanceis considered a higher priority than programmability.

Categories and Subject DescriptorsD.1.3 [Programming Techniques]: Concurrent Program-ming—Parallel Programming ; D.3.4 [PROGRAMMINGLANGUAGES]: Processors—Code generation, Compilers,Optimization, Run-time environments

General TermsDesign, Experimentation, Languages, Measurement, Perfor-

Permission to make digital or hard copies of all or part of this work forpersonal or classroom use is granted without fee provided that copies arenot made or distributed for profit or commercial advantage and that copiesbear this notice and the full citation on the first page. To copy otherwise, torepublish, to post on servers or to redistribute to lists, requires prior specificpermission and/or a fee.HiPEAC 2011 Heraklion, Crete, GreeceCopyright 2011 ACM 978-1-4503-0241-8/11/01 ...$10.00.

mance

KeywordsOpenCL, Compilers, Runtime, Hardware-managed cache mul-ticores, Software-managed cache multicores

1. INTRODUCTIONDuring the last few years, we have witnessed a paradigm

shift towards parallel computing. Technology advances haveenabled the integration of multiple cores in a single die, thusenabling the development of a plethora of computation sub-strates for parallel, high performance, computing. Architec-tures such as homogeneous or heterogeneous multicores andmanycores, and, more recently, GPUs have allowed the time-and power-efficient execution of computationally intensiveapplications at a minimum expense. However, applicationsneed to be rewritten in order to expose their inherent paral-lelism and exploit capabilities of multicore and accelerator-based architectures. Developing parallel programs is a farmore complex undertaking than sequential programming, asthe programmer is responsible for coping with hurdles suchas race conditions, synchronization issues, communication,work management and scheduling, as well as with the pecu-liarities of each parallel architecture.

In order to enable the efficient development of applica-tions, a multitude of programming models have been pro-posed, with the purpose of relieving the programmer fromthe duty of handling – at least some of – these issues thusallowing her to focus on algorithmic issues rather than tech-nicalities. These models include PThreads [15], OpenMP[20], UPC [24] or Cilk [4] for homogeneous and heteroge-neous multicores, the Cell SDK [10] and CellSs [21] for theCell B.E., as well as CUDA [18] and the AMD/ATI StreamSDK [2] that target GPUs.

None of the aforementioned models targets both homoge-neous and heterogeneous multicores, as well as accelerator-based systems at the same time, mainly due to their vastarchitectural differences. For example, applications that tar-get the Cell B.E. are mainly developed using the IBM SDK,thus making their porting to other architectures a tedioustask. There is, thus, strong demand for a programmingmodel that enables application development without priorknowledge of the computing substrate where the applica-tion will be executed. Such a programming model would en-hance portability, provided that it would allow applicationsto be transferred and efficiently executed on different archi-tectures without requiring rewriting or widespread modifica-

Page 2: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

tions. OpenCL [12] is an industry backed effort to develop aunified programming standard and infrastructure for hetero-geneous multicore platforms integrating CPUs and, possibly,accelerators.This paper discusses the design and presents the imple-

mentation of GLOpenCL (GLobal OpenCL), a unified com-piler and run-time infrastructure. GLOpenCL is, to thebest of our knowledge, one of the first OpenCL implemen-tations that enables native execution on architecturally dif-ferent systems, with both hardware- and software-controlledmemory hierarchies. We discuss in detail the compiler trans-formations and run-time support that enable this function-ality, as well as design decisions. Similar infrastructures in-clude the OpenCL SDK [11] from IBM and the unified CUD-A/OpenCL environment [17] by Nvidia that are customizedto support OpenCL applications on the Cell B.E. and NvidiaGPUs respectively. The AMD/ATI Stream SDK [2] fromAMD and ATI supports OpenCL on both x86 CPUs andATI GPUs, however, as we show in Section 5 GLOpenCLsignificantly outperforms it on CPUs. MCUDA [23] andOcelot [7] are two frameworks for efficiently supporting theCUDA programming model on x86 CPUs and the ParallelThread Execution ISA (PTX) [19] on the Cell B.E. respec-tively. They differ from GLOpenCL as they target only asingle hardware platform and are solely focused on compile-time transformations. Moreover they target CUDA andPTX instead of OpenCL codes.Through the execution of a series of benchmark appli-

cations on two representative architectures, namely Intel’sCore i7 (Nehalem) processor and the Cell B.E., we find thatGLOpenCL performs comparably and often better than ven-dor implementations customized for the specific systems.Our system achieves an average speed up of 1.84x (max-imum 2.67x) over the infrastructure from AMD/ATI forx86 systems, while resulting in low overhead compared tothe IBM OpenCL implementation (for the Cell), especiallyfor compute-bound applications. Based on experimental re-sults, we can infer that the main bottleneck for the Cellimplementation is the external software cache module thatwe utilized. OpenCL aims at being a reference, portable pro-gramming model for heterogeneous architectures. Our ex-perimental evaluation indicates, however, that performance-conscious development, combined with a good insight on theunderlying architecture, can result in significant benefits, es-pecially on non-conventional multicores.We briefly outline the OpenCL programming model in

Section 2. Section 3 discusses the compiler support thatis needed to enable efficient execution of OpenCL applica-tions, while in Section 4 we introduce the run-time system’sarchitecture. Next, in Section 5 we discuss the evaluationof our infrastructure on two multicore systems, one homoge-neous with hardware- and one heterogeneous with software-controlled caches. Finally, Section 6 concludes the paper.

2. THE OPENCL PROGRAMMING MODELThe OpenCL (Open Computing Language) [12] program-

ming model tackles the problems of programmability andportability by providing a parallel programming frameworksuitable for conventional multicore architectures as well asfor accelerators, such as the GPUs and the Cell proces-sor. Applications developed with the OpenCL programmingmodel can be ported, ideally unmodified, to any platformthat supports this framework.

OpenCL models the underlying parallel architecture as ahost and a number of OpenCL compute devices. A deviceintegrates a number of compute units, each one divided intoprocessing elements. The processing elements execute a sin-gle stream of instructions and can operate either as SIMDor as SPMD units.

An OpenCL application consists of two parts: the mainprogram that executes on the host and a number of kernelsthat execute on the compute devices. The main constructsin the OpenCL execution model are command queues, ker-nels and memory buffers. OpenCL kernels express the com-putational parts of the application. Command queues areutilized for coordinating the execution of kernels. The mainprogram enqueues commands to the queues. Commands aresubsequently scheduled for execution. A command queuecan store either commands that trigger a kernel’s executionor commands for manipulation of memory buffers. Mem-ory buffers provide the means of data exchange betweenthe host and the compute devices. The corresponding com-mands are either read or write operations for a particularmemory buffer.

OpenCL programmers typically use kernels for expressingparallelism at its finest granularity. The “geometry” of theexecution is described by a 2-level, 3D index space, whichis defined upon execution of a kernel command. Each pointin the index space is called a work-item and corresponds tothe execution of a particular instance of the kernel. Eachwork-item is described by a unique tuple of ids. Work-itemsare organized into work-groups, each having up to three di-mensions (3D thread index within the work-group geome-try). The overall computation can, in turn, be partitioned inwork-groups, also organized in a 3D space (3D work-groupindex within the global computation geometry). OpenCLprovides functionality for synchronization among work-itemsthat belong to the same work-group. On the other hand,work-groups are completely independent on each other andcan execute in parallel. Therefore, the model does not pro-vide primitives for synchronization among work-groups. Onlywork-items that belong to the same work-group can commu-nicate directly, through memory which is visible only insidethe work-group.

3. COMPILATION INFRASTRUCTURETypically, a kernel function in the OpenCL programming

model describes the computation to be executed by a log-ical thread and expresses the application’s parallelism atits finest granularity. However, the efficient exploitationof parallelism and its mapping to the execution contextsof the underlying architecture is not trivial. A straight-forward approach would map each kernel invocation to auser- or kernel-level thread. This approach is acceptable onsystems which provide explicit hardware support for fine-grained threading, such as GPUs. However, other architec-tures, such as conventional multicores or the Cell B.E., re-quire coarser-grained parallelism, in order to limit the over-head of work chunk creation, management and execution.Moreover, the naive, fine-grained execution does not neces-sarily benefit from the potential spatial and temporal local-ity inside a work-group.

To enable efficient execution of OpenCL kernel functions,we apply a series of source-code transformations. Thesetransformations collectively aim at coarsening the granular-ity of the kernel function from a per-logical-thread to a per-

Page 3: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

(a) (b)

Figure 1: Serialization of logical threads inside a kernel function. The kernel function before (a) and after(b) the transformation.

work-group basis, thus reducing overheads. This approachhas the additional benefit of reducing the memory footprintof the application as it allows different logical threads toshare the memory used for common variables. After thetransformations, the modified kernel function represents thework that must be executed by each work-group in the indexspace of the application. OpenCL work-groups can executein parallel. Therefore, it is possible to map each invoca-tion of the modified kernel to an execution context of thearchitecture, as described in more detail in Section 4.The transformation process consists of three main steps:

serialization of logical threads, elimination of synchroniza-tion functions within the kernel, and identification of vari-ables that cannot be shared among logical threads. We havemodified the Clang [6] front-end of the LLVM compiler in-frastructure [13] to support parsing of OpenCL kernel func-tions and perform transformations on the program’s abstractsyntax tree (AST).Additional compiler transformations, necessary to inte-

grate our framework with an external software cache mod-ule, and to support the execution of kernel functions withvarying numbers and types of arguments are described inSections 4.2 and 4.3 respectively.

3.1 Serialization of Logical ThreadsThe first step in the series of transformations aims at in-

creasing the amount of computation in a kernel function byserializing the execution of logical threads. Figure 1 depictsa kernel function before (1(a)) and after (1(b)) the trans-formation. In the absence of synchronization operations,work-items (i.e. logical threads) inside a work-group can beexecuted in any sequence. We enclose the instructions in thebody of a kernel function within a triple-nested loop – giventhat the maximum number of allowable work-group dimen-sions is currently three – thus executing the logical threadsin sequence. Each loop-nest enumerates the logical threadsin the corresponding work-group index dimension.The selection of a work-group as the preferred degree of

granularity for logical threads serialization may seem arbi-

trary. However, in the next section it will become evidentthat other options may present hard to overcome complica-tions in the presence of synchronization operations or mul-tiple exit points within the kernel. At the same time, work-group granularity is usually explicitly set by OpenCL pro-grammers, often considering data reuse, or matching thework-group data footprint to the capacity of specific lev-els of the memory hierarchy. Therefore, introducing differ-ent degrees of work granularity at the run-time, despite be-ing semantically correct, might introduce performance side-effects.

The reader can observe that the serialization transforma-tion typically decreases the cumulative memory footprint ofthe kernel function invocations, since just one logical threadis active at any time, thus the memory allocated to localvariables can be reused.

3.2 Elimination of Synchronization OperationsThe next transformation addresses the problems intro-

duced by synchronization operations or multiple exit pointswithin a kernel. The OpenCL programming model providesthe barrier() function to allow barrier-type synchronizationof work-items inside a work-group. In the presence of abarrier, all work-items in the work-group must execute thebarrier instruction before any of them is allowed to continueexecution beyond the barrier. Similarly, a barrier commandinside a loop implicitly enforces all work-items to executethe barrier before the next iteration of the loop. Finally, ifa barrier is present in the block of a conditional statement,the programmer must ensure that there is no control flow di-vergence within the work-group at the particular condition,otherwise a deadlock is possible.

A kernel function coarsened at a work-group granularityimplicitly enforces synchronization of the code correspond-ing to logical threads before its first and after its last itera-tion. By analogy, a barrier instruction requires that logicalthreads synchronize before traversing it.

To ensure correct execution of the coarsened kernel func-tions, we apply loop fission around each synchronization

Page 4: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

(a) (b)

Figure 2: Loop distribution (loop fission) around a synchronization statement. The Matrix Transpose kernelfunction before (a) and after (b) the transformation. triple_nested_loop stands – for brevity – for the triplenested loop introduced by the logical threads serialization pass.

statement. We partition the statements into blocks so thateach block contains no synchronization operations. Figure 2depicts this transformation for a kernel function that con-tains a barrier instruction. Since there is one synchroniza-tion statement, two loop constructs are required and suffi-cient to ensure correct execution of the kernel function forwork-items inside a work-group.A similar problem occurs in statement blocks with multi-

ple exit points, i.e. when statements that change the controlflow are present, such as continue, break, or return. If sucha statement block is enclosed within the triple-loop nest, ex-ecution will be inconsistent with the program’s semantics,since only the first logical thread will have the opportunityto execute the instructions before the statement. In orderto overcome this issue, we treat such statements similarly tosynchronization points and enclose the instructions beforeand after them in additional loop constructs.Loop fission is applied as an iterative procedure, requiring

several traversals of the AST. A transformation necessitatedby a synchronization or a control flow statement may revealother points in the code that have to be treated as synchro-nization points, thus requiring another traversal.

3.3 Variable PrivatizationAfter applying loop fission around synchronization or con-

trol flow statements, the compiler needs to cope with vari-ables whose life crosses loop fission points.Each logical thread in the initial kernel function had its

own private storage for its local variables. However, once se-rialization is applied, logical threads that belong to a work-group share the memory corresponding to local variables.This is normally both possible and legal, as each logicalthread has finished its execution – and therefore no longerneeds the value of the variable – before the iteration corre-sponding to the next logical thread starts executing. How-ever, there is a complication for variables whose life extendsbeyond a synchronization or a control flow statement, i.e.variables defined and having values assigned before such astatement and reused after it. Values assigned by logical-threads at the first loop construct introduced by loop fissioncannot be used during the execution of the second loop con-

struct, as their content has been polluted by the executionof subsequent logical threads, thus violating semantics.

Our compilation infrastructure conducts a live variableanalysis to identify the variables that are live beyond theboundaries of the loops introduced by loop fission. Follow-ing, we apply variable privatization [1] for these variables,namely we allocate them to a separate memory area for eachlogical thread. Each logical thread is therefore provided witha private copy of such variables. As a final step, referencesto those scalar variables are rewritten to references to theappropriate, thread-local position for each logical thread.

4. RUN-TIME SUPPORTFigure 3(a) depicts the architecture of the GLOpenCL

run-time system for a system with hardware-controlled mem-ory hierarchy (Intel x86), while Figure 3(b) depicts the ar-chitecture for a software-controlled memory hierarchy mul-ticore (Cell B.E.).

The run-time spawns a number of kernel-level threads,which are used either as execution vehicles, or as helperthreads. The main thread is the one that executes the hostside of the OpenCL application. Worker threads are cre-ated upon initialization and are responsible for executing themain computational tasks of the application. GLOpenCLrun-time system spawns a number of worker threads equalto the number of execution contexts available on the un-derlying architecture. Finally, management and monitoringtasks are undertaken by a helper thread. The exact respon-sibilities and implementation of the helper thread are archi-tecture specific.

4.1 Work ManagementFor each instruction of the host-side code that enqueues

a command, the main thread creates an appropriate com-mand descriptor and enqueues it in the command queue.The latter typically is a very lightly contended data struc-ture. Mutually exclusive access to the queue is implementedusing futexes [8]. Once the main thread has executed the lastinstruction of the host-side of the application, it blocks untilall enqueued commands have been executed.

Page 5: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

(a) (b)

Figure 3: The run-time system’s architecture for the Intel (a) and the Cell B.E. (b) architectures. Dotted linesidentify architecture-specific modules or operations. The numbering denotes a typical sequence of operations.

Commands are transferred from the command queue tothe ready command queue when they are ready to be exe-cuted. A command queue can be configured by the program-mer to support either in-order or out-of-order execution. Ifin-order execution is enabled, a command is transferred tothe ready queue if it is at the top of the command queue, andprovided that all previously issued commands have finishedtheir execution.When the command queue has been configured for out-of-

order execution, a dependence-driven self-scheduling schemeis applied. Each command can be marked as dependenton one or more prior commands. Each executed commandupdates the dependencies of its dependents. As soon asa dependent command is identified to have no unsatisfieddependencies, it is enqueued to the ready queue.Work-tasks are created when a command related to a ker-

nel execution is processed from the ready queue. Each work-task represents the computation that must be executed fora single work-group in the index space of the application. Awork-task corresponds to an invocation of the correspond-ing modified kernel function. The number of work-tasksdepends on the partitioning of the global index space. AnOpenCL programmer can explicitly partition the global in-dex space, by defining the dimension of work-groups. If thisis not the case, the run-time performs an implicit, static par-titioning of the index space, taking into account the numberof worker threads. In order to avoid work-task starvation,execution of work-tasks has higher priority over the execu-tion of ready commands. This means that a ready commandis processed only when work queues are empty of work-tasks.In the x86 implementation commands are transferred fromthe command queue to the ready queue and processed byworker threads. As soon as a ready command is executed,the corresponding work-tasks are created and distributed tothe work queues. This series of operations is carried out bythe helper thread in the Cell implementation.Worker threads continuously execute a scheduling loop.

In each iteration, they retrieve the next available work-taskfrom the top of the work queue and execute the correspond-ing wrapper kernel function. In the x86 implementation, aworker thread has direct access to the work queues. This

is not the case for the Cell, where each worker thread isexecuted on an SPE, thus having no direct access to workqueues residing in the address space of the PPE. When aworker has finished executing its task, it communicates withthe helper thread through the mailbox mechanism to requestthe next available task. If there is one, the helper threadinforms the worker thread, which subsequently transfers,through the DMA mechanism, the work-task descriptor andcontinues its execution. Otherwise, the helper thread marksthe worker as idling until there is a new work-task.

We have opted for a per-thread work queue scheme, whereeach work queue is local to the corresponding worker thread.Multiple work queues reduce the synchronization overhead,enhance locality and improve the scalability of the run-timesystem. Locality benefits are particularly evident in systemswith software-controlled cache hierarchies, such as the CellB.E. Work tasks are statically partitioned to the availableworker threads. Static partitioning tends to enhance local-ity, as neighboring work-groups often access data in closeproximity.

To ensure proper load balancing among worker threads,we allow work-stealing on the work queues. Each workerthat finds itself idling may attempt to steal work from thebottom of a work queue of another worker. In the x86implementation workers perform work-stealing directly. Alock-free queue implementation enforces synchronization be-tween threads that attempt to access the same queue simul-taneously. In the Cell implementation, idle workers are as-sisted in work-stealing by the helper thread. Only the helperthread accesses the queues, therefore no synchronization isrequired.

4.2 Manipulation of Memory BuffersIn OpenCL, memory buffers provide the communication

medium between the host and compute devices, as well asbetween work-items. They can be either global or local.Global memory buffers can be accessed by any work-item inthe global index space while local buffers are only accessibleby work-items inside a work-group. Global buffers present agreat challenge in the run-time system’s implementation forsoftware-controlled cache architectures, such as the Cell B.E.

Page 6: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

The capacity of the higher levels of the memory hierarchy(the Local Store in the SPEs) is limited and often insuffi-cient to accommodate the working set of a work-group. Theproblem is further complicated when there is no hardwaresupport for coherence between caches on different computedevices (Local Stores of different SPEs). At the same time,as we will discuss in Section 5, global buffers fit better tothe notion of shared memory most programmers are familiarwith. Therefore, they tend to be preferred over local buffers,even when this would not be technically necessary.Both problems can be addressed by using a software cache

module. The design and implementation of a new softwarecache mechanism is out of the scope of this work. There-fore, we have utilized the COMIC shared memory system,one of the few software caches available for the Cell B.E.[14]. COMIC is an unified software cache and threadingsystem. We have modified it to operate solely as a softwarecache and integrated it with GLOpenCL. Each reference toa global buffer in the kernel function is rewritten by thecompiler and gets redirected to the software cache mecha-nism. The software cache, in turn, performs all necessaryoperations on the Local Stores of different SPEs to guar-antee the coherence of accesses to the corresponding globalbuffer. A client side of the software cache is executed at eachworker thread (on SPEs) while the server side is executed inthe context of a helper thread on the host (PPE). Requestsfrom a software cache client are directed to the server, whichreturns the appropriate data to the corresponding client andupdates other clients on potential coherence complications.Such a mechanism is obviously redundant in the x86 im-plementation as the caches are hardware-controlled and acoherence protocol is already in place.The last component of the run-time system for the x86

architecture is the async. copy thread and the correspond-ing queue. OpenCL provides functions for asynchronouslycopying data from global buffers to local ones and vice versainside a work-group. Any asynchronous function found in-side a kernel must be executed by every work-item in thework-group. An asynchronous copy operation returns anevent descriptor which can be used later to poll whetherthe operation has completed its execution. We enable asyn-chronous copy operations by utilizing a helper thread, theasync. copy thread, to handle the corresponding requests.When a worker thread encounters such an asynchronous call,it enqueues a request in the async. copy queue. The async.copy thread is responsible for dequeuing the next availablerequest, copying the appropriate data, and updating the cor-responding event.The implementation of asynchronous memory copies in

architectures with software-controlled memory hierarchies isusually more straightforward. Such architectures tend toprogrammatically expose the DMA interface, as it is thepreferred mechanism for transferring data between differentlevels of the memory hierarchy. On the Cell for example, anasync. copy operation is implemented as one or more DMAtransfers, which are inherently asynchronous.

4.3 Dynamic Kernel InvocationOnce a worker thread is assigned a work-task, it must in-

voke the corresponding modified kernel function with theappropriate number of arguments. The optimal approachto support the dynamic invocation of a kernel function isthrough a function pointer. This approach requires that

both the address of the function and the number of its argu-ments are known. An OpenCL application can invoke mul-tiple kernel functions during its execution life, identifyingthem by their name, namely a string. Moreover, differentkernel functions can have different numbers and types of ar-guments. The complications are thus two-fold: a) The run-time system must have prior knowledge of the number andtype of each kernel function’s arguments, and b) It shouldbe able to obtain the address of the function based on itsname.

In order to support kernel functions with varying num-bers and types of arguments, we provide a uniform interfacefor the invocation of a kernel function. Therefore, the com-piler creates a wrapper for each modified kernel function inthe application. A wrapper function has only one argument(an array of void pointers) and is responsible for dispatch-ing the kernel’s arguments as the corresponding functionparameters, as well as for invoking the function. Therefore,work-task descriptors only need to contain the address ofthe corresponding wrapper function and a pointer to its ar-gument.

Overcoming the second complication is trivial on systemsthat support dynamic linking, as is the case in the x86 im-plementation. At link-time, all symbols are added to thesymbol table of the executable. Then, we exploit the func-tionality of the run-time dynamic linker to obtain the stubfunction’s address, based on its name.

An alternative approach needs to be followed on staticallylinked binaries, or when different executables are producedfor the host and the compute devices. This is, for example,the case for the Cell implementation, as the executable forthe SPEs, which contains the kernel functions, is staticallylinked with the executable of the PPE to produce a singlebinary. Therefore, no dynamic lookup is possible. The pro-posed approach is based on the observation that both PPEand the SPEs have access to the regions of the ELF binarythat is produced. We allocate a separate region in the binaryand make its address known to the SPEs upon initialization.For each wrapper function in the program, this section storesa tuple that consists of its name and its address. When apointer to a function is needed, the PPE accesses the com-mon section, locates the position of the wrapper function,and stores the offset in the work-task descriptors that areproduced. This offset is subsequently used by the SPEs inorder to index the section and obtain the pointer to the ap-propriate function.

The two aforementioned approaches are complementary.The latter has the additional positive effect of allowing us toovercome the limited capacity of the Cell B.E. Local Storewith respect to application code size. The Local Store in theSPEs is unified and stores both the data and the instructionsof the program. As a consequence, this space may not sufficefor applications that execute multiple kernels throughouttheir life, as the Local Store may be unable to concurrentlyaccommodate the source code for every function. Invokinga function through a pointer can be used along with theSPU code overlay mechanism to enable dynamic loading of afunction’s code in the Local Store of the SPE, thus virtuallyextending its capacity.

5. EXPERIMENTAL EVALUATIONIn this section we present the experimental evaluation of

GLOpenCL on two different platforms: an homogeneous

Page 7: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

Figure 4: Performance comparison between GLOpenCL and the ATI/AMD OpenCL SDK on the x86. Ex-periments have been executed for varying data sets (lower x-axis labels) and work-group sizes (upper x-axislabels).

Page 8: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

multicore with hardware-controlled memory hierarchy, andan heterogeneous multicore with software-controlled caches.Our homogeneous multicore is an Intel-based workstation,using an Intel E5520 i7 processor clocked at 2.27 GHz and 4GB of RAM. The processor integrates four identical cores.Each core has a 32 KB instruction + 32 KB data privateL1 and a unified 256 KB L2 cache. All four cores sharean 8 MB L3 cache. Cell B.E. is a typical representative ofheterogeneous multicores with software controlled memoryhierarchy. We experimented with a IBM QS20 Blade withtwo Cell processors clocked at 3.2 GHz. Only one of themwas used throughout the evaluation. The processor inte-grates a 2-way SMT PowerPC core (PPE) and 8 synergisticprocessing element cores (SPEs). Each SPE accesses a pri-vate, software-controlled, 256 KB local storage (LS). Theblade is also equipped with 1 GB of RAM.We compare the performance of GLOpenCL with that

of vendor provided, platform-customized implementations,namely the AMD/ATI Stream SDK (v2.1) on x86 and theIBM OpenCL SDK (v0.1.1) on the QS20 Cell blade. Weused the following set of representative applications, withdiverse characteristics, from the two SDK distributions:

• Vector Add: Addition of 2 vectors. No temporal lo-cality, some spatial locality, communication intensive.

• 2D DCT: Discrete Cosine Transform on an image.Blocked, temporal and spatial locality, compute bound.

• Sobel: Sobel filter [22] on an image. Blocked, similarcharacteristics with 2D DCT.

• 2D AES: AES encryption [16] of an image. Similar char-acteristics with 2D DCT and Sobel, the most computeintensive application in the set, as it was reported bothby Intel VTune [9] for the x86 and the Cell Perfor-mance Counter tool (CPC) [5] for the Cell B.E.

• BlackSholes: Solution of Black-Scholes PDEs [3] fora number of options. Some spatial locality, no tem-poral locality, compute intensive, complex math op-erations. The async. version uses double bufferingand explicit, asynchronous blocked transfers for databuffers, instead of implicitly outsourcing communica-tion to the hardware or software cache mechanism.

All codes are precompiled, i.e. the just-in-time compila-tion capabilities of OpenCL have not been used. GLOpenCLapplication binaries have been created with the Intel C Com-piler v11.1 on x86 and with xlc on Cell. In all cases, we ap-plied the set of optimization flags that resulted in the highestperforming binaries.We have executed each application with varying data sets

and work-group sizes. To ensure a fair comparison betweenthe different implementations, we measure only the kernelexecution time in each application. For each configuration,we have executed a series of ten experiments and we reportthe mean execution time. In each case, the variance of theexecution time was insignificant, which means that all re-sults are reliable.Figure 4 depicts the performance evaluation results on

the x86 platform. GLOpenCL consistently outperforms theAMD/ATI OpenCL SDK. The average performance improve-ment is 1.84x whereas the maximum speedup is 2.67. Wecannot know the exact reason for this performance difference

as internal details of the AMD/ATI OpenCL SDK are notpublicly available. Execution time in all applications scaleslinearly to the amount of work. Moreover, larger work-groupsizes consistently tend to be beneficial for performance, asless work-tasks need to be created, thus reducing work-chunkcreation, management and execution overhead. At the sametime, larger work-groups implicitly favor temporal locality,especially in blocked codes.

Another interesting observation is that the substitution ofhardware assisted buffer transfers with asynchronous, double-buffered copies in the case of BlackScholes does not seem tooffer any measurable performance benefits. Modern, hard-ware-controlled memory hierarchies have the potential of ef-fectively hiding memory access latencies, at least for memorytransfers that do not require multi-hop interconnection net-work transactions and for regular loops in which traditionaloptimizations – such as unrolling – or more aggressive tech-niques – such as compiler assisted prefetching – can be ap-plied. This is particularly true for multicore chips with large,shared outer-level caches. Therefore, such architectures are,by nature, more forgiving to suboptimal implementations.

Finally GLOpenCL proved able to work with both largerwork-groups and tackle larger data sets / problem sizes.The largest problem size reported in the charts, with theexception of AES and Sobel, is the limit beyond which theAMD/ATI OpenCL SDK did not manage to allocate buffers.Moreover, in certain cases the AMD/ATI OpenCL SDKfailed to exploit larger work-groups for a certain problemsize. Such behavior can be observed for Vector Add, DCTand both versions of BlackScholes.

Figure 5 summarizes the evaluation on the Cell blade.The IBM OpenCL SDK is performing on average 27.5%better than GLOpenCL. This can be mainly attributed tothe difference in the efficiency of the software cache imple-mentations used by each system. IBM uses a custom soft-ware cache, which significantly outperforms the one publi-cally available within the IBM Cell SDK. Moreover, the soft-ware cache is tightly integrated with the OpenCL-enabledxlc compiler, thus allowing detailed compile-time data ac-cess pattern analysis and optimizations. It is characteristicthat for the communication-intensive Vector Add applica-tion IBM OpenCL outperforms the GLOpenCL and COMICcombination by 52.6%. Excluding Vector Add, the perfor-mance gap between the GLOpenCL and IBM infrastruc-ture drops to 19.1%, or 13.2% if the best performing work-group geometry is used for each problem size. Moreover, forcompute-intensive applications, such as AES and Sobel, theperformance of the two systems is practically indistinguish-able, especially for larger problem sizes.

IBMOpenCL outperforms GLOpenCL even in the BlackSc-holes implementation using asynchronous copy, thus reduc-ing the effect of the software cache. As discussed in Sec-tion 4.2, COMIC integrates the software cache with a thread-ing system. Although we have deactivated the threadingsystem and combined COMIC with the GLOpenCL run-time, some helper threads primarily used for monitoringCOMIC threading are tightly integrated with the softwarecache module and cannot be deactivated. They, thus, inter-fere with GLOpenCL main and helper threads even whenthe cache is not heavily used. An interesting observation isthe more than 10-fold performance improvement for both in-frastructures when the asynchronous copy / double-bufferingoptimization is used for data buffers. Despite the fact that

Page 9: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

Figure 5: Performance comparison between GLOpenCL and the IBM OpenCL SDK on the Cell. Experimentshave been executed for varying data sets (lower x-axis labels) and work-group sizes (upper x-axis labels).The largest data size in each chart is the limit beyond which IBM OpenCL SDK is unable to allocate memorybuffers.

Page 10: GLOpenCL: OpenCL Support on Hardware- and Software-Managed ... · tions. OpenCL [12] is an industry backed e ort to develop a uni ed programming standard and infrastructure for hetero-geneous

OpenCL has been designed as a write-once run-everywhereframework, this result is indicative of the vast performancebenefits that can often be attained by carefully mapping thecomputation to the specific characteristics of the underlyingarchitecture.Finally, similarly to the case of x86, GLOpenCL was able

to work with both larger work-groups and be usable withlarger problem sizes than the IBM OpenCL SDK on theCell blade.

6. CONCLUSIONSWe presented the design, implementation and evaluation

of GLOpenCL, a unified compiler and run-time frameworkfor supporting OpenCL applications on a set of parallel sys-tems with diverse architectural characteristics. Our genericframework performed comparably, or often significantly bet-ter than customized, architecture specific, vendor OpenCLimplementations. Moreover, the experimental evaluation in-dicated that, even when developers use programming mod-els – such as OpenCL – targeted at efficiently supportingfundamentally different and often heterogeneous computingsubstrates, careful mapping of applications to the under-lying architecture may yield hard to overlook performancebenefits.In future work, we plan to investigate the possibility of

reducing the functionality or even removing the softwarecache in systems with software-controlled memory hierar-chies, since the specific module proved to be the main per-formance bottleneck on the Cell implementation. Althoughprogrammers tend to use shared data structures even whenthey could avoided, automatic code slicing and precomputa-tion of memory accesses – either at the host- or the computedevices-side – may prove a valuable tool in reducing com-munication overhead.

7. ACKNOWLEDGEMENTSWe would like to thank Barcelona Supercomputing Center

for providing us with access to their IBM QS20 Cell bladeservers and the anonymous reviewers for their constructivecomments. The first author is supported by a grant from‘Bodossaki’ public benefit foundation.

8. REFERENCES[1] R. Allen and K. Kennedy. Optimizing Compilers for

Modern Architectures: A Dependence-Based Approach.Morgan Kaufmann, 2002.

[2] ATI-AMD. ATI Stream Software Development Kit(SDK) v2.1. http://developer.amd.com/gpu/ATIStreamSDK/Pages/default.aspx.

[3] F. Black and M. Scholes. The Pricing of Options andCorporate Liabilities. The Journal of PoliticalEconomy, 81(3):637–654, 1973.

[4] R. D. Blumofe, C. F. Joerg, B. C. Kuszmaul, C. E.Leiserson, K. H. Randall, and Y. Zhou. Cilk: AnEfficient Multithreaded Runtime System. Journal ofParallel and Distributed Computing, 37(1):55–69, 1996.

[5] Cell B.E. Performance Counter Tool.http://www.ibm.com/developerworks/power/

tutorials/pa-sdk3tool/.

[6] Clang: A C Language Family Frontend for LLVM.http://clang.llvm.org/.

[7] G. Diamos, A. Kerr, and M. Kesavan. TranslatingGPU Binaries to Tiered SIMD Architectures withOcelot. Technical report, Georgia Institute ofTechnology, 2009.

[8] H. Franke and R. Russel. Fuss, Futexes and Furlocks:Fast User-Space Locking in Linux. In Proceedings ofthe Otawa Linux Symposium, pages 85–97, 2002.

[9] Intel Corporation. Intel VTune Performance Analyzer.Document Number 310866-001.

[10] International Business Machines Corporation (IBM).IBM SDK for Multicore Acceleration Version 3.1.http://www.ibm.com/developerworks/power/cell/.

[11] International Business Machines Corporation (IBM).OpenCL Development Kit for Linux on Power.http://www.alphaworks.ibm.com/tech/opencl.

[12] Khronos OpenCL Working Group and A. Munshi.The OpenCL Specification Version: 1.0 DocumentRevision: 48, 2009.

[13] C. Lattner and V. Adve. LLVM: A CompilationFramework for Lifelong Program Analysis &Transformation. In CGO ’04: Proceedings of theInternational Symposium on Code Generation andOptimization, pages 75–86, 2004.

[14] J. Lee, S. Seo, C. Kim, J. Kim, P. Chun, Z. Sura,J. Kim, and S. Han. COMIC: A Coherent SharedMemory Interface for Cell BE. In PACT ’08:Proceedings of the 17th International Conference onParallel Architectures and Compilation Techniques,pages 303–314, 2008.

[15] F. Mueller. A Library Implementation of POSIXThreads under Unix. In Proceedings of the USENIXConference, pages 29–41, 1993.

[16] National Institute of Standards and Technology(NIST). Announcing the ADVANCED ENCRYPTIONSTANDARD (AES). Federal Information ProcessingStandards Publication 197, November 2001.

[17] NVIDIA. CUDA Technology. http://www.nvidia.com/object/cuda\_home\_new.html.

[18] NVIDIA. CUDA Programming Guide, Version 3.0,2010.

[19] NVIDIA. NVIDIA Compute PTX: Parallel ThreadExecution ISA Version 2.0, 2010.

[20] OpenMP. The OpenMP API.http://openmp.org/wp/.

[21] J. P. Perez, P. Bellens, R. M. Badia, and J. Labarta.CellSs: Making it Easier to Program the CellBroadband Engine Processor. IBM Journal ofResearch and Development, 51(5):593–604, 2007.

[22] I. Sobel and G. Feldman. A 3x3 Isotropic GradientOperator for Image Processing. Talk presented at theStanford Artificial Project, 1968.

[23] J. A. Stratton, S. S. Stone, and W.-M. W. Hwu.MCUDA: An Efficient Implementation of CUDAKernels for Multi-core CPUs. In Languages andCompilers for Parallel Computing: 21th InternationalWorkshop, LCPC 2008, Revised Selected Papers,pages 16–30, 2008.

[24] UPC Consortium. UPC Language Specifications, v1.2.Technical Report LBNL-59208, Lawrence BerkeleyNational Lab, 2005.