<commit_before>// RaceDetector.cpp (Oclgrind)
// Copyright (c) 2013-2015, <NAME> and <NAME>,
// University of Bristol. All rights reserved.
//
// This program is provided under a three-clause BSD license. For full
// license terms please see the LICENSE file distributed with this
// source code.

#include "core/common.h"

#include "core/Context.h"
#include "core/KernelInvocation.h"
#include "core/Memory.h"
#include "core/WorkGroup.h"
#include "core/WorkItem.h"

#include "RaceDetector.h"

using namespace oclgrind;
using namespace std;

THREAD_LOCAL RaceDetector::WorkerState RaceDetector::m_state = {NULL};

#define STATE(workgroup) ((*m_state.groups)[workgroup])

// Use a bank of mutexes to reduce unnecessary synchronisation
#define NUM_GLOBAL_MUTEXES 4096 // Must be power of two
#define GLOBAL_MUTEX(buffer,offset) \
  m_globalMutexes[buffer][offset & (NUM_GLOBAL_MUTEXES-1)]

RaceDetector::RaceDetector(const Context *context)
 : Plugin(context)
{
  m_kernelInvocation = NULL;

  m_allowUniformWrites = !checkEnv("OCLGRIND_UNIFORM_WRITES");
}

void RaceDetector::kernelBegin(const KernelInvocation *kernelInvocation)
{
  m_kernelInvocation = kernelInvocation;
}

void RaceDetector::kernelEnd(const KernelInvocation *kernelInvocation)
{
  // Clear all global memory accesses
  for (auto buffer  = m_globalAccesses.begin();
            buffer != m_globalAccesses.end();
            buffer++)
  {
    size_t sz = buffer->second.size();
    buffer->second.clear();
    buffer->second.resize(sz);
  }

  m_kernelInvocation = NULL;
}

void RaceDetector::memoryAllocated(const Memory *memory, size_t address,
                                   size_t size, cl_mem_flags flags,
                                   const uint8_t *initData)
{
  if (memory->getAddressSpace() == AddrSpaceGlobal)
  {
    m_globalAccesses[EXTRACT_BUFFER(address)].resize(size);
    m_globalMutexes[EXTRACT_BUFFER(address)] = new mutex[NUM_GLOBAL_MUTEXES];
  }
}

void RaceDetector::memoryAtomicLoad(const Memory *memory,
                                    const WorkItem *workItem,
                                    AtomicOp op, size_t address, size_t size)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, true);
}

void RaceDetector::memoryAtomicStore(const Memory *memory,
                                     const WorkItem *workItem,
                                     AtomicOp op, size_t address, size_t size)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, true,
                 (const uint8_t*)memory->getPointer(address));
}

void RaceDetector::memoryDeallocated(const Memory *memory, size_t address)
{
  if (memory->getAddressSpace() == AddrSpaceGlobal)
  {
    m_globalAccesses.erase(EXTRACT_BUFFER(address));

    delete[] m_globalMutexes[EXTRACT_BUFFER(address)];
    m_globalMutexes.erase(EXTRACT_BUFFER(address));
  }
}

void RaceDetector::memoryLoad(const Memory *memory, const WorkItem *workItem,
                              size_t address, size_t size)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, false, NULL);
}

void RaceDetector::memoryLoad(const Memory *memory, const WorkGroup *workGroup,
                              size_t address, size_t size)
{
  registerAccess(memory, workGroup, NULL, address, size, false);
}

void RaceDetector::memoryStore(const Memory *memory, const WorkItem *workItem,
                               size_t address, size_t size,
                               const uint8_t *storeData)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, false, storeData);
}

void RaceDetector::memoryStore(const Memory *memory, const WorkGroup *workGroup,
                               size_t address, size_t size,
                               const uint8_t *storeData)
{
  registerAccess(memory, workGroup, NULL,
                 address, size, false, storeData);
}

void RaceDetector::workGroupBarrier(const WorkGroup *workGroup, uint32_t flags)
{
  if (flags & CLK_LOCAL_MEM_FENCE)
  {
    syncWorkItems(workGroup->getLocalMemory(),
                  STATE(workGroup), STATE(workGroup).wiLocal);
  }
  if (flags & CLK_GLOBAL_MEM_FENCE)
  {
    syncWorkItems(m_context->getGlobalMemory(),
                  STATE(workGroup), STATE(workGroup).wiGlobal);
  }
}

void RaceDetector::workGroupBegin(const WorkGroup *workGroup)
{
  // Create worker state if haven't already
  if (!m_state.groups)
  {
    m_state.groups = new unordered_map<const WorkGroup*,WorkGroupState>;
  }

  // Initialize work-group state
  WorkGroupState& state = STATE(workGroup);
  Size3 wgsize = workGroup->getGroupSize();
  state.numWorkItems = wgsize.x*wgsize.y*wgsize.z;
  state.wiGlobal.resize(state.numWorkItems+1);
  state.wiLocal.resize(state.numWorkItems+1);
}

void RaceDetector::workGroupComplete(const WorkGroup *workGroup)
{
  WorkGroupState& state = STATE(workGroup);

  syncWorkItems(workGroup->getLocalMemory(), state, state.wiLocal);
  syncWorkItems(m_context->getGlobalMemory(), state, state.wiGlobal);

  // Merge global accesses across kernel invocation
  Size3 group = workGroup->getGroupID();
  for (auto record  = state.wgGlobal.begin();
            record != state.wgGlobal.end();
            record++)
  {
    size_t address = record->first;
    size_t buffer = EXTRACT_BUFFER(address);
    size_t offset = EXTRACT_OFFSET(address);

    lock_guard<mutex> lock(GLOBAL_MUTEX(buffer, offset));

    AccessRecord& a = record->second;
    AccessRecord& b = m_globalAccesses[buffer][offset];

    // Check for races with previous accesses
    if (getAccessWorkGroup(b.store) != group && check(a.load,  b.store))
      logRace(m_context->getGlobalMemory(), address, a.load, b.store);
    if (getAccessWorkGroup(b.load) != group && check(a.store, b.load))
      logRace(m_context->getGlobalMemory(), address, a.store, b.load);
    if (getAccessWorkGroup(b.store) != group && check(a.store, b.store))
      logRace(m_context->getGlobalMemory(), address, a.store, b.store);

    // Insert accesses
    if (a.load.isSet())
      insert(b, a.load);
    if (a.store.isSet())
      insert(b, a.store);
  }
  state.wgGlobal.clear();
<commit_msg>DRD: Reordered race vs same WG checks on global accesses.<commit_after>// RaceDetector.cpp (Oclgrind)
// Copyright (c) 2013-2015, <NAME> and <NAME>,
// University of Bristol. All rights reserved.
//
// This program is provided under a three-clause BSD license. For full
// license terms please see the LICENSE file distributed with this
// source code.

#include "core/common.h"

#include "core/Context.h"
#include "core/KernelInvocation.h"
#include "core/Memory.h"
#include "core/WorkGroup.h"
#include "core/WorkItem.h"

#include "RaceDetector.h"

using namespace oclgrind;
using namespace std;

THREAD_LOCAL RaceDetector::WorkerState RaceDetector::m_state = {NULL};

#define STATE(workgroup) ((*m_state.groups)[workgroup])

// Use a bank of mutexes to reduce unnecessary synchronisation
#define NUM_GLOBAL_MUTEXES 4096 // Must be power of two
#define GLOBAL_MUTEX(buffer,offset) \
  m_globalMutexes[buffer][offset & (NUM_GLOBAL_MUTEXES-1)]

RaceDetector::RaceDetector(const Context *context)
 : Plugin(context)
{
  m_kernelInvocation = NULL;

  m_allowUniformWrites = !checkEnv("OCLGRIND_UNIFORM_WRITES");
}

void RaceDetector::kernelBegin(const KernelInvocation *kernelInvocation)
{
  m_kernelInvocation = kernelInvocation;
}

void RaceDetector::kernelEnd(const KernelInvocation *kernelInvocation)
{
  // Clear all global memory accesses
  for (auto buffer  = m_globalAccesses.begin();
            buffer != m_globalAccesses.end();
            buffer++)
  {
    size_t sz = buffer->second.size();
    buffer->second.clear();
    buffer->second.resize(sz);
  }

  m_kernelInvocation = NULL;
}

void RaceDetector::memoryAllocated(const Memory *memory, size_t address,
                                   size_t size, cl_mem_flags flags,
                                   const uint8_t *initData)
{
  if (memory->getAddressSpace() == AddrSpaceGlobal)
  {
    m_globalAccesses[EXTRACT_BUFFER(address)].resize(size);
    m_globalMutexes[EXTRACT_BUFFER(address)] = new mutex[NUM_GLOBAL_MUTEXES];
  }
}

void RaceDetector::memoryAtomicLoad(const Memory *memory,
                                    const WorkItem *workItem,
                                    AtomicOp op, size_t address, size_t size)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, true);
}

void RaceDetector::memoryAtomicStore(const Memory *memory,
                                     const WorkItem *workItem,
                                     AtomicOp op, size_t address, size_t size)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, true,
                 (const uint8_t*)memory->getPointer(address));
}

void RaceDetector::memoryDeallocated(const Memory *memory, size_t address)
{
  if (memory->getAddressSpace() == AddrSpaceGlobal)
  {
    m_globalAccesses.erase(EXTRACT_BUFFER(address));

    delete[] m_globalMutexes[EXTRACT_BUFFER(address)];
    m_globalMutexes.erase(EXTRACT_BUFFER(address));
  }
}

void RaceDetector::memoryLoad(const Memory *memory, const WorkItem *workItem,
                              size_t address, size_t size)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, false, NULL);
}

void RaceDetector::memoryLoad(const Memory *memory, const WorkGroup *workGroup,
                              size_t address, size_t size)
{
  registerAccess(memory, workGroup, NULL, address, size, false);
}

void RaceDetector::memoryStore(const Memory *memory, const WorkItem *workItem,
                               size_t address, size_t size,
                               const uint8_t *storeData)
{
  registerAccess(memory, workItem->getWorkGroup(), workItem,
                 address, size, false, storeData);
}

void RaceDetector::memoryStore(const Memory *memory, const WorkGroup *workGroup,
                               size_t address, size_t size,
                               const uint8_t *storeData)
{
  registerAccess(memory, workGroup, NULL,
                 address, size, false, storeData);
}

void RaceDetector::workGroupBarrier(const WorkGroup *workGroup, uint32_t flags)
{
  if (flags & CLK_LOCAL_MEM_FENCE)
  {
    syncWorkItems(workGroup->getLocalMemory(),
                  STATE(workGroup), STATE(workGroup).wiLocal);
  }
  if (flags & CLK_GLOBAL_MEM_FENCE)
  {
    syncWorkItems(m_context->getGlobalMemory(),
                  STATE(workGroup), STATE(workGroup).wiGlobal);
  }
}

void RaceDetector::workGroupBegin(const WorkGroup *workGroup)
{
  // Create worker state if haven't already
  if (!m_state.groups)
  {
    m_state.groups = new unordered_map<const WorkGroup*,WorkGroupState>;
  }

  // Initialize work-group state
  WorkGroupState& state = STATE(workGroup);
  Size3 wgsize = workGroup->getGroupSize();
  state.numWorkItems = wgsize.x*wgsize.y*wgsize.z;
  state.wiGlobal.resize(state.numWorkItems+1);
  state.wiLocal.resize(state.numWorkItems+1);
}

void RaceDetector::workGroupComplete(const WorkGroup *workGroup)
{
  WorkGroupState& state = STATE(workGroup);

  syncWorkItems(workGroup->getLocalMemory(), state, state.wiLocal);
  syncWorkItems(m_context->getGlobalMemory(), state, state.wiGlobal);

  // Merge global accesses across kernel invocation
  Size3 group = workGroup->getGroupID();
  for (auto record  = state.wgGlobal.begin();
            record != state.wgGlobal.end();
            record++)
  {
    size_t address = record->first;
    size_t buffer = EXTRACT_BUFFER(address);
    size_t offset = EXTRACT_OFFSET(address);

    lock_guard<mutex> lock(GLOBAL_MUTEX(buffer, offset));

    AccessRecord& a = record->second;
    AccessRecord& b = m_globalAccesses[buffer][offset];

    // Check for races with previous accesses
    if (check(a.load,  b.store) && getAccessWorkGroup(b.store) != group)
      logRace(m_context->getGlobalMemory(), address, a.load, b.store);
    if (check(a.store, b.load) && getAccessWorkGroup(b.load) != group)
      logRace(m_context->getGlobalMemory(), address, a.store, b.load);
    if (check(a.store, b.store) && getAccessWorkGroup(b.store) != group)
      logRace(m_context->getGlobalMemory(), address, a.store, b.store);

    // Insert accesses
    if (a.load.isSet())
      insert(b, a.load);
    if (a.store.isSet())
      insert(b, a.store);
  }
  state.wgGlobal.clear();

{'fraction_non_alphanumeric': 0.11318646232439336, 'fraction_numerical': 0.0036717752234993613, 'mean_word_length': 3.2572205232755693, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6247523', 'n_tokens_mistral': 3920, 'n_tokens_neox': 3847, 'n_words': 831}