This document discusses programming GPUs using OpenCL. It explores synchronization issues like hazards and critical sections that can occur in parallel programming. It also examines the GPU execution model of workitems, wavefronts, and workgroups, as well as the memory model of global and local memory. The document implements a genetic algorithm to solve the knapsack problem in OpenCL using both global and local memory. It finds that for this problem, local memory provided no performance benefit due to overhead of data transfer between memories.