P4 to Git Change 1184767 by lmoriche@lmoriche_opencl_dev on 2015/08/26 13:54:18
ECR #304775 - Remove the complib oclutils
Affected files ...
... //depot/stg/opencl/drivers/opencl/Makefile#52 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/Makefile#36 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/build/Makefile.complib#92 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/complibdefs#43 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/Makefile#2 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/build/Makefile#2 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/build/Makefile.oclutils#3 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/alloc.cpp#3 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/alloc.hpp#2 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/os.cpp#6 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/os.hpp#7 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/os_posix.cpp#11 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/os_win32.cpp#6 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/setjmp.S#2 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/os/setjmp.asm#2 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/atomic.hpp#5 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/monitor.cpp#3 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/monitor.hpp#3 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/semaphore.cpp#3 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/semaphore.hpp#4 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/thread.cpp#4 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/thread/thread.hpp#4 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/top.hpp#6 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/utils/debug.cpp#2 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/utils/debug.hpp#3 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/utils/macros.hpp#4 delete
... //depot/stg/opencl/drivers/opencl/compiler/lib/promotions/oclutils/utils/util.hpp#3 delete
... //depot/stg/opencl/drivers/opencl/runtime/Makefile#19 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/debug.cpp#4 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/debug.hpp#6 edit
... //depot/stg/opencl/drivers/opencl/runtime/utils/flags.hpp#238 edit
[ROCm/clr commit: 7f24b9ffbb]
This commit is contained in:
@@ -37,8 +37,10 @@ endif
|
||||
GCPPFLAGS += $(INCSWITCH) "$(DEPTH)/drivers"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(DEPTH)/drivers/inc/asic_reg"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(COMPLIB_DEPTH)"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(COMPLIB_DEPTH)/promotions/oclutils"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(OPENCL_DEPTH)/runtime"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(OPENCL_DEPTH)/runtime/utils"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(COMPLIB_DEPTH)/utils"
|
||||
GCPPFLAGS += $(INCSWITCH) "$(OPENCL_DEPTH)/api/opencl/khronos/headers/opencl2.0"
|
||||
|
||||
# Do we build the 0.9 version?
|
||||
ifeq ($(BUILD_VERSION_0_9), 1)
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "os/alloc.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace amd {
|
||||
|
||||
void*
|
||||
AlignedMemory::allocate(size_t size, size_t alignment)
|
||||
{
|
||||
return Os::alignedMalloc(size, alignment);
|
||||
}
|
||||
|
||||
void*
|
||||
GuardedMemory::allocate(size_t size, size_t alignment, size_t guardSize)
|
||||
{
|
||||
size_t sizeToAllocate = guardSize + alignment;
|
||||
sizeToAllocate += size + guardSize + Os::pageSize();
|
||||
|
||||
sizeToAllocate = amd::alignUp(sizeToAllocate, Os::pageSize());
|
||||
address userHostMemGuarded = Os::reserveMemory(NULL, sizeToAllocate);
|
||||
if (!userHostMemGuarded || !Os::commitMemory(
|
||||
userHostMemGuarded, sizeToAllocate, Os::MEM_PROT_RW)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
address userHostMem = userHostMemGuarded + sizeToAllocate;
|
||||
userHostMem = amd::alignDown(userHostMem - guardSize, Os::pageSize());
|
||||
|
||||
// Protect the guard pages after the end of the users's buffer.
|
||||
if (!Os::protectMemory(userHostMem, guardSize, Os::MEM_PROT_NONE)) {
|
||||
fatal("Protect memory (up) failed");
|
||||
}
|
||||
|
||||
userHostMem = userHostMem - size;
|
||||
userHostMem = amd::alignDown(userHostMem, alignment);
|
||||
// Write the actual size allocated including all the guard pages,
|
||||
// alignment, page file size... as well as the size of guarded byte
|
||||
// count before the beginning of the user's buffer.
|
||||
size_t* temp = reinterpret_cast<size_t*>(userHostMem);
|
||||
*--temp = sizeToAllocate;
|
||||
*--temp = userHostMem - userHostMemGuarded;
|
||||
|
||||
// Protect the guard pages before the beginning of the user's buffer.
|
||||
if (!Os::protectMemory(userHostMemGuarded, guardSize, Os::MEM_PROT_NONE)) {
|
||||
fatal("Protect memory (down) failed");
|
||||
}
|
||||
|
||||
return userHostMem;
|
||||
}
|
||||
|
||||
void
|
||||
AlignedMemory::deallocate(void* ptr)
|
||||
{
|
||||
Os::alignedFree(ptr);
|
||||
}
|
||||
|
||||
void
|
||||
GuardedMemory::deallocate(void* ptr)
|
||||
{
|
||||
size_t* userHostMem = static_cast<size_t*>(ptr);
|
||||
|
||||
size_t size = *--userHostMem;
|
||||
size_t offset = *--userHostMem;
|
||||
|
||||
Os::releaseMemory(static_cast<address>(ptr) - offset, size);
|
||||
}
|
||||
|
||||
void*
|
||||
HeapObject::operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void
|
||||
HeapObject::operator delete(void* obj)
|
||||
{
|
||||
free(obj);
|
||||
}
|
||||
|
||||
|
||||
} // namespace amd
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef ALLOC_HPP_
|
||||
#define ALLOC_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
|
||||
namespace amd {
|
||||
|
||||
class AlignedMemory : public AllStatic
|
||||
{
|
||||
public:
|
||||
static void* allocate(size_t size, size_t alignment);
|
||||
|
||||
static void deallocate(void* ptr);
|
||||
};
|
||||
|
||||
class GuardedMemory : public AllStatic
|
||||
{
|
||||
public:
|
||||
static void* allocate(size_t size, size_t alignment, size_t guardSize);
|
||||
|
||||
static void deallocate(void* ptr);
|
||||
};
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*ALLOC_HPP_*/
|
||||
@@ -1,145 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "os/os.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
#else // !_WIN32
|
||||
# include <time.h>
|
||||
# include <unistd.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
#if defined(ATI_ARCH_X86)
|
||||
#include <xmmintrin.h> // for _mm_pause
|
||||
#endif // ATI_ARCH_X86
|
||||
|
||||
namespace amd {
|
||||
|
||||
void*
|
||||
Os::loadLibrary(const char* libraryname)
|
||||
{
|
||||
void* handle = Os::loadLibrary_(libraryname);
|
||||
if (handle != NULL) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Try with the system library prefix and extension instead.
|
||||
std::string str = libraryname;
|
||||
|
||||
size_t namestart = str.rfind(fileSeparator());
|
||||
namestart = (namestart != std::string::npos) ? namestart + 1 : 0;
|
||||
|
||||
const char* prefix = Os::libraryPrefix();
|
||||
if (prefix != NULL
|
||||
&& str.compare(namestart, strlen(prefix), prefix) == 0) {
|
||||
// It is alread present, not need to prepend it.
|
||||
prefix = NULL;
|
||||
}
|
||||
size_t dot = str.rfind('.');
|
||||
if (dot != std::string::npos) {
|
||||
// check that the dot was on the filename not a dir name.
|
||||
if (namestart < dot) {
|
||||
// strip the previous extension.
|
||||
str.resize(dot);
|
||||
}
|
||||
}
|
||||
if (prefix != NULL && prefix[0] != '\0') {
|
||||
str.insert(namestart, prefix);
|
||||
}
|
||||
str.append(Os::libraryExtension());
|
||||
|
||||
handle = Os::loadLibrary_(str.c_str());
|
||||
if (handle != NULL || str.find(fileSeparator()) != std::string::npos) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Try to find the lib in the current directory.
|
||||
return Os::loadLibrary((std::string(".") + fileSeparator()
|
||||
+ std::string(libraryname)).c_str());
|
||||
}
|
||||
|
||||
size_t Os::pageSize_ = 0;
|
||||
|
||||
int Os::processorCount_ = 0;
|
||||
|
||||
void
|
||||
Os::spinPause()
|
||||
{
|
||||
#if defined(ATI_ARCH_X86)
|
||||
_mm_pause();
|
||||
#elif defined(__ARM_ARCH_7A__)
|
||||
__asm__ __volatile__("yield");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Os::sleep(long n)
|
||||
{
|
||||
// FIXME_lmoriche: Should be nano-seconds not seconds.
|
||||
#ifdef _WIN32
|
||||
::Sleep(n);
|
||||
#else // !_WIN32
|
||||
time_t seconds = (time_t) n / 1000;
|
||||
long nanoseconds = ((long) n - seconds * 1000) * 1000000;
|
||||
timespec ts = { seconds, nanoseconds };
|
||||
::nanosleep(&ts, NULL);
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
void
|
||||
Os::touchStackPages(address bottom, address top)
|
||||
{
|
||||
top = alignDown(top, pageSize_) - pageSize_;
|
||||
while (top >= bottom) {
|
||||
*top = 0;
|
||||
top -= pageSize_;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Os::skipIDIV(address& pc)
|
||||
{
|
||||
address insn = pc;
|
||||
if (insn[0] == 0x66) { // LCP prefix
|
||||
insn += 1;
|
||||
}
|
||||
if ((insn[0] & 0xf0) == 0x40) { // REX prefix
|
||||
insn += 1;
|
||||
}
|
||||
if (insn[0] == 0xf6 || insn[0] == 0xf7) { // IDIV
|
||||
// This is a DivisionError: skip the insn and resume execution
|
||||
char mod = insn[1] >> 6;
|
||||
char rm = insn[1] & 0x7;
|
||||
insn += 2; // skip opcode and mod/rm
|
||||
|
||||
if (rm == 0x4 && mod != 0x3) {
|
||||
insn += 1; // sib follows mod/rm
|
||||
}
|
||||
|
||||
if ((mod == 0x0 && rm == 0x5) || mod == 0x2) {
|
||||
insn += 4; // disp32
|
||||
}
|
||||
else if (mod == 0x1) {
|
||||
insn += 1; // disp8
|
||||
}
|
||||
pc = insn;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Os::setThreadAffinity(const void* handle, unsigned int cpu)
|
||||
{
|
||||
ThreadAffinityMask mask;
|
||||
mask.set(cpu);
|
||||
setThreadAffinity(handle, mask);
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
@@ -1,519 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef OS_HPP_
|
||||
#define OS_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <sched.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <Basetsd.h> // For KAFFINITY
|
||||
#endif // _WIN32
|
||||
|
||||
// Smallest supported VM page size.
|
||||
#define MIN_PAGE_SHIFT 12
|
||||
#define MIN_PAGE_SIZE (1UL << MIN_PAGE_SHIFT)
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Os Operating System Abstraction
|
||||
*
|
||||
* \copydoc amd::Os
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
class Thread; // For Os::createOsThread()
|
||||
|
||||
class Os : AllStatic
|
||||
{
|
||||
public:
|
||||
enum MemProt
|
||||
{
|
||||
MEM_PROT_NONE = 0,
|
||||
MEM_PROT_READ,
|
||||
MEM_PROT_RW,
|
||||
MEM_PROT_RWX
|
||||
};
|
||||
|
||||
class ThreadAffinityMask
|
||||
{
|
||||
friend class Os;
|
||||
private:
|
||||
#if defined(__linux__)
|
||||
cpu_set_t mask_;
|
||||
#else // _WIN32
|
||||
#if !defined(_WIN32)
|
||||
typedef uint KAFFINITY;
|
||||
#endif
|
||||
KAFFINITY mask_[512 / sizeof(KAFFINITY)];
|
||||
#endif
|
||||
|
||||
public:
|
||||
ThreadAffinityMask() { init(); }
|
||||
|
||||
inline void init();
|
||||
inline void set(uint cpu);
|
||||
inline void clear(uint cpu);
|
||||
inline bool isSet(uint cpu) const;
|
||||
inline bool isEmpty() const;
|
||||
inline uint countSet() const;
|
||||
|
||||
inline uint getFirstSet() const;
|
||||
inline uint getNextSet(uint cpu) const;
|
||||
|
||||
#if defined(__linux__)
|
||||
inline void set(const cpu_set_t& mask);
|
||||
inline void clear(const cpu_set_t& mask);
|
||||
inline void adjust(cpu_set_t& mask) const;
|
||||
inline cpu_set_t& getNative() { return mask_; }
|
||||
#else
|
||||
inline void set(size_t group, KAFFINITY affinity);
|
||||
inline void adjust(size_t group, KAFFINITY& affinity) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
static const size_t FILE_PATH_MAX_LENGTH = 1024;
|
||||
|
||||
static size_t pageSize_; //!< The default os page size.
|
||||
static int processorCount_; //!< The number of active processors.
|
||||
|
||||
private:
|
||||
//! Load the shared library named by \a filename
|
||||
static void* loadLibrary_(const char* filename);
|
||||
|
||||
public:
|
||||
//! Initialize the Os package.
|
||||
static bool init();
|
||||
//! Tear down the Os package.
|
||||
static void tearDown();
|
||||
|
||||
// Topology helper routines:
|
||||
//
|
||||
|
||||
//! Return the number of active processors in the system.
|
||||
inline static int processorCount();
|
||||
|
||||
#if defined(ATI_ARCH_X86)
|
||||
//! Query the processor information about supported features and CPU type.
|
||||
static void cpuid(int regs[4], int info);
|
||||
//! Get value of extended control register
|
||||
static uint64_t xgetbv(uint32_t which);
|
||||
#endif // ATI_ARCH_X86
|
||||
|
||||
// Stack helper routines:
|
||||
//
|
||||
|
||||
//! Return the current stack base and size information.
|
||||
static void currentStackInfo(address* base, size_t *size);
|
||||
|
||||
//! Return the value of the current stack pointer.
|
||||
static NOT_WIN64(inline) address currentStackPtr();
|
||||
//! Set the value of the current stack pointer.
|
||||
static WIN64_ONLY(inline) void WINDOWS_ONLY(__stdcall/*callee cleanup*/)
|
||||
setCurrentStackPtr(address sp);
|
||||
//! Touches all stack pages between [bottom,top[
|
||||
static void touchStackPages(address bottom, address top);
|
||||
|
||||
// Thread routines:
|
||||
//
|
||||
|
||||
//! Create a native thread and link it to the given OsThread.
|
||||
static const void* createOsThread(Thread* osThread);
|
||||
//! Set the thread's affinity to the given cpu ordinal.
|
||||
static void setThreadAffinity(const void* handle, unsigned int cpu);
|
||||
//! Set the thread's affinity to the given cpu mask.
|
||||
static void setThreadAffinity(const void* handle, const ThreadAffinityMask& mask);
|
||||
//! Set the currently running thread's name.
|
||||
static void setCurrentThreadName(const char* name);
|
||||
//! Check if the thread is alive
|
||||
static bool isThreadAlive(const Thread& osThread);
|
||||
|
||||
//! Sleep for n milli-seconds.
|
||||
static void sleep(long n);
|
||||
//! Yield to threads of the same or lower priority
|
||||
static void yield();
|
||||
//! Execute a pause instruction (for spin loops).
|
||||
static void spinPause();
|
||||
|
||||
// Memory routines:
|
||||
//
|
||||
|
||||
//! Return the default os page size.
|
||||
inline static size_t pageSize();
|
||||
//! Return the amount of host total physical memory in bytes.
|
||||
static uint64_t hostTotalPhysicalMemory();
|
||||
|
||||
//! Reserve a chunk of memory (priv | anon | noreserve).
|
||||
static address reserveMemory(address start, size_t size, size_t alignment = 0, MemProt prot = MEM_PROT_NONE);
|
||||
//! Release a chunk of memory reserved with reserveMemory.
|
||||
static bool releaseMemory(void* addr, size_t size);
|
||||
//! Commit a chunk of memory previously reserved with reserveMemory.
|
||||
static bool commitMemory(void* addr, size_t size, MemProt prot = MEM_PROT_NONE);
|
||||
//! Uncommit a chunk of memory previously committed with commitMemory.
|
||||
static bool uncommitMemory(void* addr, size_t size);
|
||||
//! Set the page protections for the given memory region.
|
||||
static bool protectMemory(void* addr, size_t size, MemProt prot);
|
||||
|
||||
//! Allocate an aligned chunk of memory.
|
||||
static void* alignedMalloc(size_t size, size_t alignment);
|
||||
//! Deallocate an aligned chunk of memory.
|
||||
static void alignedFree(void* mem);
|
||||
|
||||
//! Platform-specific optimized memcpy()
|
||||
static void* fastMemcpy(void *dest, const void *src, size_t n);
|
||||
|
||||
// File/Path helper routines:
|
||||
//
|
||||
|
||||
//! Return the shared library extension string.
|
||||
static const char* libraryExtension();
|
||||
//! Return the shared library prefix string.
|
||||
static const char* libraryPrefix();
|
||||
//! Return the object extension string.
|
||||
static const char* objectExtension();
|
||||
//! Return the file separator char.
|
||||
static char fileSeparator();
|
||||
//! Return the path separator char.
|
||||
static char pathSeparator();
|
||||
//! Return whether the path exists
|
||||
static bool pathExists(const std::string& path);
|
||||
//! Create the path if it does not exist
|
||||
static bool createPath(const std::string& path);
|
||||
//! Remove the path if it is empty
|
||||
static bool removePath(const std::string& path);
|
||||
//! Printf re-implementation (due to MS CRT problem)
|
||||
static int printf(const char*fmt,...);
|
||||
/*! \brief Invokes the command processor for the command execution
|
||||
*
|
||||
* \result Returns the operation result
|
||||
*/
|
||||
static int systemCall(
|
||||
const std::string& command); //!< command for execution
|
||||
|
||||
/*! \brief Retrieves a string containing the value
|
||||
* of the environment variable
|
||||
*
|
||||
* \result Returns the environment variable value
|
||||
*/
|
||||
static std::string getEnvironment(
|
||||
const std::string& name); //!< the environment variable's name
|
||||
|
||||
/*! \brief Retrieves the path of the directory designated for temporary
|
||||
* files
|
||||
*
|
||||
* \result Returns the temporary path
|
||||
*/
|
||||
static std::string getTempPath();
|
||||
|
||||
/*! \brief Creates a name for a temporary file
|
||||
*
|
||||
* \result Returns the name of temporary file
|
||||
*/
|
||||
static std::string getTempFileName();
|
||||
|
||||
//! Deletes file
|
||||
static int unlink(const std::string& path);
|
||||
|
||||
// Library routines:
|
||||
//
|
||||
typedef bool (*SymbolCallback)(std::string, const void*, void*);
|
||||
|
||||
//! Load the shared library named by \a filename
|
||||
static void* loadLibrary(const char* filename);
|
||||
//! Unload the shared library.
|
||||
static void unloadLibrary(void* handle);
|
||||
//! Return the address of the function identified by \a name.
|
||||
static void* getSymbol(void* handle, const char* name);
|
||||
//! Get all the __kernel functions in the given shared library.
|
||||
static bool iterateSymbols(void* handle, SymbolCallback func, void* data);
|
||||
|
||||
// Time routines:
|
||||
//
|
||||
|
||||
//! Return the current system time counter in nanoseconds.
|
||||
static uint64_t timeNanos();
|
||||
//! Return the system timer's resolution in nanoseconds.
|
||||
static uint64_t timerResolutionNanos();
|
||||
//! Return the timeNanos starting point offset to Epoch.
|
||||
static uint64_t offsetToEpochNanos();
|
||||
|
||||
// X86 Instructions helpers:
|
||||
//
|
||||
|
||||
//! Skip an IDIV (F6/F7) instruction and return a pointer to the next insn.
|
||||
static bool skipIDIV(address& insn);
|
||||
|
||||
// return gloabal memory size to be assigned to device info
|
||||
static size_t getPhysicalMemSize();
|
||||
|
||||
//! get Application file name
|
||||
static std::string getAppFileName();
|
||||
};
|
||||
|
||||
/*@}*/
|
||||
|
||||
inline size_t
|
||||
Os::pageSize()
|
||||
{
|
||||
assert(pageSize_ != 0 && "runtime is not initialized");
|
||||
return pageSize_;
|
||||
}
|
||||
|
||||
inline int
|
||||
Os::processorCount()
|
||||
{
|
||||
return processorCount_;
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
extern "C" void _Os_setCurrentStackPtr(address sp);
|
||||
|
||||
ALWAYSINLINE void
|
||||
Os::setCurrentStackPtr(address sp)
|
||||
{
|
||||
_Os_setCurrentStackPtr(sp);
|
||||
}
|
||||
|
||||
#else // !_WIN64
|
||||
|
||||
ALWAYSINLINE address
|
||||
Os::currentStackPtr()
|
||||
{
|
||||
intptr_t value;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
__asm__ __volatile__ (
|
||||
# if defined(ATI_ARCH_X86)
|
||||
LP64_SWITCH("movl %%esp", "movq %%rsp") ",%0" : "=r"(value)
|
||||
# elif defined(ATI_ARCH_ARM)
|
||||
"mov %0,sp" : "=r"(value)
|
||||
# endif
|
||||
);
|
||||
#else // !__GNUC__
|
||||
__asm mov value, esp;
|
||||
#endif // !__GNUC__
|
||||
|
||||
return (address)value;
|
||||
}
|
||||
|
||||
#endif // !_WIN64
|
||||
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::init()
|
||||
{
|
||||
CPU_ZERO(&mask_);
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::set(uint cpu)
|
||||
{
|
||||
CPU_SET(cpu, &mask_);
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::clear(uint cpu)
|
||||
{
|
||||
CPU_CLR(cpu, &mask_);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Os::ThreadAffinityMask::isSet(uint cpu) const
|
||||
{
|
||||
return CPU_ISSET(cpu, &mask_);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Os::ThreadAffinityMask::isEmpty() const
|
||||
{
|
||||
const uint32_t* bits = (const uint32_t*)mask_.__bits;
|
||||
for (uint i = 0; i < sizeof(mask_.__bits) / sizeof(uint32_t); ++i) {
|
||||
if (bits[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::set(const cpu_set_t& mask)
|
||||
{
|
||||
mask_ = mask;
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::clear(const cpu_set_t& mask)
|
||||
{
|
||||
const uint32_t* bitsClear = (const uint32_t*)mask.__bits;
|
||||
uint32_t* bits = (uint32_t*)mask_.__bits;
|
||||
for (uint i = 0; i < sizeof(mask_.__bits) / sizeof(uint32_t); ++i) {
|
||||
bits[i] &= ~bitsClear[i];
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::adjust(cpu_set_t& mask) const
|
||||
{
|
||||
uint32_t* bitsOut = (uint32_t*)mask.__bits;
|
||||
const uint32_t* bits = (const uint32_t*)mask_.__bits;
|
||||
for (uint i = 0; i < sizeof(mask_.__bits) / sizeof(uint32_t); ++i) {
|
||||
bitsOut[i] &= bits[i];
|
||||
}
|
||||
}
|
||||
|
||||
inline uint
|
||||
Os::ThreadAffinityMask::countSet() const
|
||||
{
|
||||
uint count = 0;
|
||||
const uint32_t* bits = (const uint32_t*)mask_.__bits;
|
||||
for (uint i = 0; i < sizeof(mask_.__bits) / sizeof(uint32_t); ++i) {
|
||||
count += countBitsSet(bits[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
inline uint
|
||||
Os::ThreadAffinityMask::getFirstSet() const
|
||||
{
|
||||
const uint32_t* bits = (const uint32_t*)mask_.__bits;
|
||||
for (uint i = 0; i < sizeof(mask_.__bits) / sizeof(uint32_t); ++i) {
|
||||
if (bits[i] != 0) {
|
||||
return leastBitSet(bits[i]) + (i * (8*sizeof(uint32_t)));
|
||||
}
|
||||
}
|
||||
return (uint)-1;
|
||||
}
|
||||
|
||||
inline uint
|
||||
Os::ThreadAffinityMask::getNextSet(uint cpu) const
|
||||
{
|
||||
const uint32_t* bits = (const uint32_t*)mask_.__bits;
|
||||
++cpu;
|
||||
uint j = cpu % (8*sizeof(uint32_t));
|
||||
for (uint i = cpu / (8*sizeof(uint32_t));
|
||||
i < sizeof(mask_.__bits) / sizeof(uint32_t); ++i) {
|
||||
if (bits[i] != 0) {
|
||||
for (; j < (8*sizeof(uint32_t)); ++j) {
|
||||
if (0 != (bits[i] & ((uint32_t)1 << j))) {
|
||||
return i * (8*sizeof(uint32_t)) + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
return (uint)-1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::init()
|
||||
{
|
||||
for (uint i = 0; i < sizeof(mask_) / sizeof(KAFFINITY); ++i) {
|
||||
mask_[i] = (KAFFINITY)0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::set(uint cpu)
|
||||
{
|
||||
mask_[cpu / (8*sizeof(KAFFINITY))] |=
|
||||
(KAFFINITY)1 << (cpu % (8*sizeof(KAFFINITY)));
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::clear(uint cpu)
|
||||
{
|
||||
mask_[cpu / (8*sizeof(KAFFINITY))] &=
|
||||
~( (KAFFINITY)1 << (cpu % (8*sizeof(KAFFINITY))) );
|
||||
}
|
||||
|
||||
inline bool
|
||||
Os::ThreadAffinityMask::isSet(uint cpu) const
|
||||
{
|
||||
return (KAFFINITY)0 != (mask_[cpu / (8*sizeof(KAFFINITY))] &
|
||||
((KAFFINITY)1 << (cpu % (8*sizeof(KAFFINITY)))));
|
||||
}
|
||||
|
||||
inline bool
|
||||
Os::ThreadAffinityMask::isEmpty() const
|
||||
{
|
||||
for (uint i = 0; i < sizeof(mask_) / sizeof(KAFFINITY); ++i) {
|
||||
if (mask_[i] != (KAFFINITY)0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::set(size_t group, KAFFINITY affinity)
|
||||
{
|
||||
mask_[group] |= affinity;
|
||||
}
|
||||
|
||||
inline void
|
||||
Os::ThreadAffinityMask::adjust(size_t group, KAFFINITY& affinity) const
|
||||
{
|
||||
affinity &= mask_[group];
|
||||
}
|
||||
|
||||
inline uint
|
||||
Os::ThreadAffinityMask::countSet() const
|
||||
{
|
||||
uint count = 0;
|
||||
for (uint i = 0; i < sizeof(mask_) / sizeof(KAFFINITY); ++i) {
|
||||
count += countBitsSet(mask_[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
inline uint
|
||||
Os::ThreadAffinityMask::getFirstSet() const
|
||||
{
|
||||
for (uint i = 0; i < sizeof(mask_) / sizeof(KAFFINITY); ++i) {
|
||||
if (mask_[i] != 0) {
|
||||
return leastBitSet(mask_[i]) + (i * (8*sizeof(KAFFINITY)));
|
||||
}
|
||||
}
|
||||
return (uint)-1;
|
||||
}
|
||||
|
||||
inline uint
|
||||
Os::ThreadAffinityMask::getNextSet(uint cpu) const
|
||||
{
|
||||
++cpu;
|
||||
uint j = cpu % (8*sizeof(KAFFINITY));
|
||||
for (uint i = cpu / (8*sizeof(KAFFINITY));
|
||||
i < sizeof(mask_) / sizeof(KAFFINITY); ++i) {
|
||||
if (mask_[i] != 0) {
|
||||
for (; j < (8*sizeof(KAFFINITY)); ++j) {
|
||||
if (0 != (mask_[i] & ((KAFFINITY)1 << j))) {
|
||||
return i * (8*sizeof(KAFFINITY)) + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
return (uint)-1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*OS_HPP_*/
|
||||
@@ -1,888 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
#include "os/os.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include <link.h>
|
||||
#include <time.h>
|
||||
#include <elf.h>
|
||||
#ifndef DT_GNU_HASH
|
||||
# define DT_GNU_HASH 0x6ffffef5
|
||||
#endif // DT_GNU_HASH
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <cstring> // for strncmp
|
||||
#include <cstdlib>
|
||||
#include <cstdio> // for tempnam
|
||||
#include <limits.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef ANDROID
|
||||
//#include <sys/ucontext.h>
|
||||
#endif
|
||||
|
||||
namespace amd {
|
||||
|
||||
static struct sigaction oldSigAction;
|
||||
|
||||
static bool
|
||||
callOldSignalHandler(int sig, siginfo_t* info, void* ptr)
|
||||
{
|
||||
if (oldSigAction.sa_handler == SIG_DFL) {
|
||||
// no signal handler was previously installed.
|
||||
return false;
|
||||
}
|
||||
else if (oldSigAction.sa_handler != SIG_IGN) {
|
||||
|
||||
if ((oldSigAction.sa_flags & SA_NODEFER) == 0) {
|
||||
sigaddset(&oldSigAction.sa_mask, sig);
|
||||
}
|
||||
|
||||
void (*handler)(int) = oldSigAction.sa_handler;
|
||||
if (oldSigAction.sa_flags & SA_RESETHAND) {
|
||||
oldSigAction.sa_handler = SIG_DFL;
|
||||
}
|
||||
|
||||
sigset_t savedSigSet;
|
||||
pthread_sigmask(SIG_SETMASK, &oldSigAction.sa_mask, &savedSigSet);
|
||||
|
||||
if (oldSigAction.sa_flags & SA_SIGINFO) {
|
||||
oldSigAction.sa_sigaction(sig, info, ptr);
|
||||
}
|
||||
else {
|
||||
handler(sig);
|
||||
}
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &savedSigSet, NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
divisionErrorHandler(int sig, siginfo_t* info, void* ptr)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
assert(false && "ucontext_t undefined for Android");
|
||||
return;
|
||||
#else
|
||||
assert(info != NULL && ptr != NULL && "just checking");
|
||||
ucontext_t* uc = (ucontext_t*) ptr;
|
||||
address insn;
|
||||
|
||||
#if defined(ATI_ARCH_X86)
|
||||
insn = (address)uc->uc_mcontext.gregs[LP64_SWITCH(REG_EIP,REG_RIP)];
|
||||
#else
|
||||
assert(!"Unimplemented");
|
||||
#endif
|
||||
|
||||
if(Thread::current()->isWorkerThread()) {
|
||||
if (Os::skipIDIV(insn)) {
|
||||
#if defined(ATI_ARCH_X86)
|
||||
uc->uc_mcontext.gregs[LP64_SWITCH(REG_EIP,REG_RIP)] = (greg_t)insn;
|
||||
#else
|
||||
assert(!"Unimplemented");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Call the chained signal handler
|
||||
if (callOldSignalHandler(sig, info, ptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::cerr << "Unhandled signal in divisionErrorHandler()" << std::endl;
|
||||
::abort();
|
||||
#endif // !ANDROID
|
||||
}
|
||||
|
||||
typedef int (*pthread_setaffinity_fn)(pthread_t, size_t , const cpu_set_t *);
|
||||
static pthread_setaffinity_fn pthread_setaffinity_fptr;
|
||||
|
||||
static void init() __attribute__((constructor(101)));
|
||||
static void init() { Os::init(); }
|
||||
|
||||
bool
|
||||
Os::init()
|
||||
{
|
||||
static bool initialized_ = false;
|
||||
|
||||
// We could use pthread_once here:
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
initialized_ = true;
|
||||
|
||||
pageSize_ = (size_t) ::sysconf(_SC_PAGESIZE);
|
||||
processorCount_ = ::sysconf(_SC_NPROCESSORS_CONF);
|
||||
|
||||
// Install a SIGFPE signal handler @todo: Chain the handlers
|
||||
struct sigaction sa;
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sa.sa_sigaction = divisionErrorHandler;
|
||||
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
||||
|
||||
if (sigaction(SIGFPE, &sa, &oldSigAction) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_setaffinity_fptr = (pthread_setaffinity_fn)
|
||||
dlsym(RTLD_NEXT, "pthread_setaffinity_np");
|
||||
|
||||
return Thread::init();
|
||||
}
|
||||
|
||||
static void __exit() __attribute__((destructor(101)));
|
||||
static void __exit() { Os::tearDown(); }
|
||||
|
||||
void
|
||||
Os::tearDown()
|
||||
{
|
||||
Thread::tearDown();
|
||||
}
|
||||
|
||||
bool
|
||||
Os::iterateSymbols(void* handle, Os::SymbolCallback callback, void* data)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
assert(false && "dlinfo undefined for Android in dlfcn.h");
|
||||
return false;
|
||||
#else
|
||||
const char magic[] = "__OpenCL_";
|
||||
const size_t len = sizeof(magic) - 1;
|
||||
|
||||
struct link_map *link_map = NULL;
|
||||
if (::dlinfo(handle, RTLD_DI_LINKMAP, &link_map) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(link_map != NULL && "just checking");
|
||||
const ElfW(Dyn)* dyn = (ElfW(Dyn)*)(link_map->l_ld);
|
||||
|
||||
const Elf32_Word* gnuhash = NULL;
|
||||
const Elf_Symndx* hash = NULL;
|
||||
const ElfW(Sym)* symbols = NULL;
|
||||
const char* stringTable = NULL;
|
||||
size_t tableSize = 0;
|
||||
|
||||
// Search for the string table address and size.
|
||||
while (dyn->d_tag != DT_NULL) {
|
||||
switch (dyn->d_tag) {
|
||||
case DT_HASH:
|
||||
hash = (Elf_Symndx*) dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_GNU_HASH:
|
||||
gnuhash = (Elf32_Word*) dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
symbols = (ElfW(Sym)*) dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_STRTAB:
|
||||
stringTable = (const char*) dyn->d_un.d_ptr;
|
||||
break;
|
||||
case DT_STRSZ:
|
||||
tableSize = dyn->d_un.d_val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++dyn;
|
||||
}
|
||||
if (stringTable == NULL || tableSize == 0 || symbols == NULL
|
||||
|| (hash == NULL && gnuhash == NULL)) {
|
||||
// Could not find the string table
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gnuhash == NULL) {
|
||||
// Read the defined symbols out of the classic SYSV hashtable.
|
||||
|
||||
Elf_Symndx nbuckets = hash[1];
|
||||
for (Elf_Symndx i = 0; i < nbuckets; ++i) {
|
||||
|
||||
if (symbols[i].st_shndx == SHN_UNDEF
|
||||
&& symbols[i].st_value == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* name = &stringTable[symbols[i].st_name];
|
||||
if (::strncmp(name, magic, len) == 0) {
|
||||
callback(name, (const void*)
|
||||
(link_map->l_addr + symbols[i].st_value), data);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read the defined symbols out of the GNU hashtable.
|
||||
|
||||
Elf_Symndx nbuckets = gnuhash[0];
|
||||
Elf32_Word bias = gnuhash[1];
|
||||
Elf32_Word nwords = gnuhash[2];
|
||||
const Elf32_Word* buckets = &gnuhash[4 + __ELF_NATIVE_CLASS / 32 * nwords];
|
||||
const Elf32_Word* chain0 = &buckets[nbuckets] - bias;
|
||||
|
||||
for (Elf_Symndx i = 0; i < nbuckets; ++i) {
|
||||
size_t index = buckets[i];
|
||||
const Elf32_Word *hasharr = &chain0[index];
|
||||
do {
|
||||
if (symbols[index].st_shndx != SHN_UNDEF
|
||||
|| symbols[index].st_value != 0) {
|
||||
const char* name = &stringTable[symbols[index].st_name];
|
||||
if (::strncmp(name, magic, len) == 0) {
|
||||
callback(name, (const void*)
|
||||
(link_map->l_addr + symbols[index].st_value), data);
|
||||
}
|
||||
}
|
||||
++index;
|
||||
} while ((*hasharr++ & 1) == 0);
|
||||
}
|
||||
|
||||
#endif // !ANDROID
|
||||
return true;
|
||||
}
|
||||
|
||||
void*
|
||||
Os::loadLibrary_(const char *filename)
|
||||
{
|
||||
return (*filename == '\0') ? NULL : ::dlopen(filename, RTLD_LAZY);
|
||||
}
|
||||
|
||||
void
|
||||
Os::unloadLibrary(void* handle)
|
||||
{
|
||||
::dlclose(handle);
|
||||
}
|
||||
|
||||
void*
|
||||
Os::getSymbol(void* handle, const char* name)
|
||||
{
|
||||
return ::dlsym(handle, name);
|
||||
}
|
||||
|
||||
static inline int
|
||||
memProtToOsProt(Os::MemProt prot)
|
||||
{
|
||||
switch (prot) {
|
||||
case Os::MEM_PROT_NONE: return PROT_NONE;
|
||||
case Os::MEM_PROT_READ: return PROT_READ;
|
||||
case Os::MEM_PROT_RW: return PROT_READ | PROT_WRITE;
|
||||
case Os::MEM_PROT_RWX: return PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
default: break;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return -1;
|
||||
}
|
||||
|
||||
address
|
||||
Os::reserveMemory(address start, size_t size, size_t alignment, MemProt prot)
|
||||
{
|
||||
size = alignUp(size, pageSize());
|
||||
alignment = std::max(pageSize(), alignUp(alignment, pageSize()));
|
||||
assert(isPowerOfTwo(alignment) && "not a power of 2");
|
||||
|
||||
size_t requested = size + alignment - pageSize();
|
||||
address mem = (address) ::mmap(start, requested, memProtToOsProt(prot),
|
||||
MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, 0, 0);
|
||||
|
||||
// check for out of memory
|
||||
if (mem == NULL) return NULL;
|
||||
|
||||
address aligned = alignUp(mem, alignment);
|
||||
|
||||
// return the unused leading pages to the free state
|
||||
if (&aligned[0] != &mem[0]) {
|
||||
assert(&aligned[0] > &mem[0] && "check this code");
|
||||
if (::munmap(&mem[0], &aligned[0] - &mem[0]) != 0) {
|
||||
assert(!"::munmap failed");
|
||||
}
|
||||
}
|
||||
// return the unused trailing pages to the free state
|
||||
if (&aligned[size] != &mem[requested]) {
|
||||
assert(&aligned[size] < &mem[requested] && "check this code");
|
||||
if (::munmap(&aligned[size], &mem[requested] - &aligned[size]) != 0) {
|
||||
assert(!"::munmap failed");
|
||||
}
|
||||
}
|
||||
|
||||
return aligned;
|
||||
}
|
||||
|
||||
bool
|
||||
Os::releaseMemory(void* addr, size_t size)
|
||||
{
|
||||
assert(isMultipleOf(addr, pageSize()) && "not page aligned!");
|
||||
size = alignUp(size, pageSize());
|
||||
|
||||
return 0 == ::munmap(addr, size);
|
||||
}
|
||||
|
||||
bool
|
||||
Os::commitMemory(void* addr, size_t size, MemProt prot)
|
||||
{
|
||||
assert(isMultipleOf(addr, pageSize()) && "not page aligned!");
|
||||
size = alignUp(size, pageSize());
|
||||
|
||||
return ::mmap(addr, size, memProtToOsProt(prot),
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
|
||||
-1, 0) != MAP_FAILED;
|
||||
}
|
||||
|
||||
bool
|
||||
Os::uncommitMemory(void* addr, size_t size)
|
||||
{
|
||||
assert(isMultipleOf(addr, pageSize()) && "not page aligned!");
|
||||
size = alignUp(size, pageSize());
|
||||
|
||||
return ::mmap(addr, size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANONYMOUS,
|
||||
-1, 0) != MAP_FAILED;
|
||||
}
|
||||
|
||||
bool
|
||||
Os::protectMemory(void* addr, size_t size, MemProt prot)
|
||||
{
|
||||
assert(isMultipleOf(addr, pageSize()) && "not page aligned!");
|
||||
size = alignUp(size, pageSize());
|
||||
|
||||
return 0 == ::mprotect(addr, size, memProtToOsProt(prot));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Os::hostTotalPhysicalMemory()
|
||||
{
|
||||
static uint64_t totalPhys = 0;
|
||||
|
||||
if (totalPhys != 0) {
|
||||
return totalPhys;
|
||||
}
|
||||
|
||||
totalPhys = sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
||||
return totalPhys;
|
||||
}
|
||||
|
||||
void*
|
||||
Os::alignedMalloc(size_t size, size_t alignment)
|
||||
{
|
||||
void * ptr = NULL;
|
||||
if (0 == ::posix_memalign(&ptr, alignment, size)) {
|
||||
return ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Os::alignedFree(void *mem)
|
||||
{
|
||||
::free(mem);
|
||||
}
|
||||
|
||||
void
|
||||
Os::currentStackInfo(address* base, size_t *size)
|
||||
{
|
||||
// There could be some issue trying to get the pthread_attr of
|
||||
// the primordial thread if the pthread library is not present
|
||||
// at load time (a binary loads the OpenCL app/runtime dynamically.
|
||||
// We should look into this... -laurent
|
||||
|
||||
pthread_t self = ::pthread_self();
|
||||
|
||||
pthread_attr_t threadAttr;
|
||||
if (0 != ::pthread_getattr_np(self, &threadAttr)) {
|
||||
fatal("pthread_getattr_np() failed");
|
||||
}
|
||||
|
||||
if (0 != ::pthread_attr_getstack(&threadAttr,
|
||||
(void **) base, size)) {
|
||||
fatal("pthread_attr_getstack() failed");
|
||||
}
|
||||
*base += *size;
|
||||
|
||||
::pthread_attr_destroy(&threadAttr);
|
||||
|
||||
assert(Os::currentStackPtr() >= *base - *size
|
||||
&& Os::currentStackPtr() < *base
|
||||
&& "just checking");
|
||||
}
|
||||
|
||||
void
|
||||
Os::setCurrentThreadName(const char* name)
|
||||
{
|
||||
::prctl(PR_SET_NAME, name);
|
||||
}
|
||||
|
||||
|
||||
void*
|
||||
Thread::entry(Thread* thread)
|
||||
{
|
||||
sigset_t set;
|
||||
|
||||
sigfillset(&set);
|
||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGFPE);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
|
||||
return thread->main();
|
||||
}
|
||||
|
||||
bool
|
||||
Os::isThreadAlive(const Thread& thread)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const void*
|
||||
Os::createOsThread(amd::Thread* thread)
|
||||
{
|
||||
pthread_attr_t threadAttr;
|
||||
::pthread_attr_init(&threadAttr);
|
||||
|
||||
if (thread->stackSize_ != 0) {
|
||||
size_t guardsize = 0;
|
||||
if (0 != ::pthread_attr_getguardsize(&threadAttr,
|
||||
&guardsize)) {
|
||||
fatal("pthread_attr_getguardsize() failed");
|
||||
}
|
||||
::pthread_attr_setstacksize(&threadAttr, thread->stackSize_ + guardsize);
|
||||
}
|
||||
|
||||
// We never plan the use join, so free the resources now.
|
||||
::pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
pthread_t handle = 0;
|
||||
if (0 != ::pthread_create(&handle, &threadAttr,
|
||||
(void* (*)(void*)) &Thread::entry, thread)) {
|
||||
thread->setState(Thread::FAILED);
|
||||
}
|
||||
|
||||
::pthread_attr_destroy(&threadAttr);
|
||||
return reinterpret_cast<const void*>(handle);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Os::setThreadAffinity(const void* handle, const Os::ThreadAffinityMask& mask)
|
||||
{
|
||||
if (pthread_setaffinity_fptr != NULL) {
|
||||
pthread_setaffinity_fptr((pthread_t)handle, sizeof(cpu_set_t), &mask.mask_);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Os::yield()
|
||||
{
|
||||
::sched_yield();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Os::timeNanos()
|
||||
{
|
||||
struct timespec tp;
|
||||
::clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||
return (uint64_t) tp.tv_sec * (1000ULL*1000ULL*1000ULL)
|
||||
+ (uint64_t) tp.tv_nsec;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Os::timerResolutionNanos()
|
||||
{
|
||||
static uint64_t resolution = 0;
|
||||
if (resolution == 0) {
|
||||
struct timespec tp;
|
||||
::clock_getres(CLOCK_MONOTONIC, &tp);
|
||||
resolution = (uint64_t) tp.tv_sec * (1000ULL*1000ULL*1000ULL)
|
||||
+ (uint64_t) tp.tv_nsec;
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
Os::libraryExtension()
|
||||
{
|
||||
return MACOS_SWITCH(".dylib", ".so");
|
||||
}
|
||||
|
||||
const char*
|
||||
Os::libraryPrefix()
|
||||
{
|
||||
return "lib";
|
||||
}
|
||||
|
||||
const char*
|
||||
Os::objectExtension()
|
||||
{
|
||||
return ".o";
|
||||
}
|
||||
|
||||
char
|
||||
Os::fileSeparator()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
char
|
||||
Os::pathSeparator()
|
||||
{
|
||||
return ':';
|
||||
}
|
||||
|
||||
bool Os::pathExists(const std::string& path)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(path.c_str(), &st) != 0)
|
||||
return false;
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
bool Os::createPath(const std::string& path)
|
||||
{
|
||||
mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
|
||||
size_t pos = 0;
|
||||
while (true) {
|
||||
pos = path.find(fileSeparator(), pos);
|
||||
const std::string currPath = path.substr(0, pos);
|
||||
if (!currPath.empty() && !pathExists(currPath)) {
|
||||
int ret = mkdir(currPath.c_str(), mode);
|
||||
if (ret == -1) return false;
|
||||
}
|
||||
if (pos == std::string::npos) break;
|
||||
++pos;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Os::removePath(const std::string& path)
|
||||
{
|
||||
size_t pos = std::string::npos;
|
||||
bool removed =false;
|
||||
while (true) {
|
||||
const std::string currPath = path.substr(0, pos);
|
||||
if (!currPath.empty()) {
|
||||
int ret = rmdir(currPath.c_str());
|
||||
if (ret == -1) return removed;
|
||||
removed = true;
|
||||
}
|
||||
if (pos == 0) break;
|
||||
pos = path.rfind(fileSeparator(), pos == std::string::npos?pos:pos-1);
|
||||
if (pos == std::string::npos) break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Os::printf(const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
int len = ::vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Os::systemCall()
|
||||
// ================
|
||||
// Execute a program and return the program exitcode or -1 if there were problems.
|
||||
// The input argument 'command' is expected to be a space separated string of
|
||||
// command-line arguments with arguments containing spaces between double-quotes.
|
||||
//
|
||||
// In order to avoid duplication of memory, we use vfork()+exec(). vfork() has
|
||||
// potiential security risks; read the following for details:
|
||||
//
|
||||
// https://www.securecoding.cert.org/confluence/display/seccode/POS33-C.+Do+not+use+vfork()
|
||||
//
|
||||
// In spite of these risks, the alternatives (system() or fork()) create resource
|
||||
// issues when running conformance test_allocation which stretches the system
|
||||
// memory to its limits. Thus we will accept this compromise under the condition
|
||||
// that the runtime will soon remove any need to call out to external commands.
|
||||
//
|
||||
// Note that stdin/stdout/stderr of the command are sent to /dev/null.
|
||||
//
|
||||
int
|
||||
Os::systemCall(const std::string& command)
|
||||
{
|
||||
#if 1
|
||||
size_t len = command.size();
|
||||
char* cmd = new char[len + 1];
|
||||
fastMemcpy(cmd, command.c_str(), len);
|
||||
cmd[len] = 0;
|
||||
|
||||
// Split the command into arguments. This is a very
|
||||
// simple parser that only takes care of quotes and
|
||||
// doesn't support escaping with back-slash. In
|
||||
// the future, Os::systemCall() will either
|
||||
// disappear or it will be replaced with an
|
||||
// argc/argv interface. This parser also assumes
|
||||
// that if an argument is quoted, the whole
|
||||
// argument starts and ends with a double-quote.
|
||||
bool inQuote = false;
|
||||
int argLength = 0;
|
||||
int n = 0;
|
||||
char* cp = cmd;
|
||||
while(*cp) {
|
||||
switch(static_cast<int>(*cp)) {
|
||||
case ' ':
|
||||
if(inQuote) {
|
||||
++argLength;
|
||||
}
|
||||
else {
|
||||
*cp = '\0';
|
||||
argLength = 0;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if(inQuote) {
|
||||
inQuote = false;
|
||||
*cp = '\0';
|
||||
}
|
||||
else {
|
||||
inQuote = true;
|
||||
*cp = '\0';
|
||||
argLength = 1;
|
||||
++n;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(++argLength == 1) {
|
||||
++n;
|
||||
}
|
||||
break;
|
||||
}
|
||||
++cp;
|
||||
}
|
||||
|
||||
char** argv = new char*[n + 1];
|
||||
int argc = 0;
|
||||
cp = cmd;
|
||||
do {
|
||||
while('\0' == *cp) {
|
||||
++cp;
|
||||
}
|
||||
argv[argc++] = cp;
|
||||
while('\0' != *cp) {
|
||||
++cp;
|
||||
}
|
||||
} while(argc < n);
|
||||
argv[argc] = NULL;
|
||||
|
||||
int ret = -1;
|
||||
pid_t pid = vfork();
|
||||
if(0 == pid) {
|
||||
// Child. Redirect stdin/stdout/stderr to /dev/null
|
||||
int fdIn = open("/dev/null", O_RDONLY);
|
||||
int fdOut = open("/dev/null", O_WRONLY);
|
||||
if(0 <= fdIn || 0 <= fdOut) {
|
||||
dup2(fdIn, 0);
|
||||
dup2(fdOut, 1);
|
||||
dup2(fdOut, 2);
|
||||
|
||||
// Execute the program
|
||||
execvp(argv[0], argv);
|
||||
}
|
||||
_exit(-1);
|
||||
}
|
||||
else if(0 > pid) {
|
||||
// Can't vfork
|
||||
}
|
||||
else {
|
||||
// Parent - wait for program to complete and get exit code.
|
||||
int exitCode;
|
||||
if(0 <= waitpid(pid, &exitCode, 0)) {
|
||||
ret = exitCode;
|
||||
}
|
||||
}
|
||||
delete [] argv;
|
||||
delete [] cmd;
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return ::system(command.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string
|
||||
Os::getEnvironment(const std::string& name)
|
||||
{
|
||||
char* dstBuf;
|
||||
|
||||
dstBuf = ::getenv(name.c_str());
|
||||
if (dstBuf == NULL) {
|
||||
return std::string("");
|
||||
}
|
||||
return std::string(dstBuf);
|
||||
}
|
||||
|
||||
std::string
|
||||
Os::getTempPath()
|
||||
{
|
||||
std::string tempFolder = amd::Os::getEnvironment("TEMP");
|
||||
if (tempFolder.empty()) {
|
||||
tempFolder = amd::Os::getEnvironment("TMP");
|
||||
}
|
||||
|
||||
if (tempFolder.empty()) {
|
||||
tempFolder = "/tmp";;
|
||||
}
|
||||
return tempFolder;
|
||||
}
|
||||
|
||||
std::string
|
||||
Os::getTempFileName()
|
||||
{
|
||||
static std::atomic_size_t counter(0);
|
||||
|
||||
std::string tempPath = getTempPath();
|
||||
std::stringstream tempFileName;
|
||||
|
||||
tempFileName << tempPath << "/OCLC" << ::getpid() << 'T' << counter++;
|
||||
return tempFileName.str();
|
||||
}
|
||||
|
||||
int
|
||||
Os::unlink(const std::string& path)
|
||||
{
|
||||
return ::unlink(path.c_str());
|
||||
}
|
||||
|
||||
#if defined(ATI_ARCH_X86)
|
||||
void
|
||||
Os::cpuid(int regs[4], int info)
|
||||
{
|
||||
#ifdef _LP64
|
||||
__asm__ __volatile__ (
|
||||
"movq %%rbx, %%rsi;"
|
||||
"cpuid;"
|
||||
"xchgq %%rbx, %%rsi;"
|
||||
: "=a" (regs[0]), "=S" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
|
||||
: "a" (info));
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"movl %%ebx, %%esi;"
|
||||
"cpuid;"
|
||||
"xchgl %%ebx, %%esi;"
|
||||
: "=a" (regs[0]), "=S" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
|
||||
: "a" (info));
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Os::xgetbv(uint32_t ecx)
|
||||
{
|
||||
uint32_t eax, edx;
|
||||
|
||||
__asm__ __volatile__(
|
||||
".byte 0x0f,0x01,0xd0" // in case assembler doesn't recognize xgetbv
|
||||
: "=a"(eax), "=d"(edx)
|
||||
: "c"(ecx));
|
||||
|
||||
return ((uint64_t)edx << 32) | (uint64_t)eax;
|
||||
}
|
||||
#endif // ATI_ARCH_X86
|
||||
|
||||
void*
|
||||
Os::fastMemcpy(void *dest, const void *src, size_t n)
|
||||
{
|
||||
return memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Os::offsetToEpochNanos()
|
||||
{
|
||||
static uint64_t offset = 0;
|
||||
|
||||
if (offset != 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
struct timeval now;
|
||||
if (::gettimeofday(&now, NULL) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset = (now.tv_sec * UINT64_C(1000000) + now.tv_usec)
|
||||
* UINT64_C(1000) - timeNanos();
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void
|
||||
Os::setCurrentStackPtr(address sp)
|
||||
{
|
||||
sp -= sizeof(void*);
|
||||
*(void**) sp = __builtin_return_address(0);
|
||||
|
||||
#if defined(ATI_ARCH_ARM)
|
||||
assert(!"Unimplemented");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
#if !defined(OMIT_FRAME_POINTER)
|
||||
LP64_SWITCH("movl (%%ebp),%%ebp;","movq (%%rbp),%%rbp;")
|
||||
#endif // !OMIT_FRAME_POINTER
|
||||
LP64_SWITCH("movl %0,%%esp; ret;","movq %0,%%rsp; ret;")
|
||||
:: "r"(sp)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t Os::getPhysicalMemSize()
|
||||
{
|
||||
struct ::sysinfo si;
|
||||
|
||||
if (::sysinfo(&si) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (si.mem_unit == 0) {
|
||||
// Linux kernels prior to 2.3.23 return sizes in bytes.
|
||||
si.mem_unit = 1;
|
||||
}
|
||||
|
||||
return (size_t) si.totalram * si.mem_unit;
|
||||
}
|
||||
|
||||
std::string Os::getAppFileName()
|
||||
{
|
||||
std::unique_ptr<char[]> buff(new char[FILE_PATH_MAX_LENGTH]());
|
||||
|
||||
if (readlink("/proc/self/exe", buff.get(), FILE_PATH_MAX_LENGTH) > 0) {
|
||||
// Get filename without path and extension.
|
||||
return std::string(basename(buff.get()));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif // !defined(_WIN32) && !defined(__CYGWIN__)
|
||||
Plik diff jest za duży
Load Diff
@@ -1,63 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
.text
|
||||
.globl _StackContext_setjmp
|
||||
.type _StackContext_setjmp, @function
|
||||
_StackContext_setjmp:
|
||||
|
||||
#if defined(_LP64)
|
||||
movq (%rsp), %rsi
|
||||
movq %rbx, (%rdi)
|
||||
lea 8(%rsp), %rax
|
||||
movq %rax, 8(%rdi)
|
||||
movq %rbp, 16(%rdi)
|
||||
movq %r12, 24(%rdi)
|
||||
movq %r13, 32(%rdi)
|
||||
movq %r14, 40(%rdi)
|
||||
movq %r15, 48(%rdi)
|
||||
movq %rsi, 56(%rdi)
|
||||
#else // _LP64
|
||||
movl (%esp), %ecx
|
||||
movl 4(%esp), %edx
|
||||
movl %ebx, (%edx)
|
||||
lea 4(%esp), %eax
|
||||
movl %eax, 4(%edx)
|
||||
movl %ebp, 8(%edx)
|
||||
movl %edi, 12(%edx)
|
||||
movl %esi, 16(%edx)
|
||||
movl %ecx, 20(%edx)
|
||||
#endif // _LP64
|
||||
xor %eax, %eax
|
||||
ret
|
||||
|
||||
.globl _StackContext_longjmp
|
||||
.type _StackContext_longjmp, @function
|
||||
_StackContext_longjmp:
|
||||
|
||||
#if defined(_LP64)
|
||||
mov %rsi, %rax
|
||||
movq (%rdi), %rbx
|
||||
movq 8(%rdi), %rsp
|
||||
movq 16(%rdi), %rbp
|
||||
movq 24(%rdi), %r12
|
||||
movq 32(%rdi), %r13
|
||||
movq 40(%rdi), %r14
|
||||
movq 48(%rdi), %r15
|
||||
movq 56(%rdi), %r8
|
||||
jmp *%r8
|
||||
#else // !_LP64
|
||||
movl 4(%esp), %edx
|
||||
movl 8(%esp), %eax
|
||||
movl (%edx), %ebx
|
||||
movl 4(%edx), %esp
|
||||
movl 8(%edx), %ebp
|
||||
movl 12(%edx), %edi
|
||||
movl 16(%edx), %esi
|
||||
movl 20(%edx), %ecx
|
||||
jmp *%ecx
|
||||
#endif // !_LP64
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
;
|
||||
; Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
;
|
||||
|
||||
ifndef _WIN64
|
||||
.386
|
||||
.model flat, c
|
||||
endif ; !_WIN64
|
||||
|
||||
OPTION PROLOGUE:NONE
|
||||
OPTION EPILOGUE:NONE
|
||||
.code
|
||||
|
||||
ifndef _WIN64
|
||||
|
||||
_StackContext_setjmp proc
|
||||
mov ecx,[esp]
|
||||
mov edx,4[esp]
|
||||
mov [edx],ebx
|
||||
lea eax,4[esp]
|
||||
mov 4[edx],eax
|
||||
mov 8[edx],ebp
|
||||
mov 0Ch[edx],edi
|
||||
mov 10h[edx],esi
|
||||
mov 14h[edx],ecx
|
||||
xor eax,eax
|
||||
ret
|
||||
_StackContext_setjmp endp
|
||||
|
||||
_StackContext_longjmp proc
|
||||
mov edx,4[esp]
|
||||
mov eax,8[esp]
|
||||
mov ebx,[edx]
|
||||
mov esp,4[edx]
|
||||
mov ebp,8[edx]
|
||||
mov edi,0Ch[edx]
|
||||
mov esi,10h[edx]
|
||||
mov ecx,14h[edx]
|
||||
jmp ecx
|
||||
_StackContext_longjmp endp
|
||||
|
||||
else ; _WIN64
|
||||
|
||||
_Os_setCurrentStackPtr proc
|
||||
pop r8
|
||||
mov rsp,rcx
|
||||
push r8
|
||||
ret
|
||||
_Os_setCurrentStackPtr endp
|
||||
|
||||
_StackContext_setjmp proc
|
||||
mov r8,[rsp]
|
||||
mov [rcx],rbx
|
||||
lea r9,8[rsp]
|
||||
mov 8[rcx],r9
|
||||
mov 10h[rcx],rbp
|
||||
mov 18h[rcx],rsi
|
||||
mov 20h[rcx],rdi
|
||||
mov 28h[rcx],r12
|
||||
mov 30h[rcx],r13
|
||||
mov 38h[rcx],r14
|
||||
mov 40h[rcx],r15
|
||||
mov 48h[rcx],r8
|
||||
stmxcsr 50h[rcx]
|
||||
fnstcw 54h[rcx]
|
||||
movdqa 60h[rcx],xmm6
|
||||
movdqa 70h[rcx],xmm7
|
||||
movdqa 80h[rcx],xmm8
|
||||
movdqa 90h[rcx],xmm9
|
||||
movdqa 0A0h[rcx],xmm10
|
||||
movdqa 0B0h[rcx],xmm11
|
||||
movdqa 0C0h[rcx],xmm12
|
||||
movdqa 0D0h[rcx],xmm13
|
||||
movdqa 0E0h[rcx],xmm14
|
||||
movdqa 0F0h[rcx],xmm15
|
||||
xor rax,rax
|
||||
ret
|
||||
_StackContext_setjmp endp
|
||||
|
||||
_StackContext_longjmp proc
|
||||
mov rax,rdx
|
||||
mov rbx,[rcx]
|
||||
mov rsp,8[rcx]
|
||||
mov rbp,10h[rcx]
|
||||
mov rsi,18h[rcx]
|
||||
mov rdi,20h[rcx]
|
||||
mov r12,28h[rcx]
|
||||
mov r13,30h[rcx]
|
||||
mov r14,38h[rcx]
|
||||
mov r15,40h[rcx]
|
||||
mov rdx,48h[rcx]
|
||||
ldmxcsr 50h[rcx]
|
||||
fnclex
|
||||
fldcw 54h[rcx]
|
||||
movdqa xmm6,60h[rcx]
|
||||
movdqa xmm7,70h[rcx]
|
||||
movdqa xmm8,80h[rcx]
|
||||
movdqa xmm9,90h[rcx]
|
||||
movdqa xmm10,0A0h[rcx]
|
||||
movdqa xmm11,0B0h[rcx]
|
||||
movdqa xmm12,0C0h[rcx]
|
||||
movdqa xmm13,0D0h[rcx]
|
||||
movdqa xmm14,0E0h[rcx]
|
||||
movdqa xmm15,0F0h[rcx]
|
||||
jmp rdx
|
||||
_StackContext_longjmp endp
|
||||
|
||||
endif ; _WIN64
|
||||
|
||||
end
|
||||
@@ -1,548 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
/*! \file atomic.hpp
|
||||
* \brief Declarations for Memory order access and Atomic operations.
|
||||
*
|
||||
* \author Laurent Morichetti (laurent.morichetti@amd.com)
|
||||
* \date October 2008
|
||||
*/
|
||||
|
||||
#ifndef ATOMIC_HPP_
|
||||
#define ATOMIC_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <intrin.h>
|
||||
#elif defined(ATI_ARCH_X86)
|
||||
# include <emmintrin.h>
|
||||
# include <xmmintrin.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Threads
|
||||
* @{
|
||||
*
|
||||
* \addtogroup Atomic Atomic Operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \brief Static functions for atomic operations.
|
||||
*/
|
||||
class AtomicOperation : AllStatic
|
||||
{
|
||||
private:
|
||||
|
||||
//! Template to specialize atomic intrinsics on register size.
|
||||
template <int N>
|
||||
struct Intrinsics {
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T add(T increment, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T swap(T value, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and xchge value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T compareAndSwap(T compare, volatile T* dest, T value);
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T increment(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T decrement(volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T _or(T mask, volatile T* dest);
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically and \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static inline T _and(T mask, volatile T* dest);
|
||||
};
|
||||
|
||||
public:
|
||||
/*! \brief %Atomic add.
|
||||
*
|
||||
* Atomically add \a inc to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T add(T inc, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::add((T) inc, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic exchange.
|
||||
*
|
||||
* Atomically exchange value with *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T swap(T value, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::swap(value, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic compare and exchange.
|
||||
*
|
||||
* Atomically compare and exchange value with *dest if *dest == compare.
|
||||
* Return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T compareAndSwap(T compare, volatile T* dest, T value)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::compareAndSwap(compare, dest, value);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic increment.
|
||||
*
|
||||
* Atomically increment *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T increment(volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::increment(dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic decrement.
|
||||
*
|
||||
* Atomically decrement *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T decrement(volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::decrement(dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic or.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T _or(T mask, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::_or((T) mask, dest);
|
||||
}
|
||||
|
||||
/*! \brief %Atomic and.
|
||||
*
|
||||
* Atomically or \a mask to \a *dest and return the prior value.
|
||||
*/
|
||||
template <typename T>
|
||||
static T _and(T mask, volatile T* dest)
|
||||
{
|
||||
return Intrinsics<sizeof(T)>::_and((T) mask, dest);
|
||||
}
|
||||
};
|
||||
|
||||
/*@}*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::add(T increment, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchangeAdd(
|
||||
(volatile long*)dest, (long)increment);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::swap(T value, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchange(
|
||||
(volatile long*)dest, (long)value);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::compareAndSwap(
|
||||
T compare, volatile T* dest, T value)
|
||||
{
|
||||
return (T)_InterlockedCompareExchange(
|
||||
(volatile long*)dest, (long)value, (long)compare);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::increment(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedIncrement((volatile long*)dest) - 1L);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::decrement(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedDecrement((volatile long*)dest) + 1L);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::_or(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedOr(
|
||||
(volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<4>::_and(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedAnd(
|
||||
(volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::add(T increment, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchangeAdd64(
|
||||
(volatile __int64*)dest, (__int64)increment);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::swap(T value, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedExchange64(
|
||||
(volatile __int64*)dest, (__int64)value);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::compareAndSwap(
|
||||
T compare, volatile T* dest, T value)
|
||||
{
|
||||
return (T)_InterlockedCompareExchange64(
|
||||
(volatile __int64*)dest, (__int64)value, (__int64)compare);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::increment(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedIncrement64((volatile __int64*)dest) - 1LL);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::decrement(volatile T* dest)
|
||||
{
|
||||
return (T)(_InterlockedDecrement64((volatile __int64*)dest) + 1LL);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::_or(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedOr64(
|
||||
(volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<8>::_and(T mask, volatile T* dest)
|
||||
{
|
||||
return (T)_InterlockedAnd64(
|
||||
(volatile long*)dest, (long)mask);
|
||||
}
|
||||
|
||||
#endif // _LP64
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::add(T inc, volatile T* dest)
|
||||
{
|
||||
return __sync_fetch_and_add(dest, inc);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::swap(T value, volatile T* dest)
|
||||
{
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::compareAndSwap(
|
||||
T compare, volatile T* dest, T value)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dest, compare, value);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::increment(volatile T* dest)
|
||||
{
|
||||
return add(T(1), dest);
|
||||
}
|
||||
|
||||
template<int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::decrement(volatile T* dest)
|
||||
{
|
||||
return add(T(-1), dest);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::_or(T mask, volatile T* dest)
|
||||
{
|
||||
return __sync_fetch_and_or(dest, mask);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
template <typename T>
|
||||
inline T
|
||||
AtomicOperation::Intrinsics<N>::_and(T mask, volatile T* dest)
|
||||
{
|
||||
return __sync_fetch_and_and(dest, mask);
|
||||
}
|
||||
|
||||
#else
|
||||
# error Unimplemented
|
||||
#endif
|
||||
|
||||
/*! \addtogroup Atomic Atomic Operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \brief A variable of type T with atomic properties.
|
||||
*/
|
||||
template <typename T>
|
||||
class Atomic
|
||||
{
|
||||
private:
|
||||
|
||||
typedef typename std::remove_volatile<typename std::remove_pointer<
|
||||
typename std::remove_reference<T>::type>::type>::type value_type;
|
||||
typename std::add_volatile<T>::type value_; //!< \brief The variable.
|
||||
|
||||
public:
|
||||
//! Construct a new %Atomic variable of type T.
|
||||
Atomic() : value_(T(0)) {}
|
||||
//! Construct a new %Atomic variable of type T from \a value.
|
||||
Atomic(T value) : value_(value) {}
|
||||
//! Construct a new %Atomic variable of type T from another %Atomic.
|
||||
Atomic(const Atomic<T>& atomic) : value_(atomic.value_) { }
|
||||
//! Copy value into this %Atomic variable.
|
||||
Atomic<T>& operator = (T value)
|
||||
{
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Return the %Atomic variable value.
|
||||
operator T () const { return T(value_); }
|
||||
//! Return the %Atomic variable value.
|
||||
T operator ->() const { return T(value_); }
|
||||
//! Return the %Atomic variable's address.
|
||||
typename std::add_pointer<typename std::add_volatile<value_type>::type>::
|
||||
type operator &() { return &value_; }
|
||||
|
||||
//! Atomically add \a inc to this variable.
|
||||
Atomic<T>& operator += (value_type inc)
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically subtract \a inc to this variable.
|
||||
Atomic<T>& operator -= (value_type inc)
|
||||
{
|
||||
value_type modifier = 0;
|
||||
if (std::is_pointer<T>::value) {
|
||||
inc *= sizeof(typename std::remove_pointer<T>::type);
|
||||
}
|
||||
AtomicOperation::add(modifier - inc, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically OR \a value to this variable.
|
||||
Atomic<T>& operator |= (value_type mask)
|
||||
{
|
||||
AtomicOperation::_or(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically AND \a value to this variable.
|
||||
Atomic<T>& operator &= (value_type mask)
|
||||
{
|
||||
AtomicOperation::_and(mask, &value_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Atomically increment this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator ++ ()
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(
|
||||
sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_) + 1;
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::increment(&value_) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically decrement this variable and return its new value.
|
||||
typename std::remove_reference<T>::type operator -- ()
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(-
|
||||
static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_) - 1;
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::decrement(&value_) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically increment this variable and return its previous value.
|
||||
typename std::remove_reference<T>::type operator ++ (int)
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(
|
||||
sizeof(typename std::remove_pointer<T>::type));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::increment(&value_);
|
||||
}
|
||||
}
|
||||
|
||||
//! Atomically decrement this variable and return its previous value.
|
||||
T operator -- (int)
|
||||
{
|
||||
if (std::is_pointer<T>::value) {
|
||||
value_type inc = static_cast<value_type>(-
|
||||
static_cast<typename std::make_signed<value_type>::type>(
|
||||
sizeof(typename std::remove_pointer<T>::type)));
|
||||
return AtomicOperation::add(inc, &value_);
|
||||
}
|
||||
else {
|
||||
return AtomicOperation::decrement(&value_);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Atomically compare this variable with \a compare and set
|
||||
* to value if equals
|
||||
*/
|
||||
bool compareAndSet(T compare, T value)
|
||||
{
|
||||
return compare == AtomicOperation::compareAndSwap(
|
||||
compare, &value_, value);
|
||||
}
|
||||
|
||||
//! Atomically set this variable to \a value and return its previous value.
|
||||
T swap(T value)
|
||||
{
|
||||
return AtomicOperation::swap(value, &value_);
|
||||
}
|
||||
|
||||
/*! \brief Execute a stores fence followed by a store to this variable.
|
||||
*
|
||||
* This storeRelease operation ensures that all store to memory operations
|
||||
* preceding this function will be globally visible before the update to
|
||||
* this variable's value.
|
||||
*/
|
||||
void storeRelease(T value)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
/*! \brief Execute a load from this variable followed by a loads fence.
|
||||
*
|
||||
* This loadAcquire operation ensures that all load from memory operations
|
||||
* following this function will be globally visible after the read from
|
||||
* this variable's value.
|
||||
*/
|
||||
T loadAcquire() const
|
||||
{
|
||||
T value = value_;
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
//! Helper function to tie an Atomic<T&> to a variable of type T.
|
||||
template <typename T>
|
||||
inline Atomic<T&>
|
||||
make_atomic(T& t)
|
||||
{
|
||||
return Atomic<T&>(t);
|
||||
}
|
||||
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*ATOMIC_HPP_*/
|
||||
@@ -1,321 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "thread/monitor.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace amd {
|
||||
|
||||
Monitor::Monitor(const char* name, bool recursive) :
|
||||
contendersList_(0), onDeck_(0), waitersList_(NULL),
|
||||
owner_(NULL), recursive_(recursive)
|
||||
{
|
||||
const size_t maxNameLen = sizeof(name_);
|
||||
if (name == NULL) {
|
||||
const char* unknownName = "@unknown@";
|
||||
assert(sizeof(unknownName) < maxNameLen && "just checking");
|
||||
strcpy(name_, unknownName);
|
||||
}
|
||||
else {
|
||||
strncpy(name_, name, maxNameLen - 1);
|
||||
name_[maxNameLen - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Monitor::trySpinLock()
|
||||
{
|
||||
if (tryLock()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int s = kMaxSpinIter; s > 0; --s) {
|
||||
// First, be SMT friendly
|
||||
if (s >= (kMaxSpinIter - kMaxReadSpinIter)) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else {
|
||||
Thread::yield();
|
||||
}
|
||||
if (!isLocked()) {
|
||||
return tryLock();
|
||||
}
|
||||
}
|
||||
|
||||
// We could not acquire the lock in the spin loop.
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::finishLock()
|
||||
{
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread != NULL && "cannot lock() from (null)");
|
||||
|
||||
if (trySpinLock()) {
|
||||
return; // We succeeded, we are done.
|
||||
}
|
||||
|
||||
/* The lock is contended. Push the thread's semaphore onto
|
||||
* the contention list.
|
||||
*/
|
||||
Semaphore& semaphore = thread->lockSemaphore();
|
||||
semaphore.reset();
|
||||
|
||||
LinkedNode newHead;
|
||||
newHead.setItem(&semaphore);
|
||||
|
||||
intptr_t head = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
// The assumption is that lockWord is locked. Make sure we do not
|
||||
// continue unless the lock bit is set.
|
||||
if ((head & kLockBit) == 0) {
|
||||
if (tryLock()) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the new contention list head if lockWord is unchanged.
|
||||
newHead.setNext(reinterpret_cast<LinkedNode*>(head & ~kLockBit));
|
||||
if (contendersList_.compare_exchange_weak(head,
|
||||
reinterpret_cast<intptr_t>(&newHead) | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// We failed the CAS. yield/pause before trying again.
|
||||
Thread::yield();
|
||||
}
|
||||
|
||||
int32_t spinCount = 0;
|
||||
// Go to sleep until we become the on-deck thread.
|
||||
while ((onDeck_ & ~kLockBit) != reinterpret_cast<intptr_t>(&semaphore)) {
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
semaphore.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
spinCount = 0;
|
||||
//
|
||||
// From now-on, we are the on-deck thread. It will stay that way until
|
||||
// we successfuly acquire the lock.
|
||||
//
|
||||
for (;;) {
|
||||
assert((onDeck_ & ~kLockBit) == reinterpret_cast<intptr_t>(&semaphore)
|
||||
&& "just checking");
|
||||
if (tryLock()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Somebody beat us to it. Since we are on-deck, we can just go
|
||||
// back to sleep.
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
semaphore.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
assert(newHead.next() == NULL && "Should not be linked");
|
||||
onDeck_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::finishUnlock()
|
||||
{
|
||||
// If we get here, it means that there might be a thread in the contention
|
||||
// list waiting to acquire the lock. We need to select a successor and
|
||||
// place it on-deck.
|
||||
|
||||
for (;;) {
|
||||
// Grab the onDeck_ microlock to protect the next loop (make sure only
|
||||
// one semaphore is removed from the contention list).
|
||||
//
|
||||
intptr_t ptr = 0;
|
||||
if (!onDeck_.compare_exchange_strong(ptr, ptr | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
return; // Somebody else has the microlock, let him select onDeck_
|
||||
}
|
||||
|
||||
intptr_t head = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
if (head == 0) {
|
||||
break; // There's nothing else to do.
|
||||
}
|
||||
|
||||
if ((head & kLockBit) != 0) {
|
||||
// Somebody could have acquired then released the lock
|
||||
// and failed to grab the onDeck_ microlock.
|
||||
head = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (contendersList_.compare_exchange_weak(
|
||||
head, reinterpret_cast<intptr_t>(
|
||||
reinterpret_cast<LinkedNode*>(head)->next()),
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
#ifdef ASSERT
|
||||
reinterpret_cast<LinkedNode*>(head)->setNext(NULL);
|
||||
#endif // ASSERT
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore* semaphore = (head != 0)
|
||||
? reinterpret_cast<LinkedNode*>(head)->item()
|
||||
: NULL;
|
||||
|
||||
onDeck_.store(reinterpret_cast<intptr_t>(semaphore),
|
||||
std::memory_order_release);
|
||||
//
|
||||
// Release the onDeck_ microlock (end of critical region);
|
||||
|
||||
if (semaphore != NULL) {
|
||||
semaphore->post();
|
||||
return;
|
||||
}
|
||||
|
||||
// We do not have an on-deck thread (semaphore == NULL). Return if
|
||||
// the contention list is empty or if the lock got acquired again.
|
||||
head = contendersList_;
|
||||
if (head == 0 || (head & kLockBit) != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::wait()
|
||||
{
|
||||
Thread* thread = Thread::current();
|
||||
assert(isLocked() && owner_ == thread && "just checking");
|
||||
|
||||
// Add the thread's resume semaphore to the list.
|
||||
Semaphore& suspend = thread->suspendSemaphore();
|
||||
suspend.reset();
|
||||
|
||||
LinkedNode newHead;
|
||||
newHead.setItem(&suspend);
|
||||
newHead.setNext(waitersList_);
|
||||
waitersList_ = &newHead;
|
||||
|
||||
// Preserve the lock count (for recursive mutexes)
|
||||
uint32_t lockCount = lockCount_;
|
||||
lockCount_ = 1;
|
||||
|
||||
// Release the lock and go to sleep.
|
||||
unlock();
|
||||
|
||||
// Go to sleep until we become the on-deck thread.
|
||||
int32_t spinCount = 0;
|
||||
while ((onDeck_ & ~kLockBit) != reinterpret_cast<intptr_t>(&suspend)) {
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
suspend.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
spinCount = 0;
|
||||
for (;;) {
|
||||
assert((onDeck_ & ~kLockBit) == reinterpret_cast<intptr_t>(&suspend)
|
||||
&& "just checking");
|
||||
|
||||
if (trySpinLock()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Somebody beat us to it. Since we are on-deck, we can just go
|
||||
// back to sleep.
|
||||
// First, be SMT friendly
|
||||
if (spinCount < kMaxReadSpinIter) {
|
||||
Os::spinPause();
|
||||
}
|
||||
// and then SMP friendly
|
||||
else if (spinCount < kMaxSpinIter) {
|
||||
Thread::yield();
|
||||
}
|
||||
// now go to sleep
|
||||
else {
|
||||
suspend.wait();
|
||||
}
|
||||
spinCount++;
|
||||
}
|
||||
|
||||
// Restore the lock count (for recursive mutexes)
|
||||
lockCount_ = lockCount;
|
||||
|
||||
onDeck_.store(0, std::memory_order_release);
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::notify()
|
||||
{
|
||||
assert(isLocked() && owner_ == Thread::current() && "just checking");
|
||||
|
||||
LinkedNode* waiter = waitersList_;
|
||||
if (waiter == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dequeue a waiter from the wait list and add it to the contention list.
|
||||
waitersList_ = waiter->next();
|
||||
|
||||
intptr_t node = contendersList_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
waiter->setNext(reinterpret_cast<LinkedNode*>(node & ~kLockBit));
|
||||
if (contendersList_.compare_exchange_weak(node,
|
||||
reinterpret_cast<intptr_t>(waiter) | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Monitor::notifyAll()
|
||||
{
|
||||
// NOTE: We could CAS the whole list in 1 shot but this is
|
||||
// not critical code. Optimize this if it becomes hot.
|
||||
while (waitersList_ != NULL) {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
@@ -1,263 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MONITOR_HPP_
|
||||
#define MONITOR_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Threads
|
||||
* @{
|
||||
*
|
||||
* \addtogroup Synchronization
|
||||
* @{
|
||||
*/
|
||||
|
||||
namespace details {
|
||||
|
||||
template <class T, class AllocClass = HeapObject>
|
||||
struct SimplyLinkedNode : public AllocClass
|
||||
{
|
||||
typedef SimplyLinkedNode<T, AllocClass> Node;
|
||||
|
||||
protected:
|
||||
std::atomic<Node*> next_; /*!< \brief The next element. */
|
||||
T volatile item_;
|
||||
|
||||
public:
|
||||
//! \brief Return the next element in the linked-list.
|
||||
Node* next() const { return next_; }
|
||||
//! \brief Return the item.
|
||||
T item() const { return item_; }
|
||||
|
||||
//! \brief Set the next element pointer.
|
||||
void setNext(Node* next) { next_ = next; }
|
||||
//! \brief Set the item.
|
||||
void setItem(T item) { item_ = item; }
|
||||
|
||||
//! \brief Swap the next element pointer.
|
||||
Node* swapNext(Node* next) { return next_.swap(next); }
|
||||
|
||||
//! \brief Compare and set the next element pointer.
|
||||
bool compareAndSetNext(Node* compare, Node* next)
|
||||
{
|
||||
return next_.compare_exchange_strong(compare, next);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
class Monitor : public HeapObject
|
||||
{
|
||||
typedef details::SimplyLinkedNode<Semaphore*,StackObject> LinkedNode;
|
||||
|
||||
private:
|
||||
static const intptr_t kLockBit = 0x1;
|
||||
|
||||
static const int kMaxSpinIter = 55; //!< Total number of spin iterations.
|
||||
static const int kMaxReadSpinIter = 50; //!< Read iterations before yielding
|
||||
|
||||
/*! Linked list of semaphores the contending threads are waiting on
|
||||
* and main lock.
|
||||
*/
|
||||
std::atomic_intptr_t contendersList_;
|
||||
//! The Mutex's name
|
||||
char name_[64];
|
||||
|
||||
//! Semaphore of the next thread to contend for the lock.
|
||||
std::atomic_intptr_t onDeck_;
|
||||
//! Linked list of the suspended threads resume semaphores.
|
||||
LinkedNode* volatile waitersList_;
|
||||
|
||||
//! Thread owning this monitor.
|
||||
Thread* volatile owner_;
|
||||
//! The amount of times this monitor was acquired by the owner.
|
||||
uint32_t lockCount_;
|
||||
//! True if this is a recursive mutex, false otherwise.
|
||||
const bool recursive_;
|
||||
|
||||
private:
|
||||
//! Finish locking the mutex (contented case).
|
||||
void finishLock();
|
||||
//! Finish unlocking the mutex (contented case).
|
||||
void finishUnlock();
|
||||
|
||||
protected:
|
||||
//! Try to spin-acquire the lock, return true if successful.
|
||||
bool trySpinLock();
|
||||
|
||||
/*! \brief Return true if the lock is owned.
|
||||
*
|
||||
* \note The user is responsible for the memory ordering.
|
||||
*/
|
||||
bool isLocked() const { return (contendersList_ & kLockBit) != 0; }
|
||||
|
||||
//! Return this monitor's owner thread (NULL if unlocked).
|
||||
Thread* owner() const { return owner_; }
|
||||
|
||||
//! Set the owner.
|
||||
void setOwner(Thread* thread) { owner_ = thread; }
|
||||
|
||||
public:
|
||||
explicit Monitor(const char* name = NULL, bool recursive = false);
|
||||
~Monitor() {}
|
||||
|
||||
//! Try to acquire the lock, return true if successful.
|
||||
inline bool tryLock();
|
||||
|
||||
//! Acquire the lock or suspend the calling thread.
|
||||
inline void lock();
|
||||
|
||||
//! Release the lock and wake a single waiting thread if any.
|
||||
inline void unlock();
|
||||
|
||||
/*! \brief Give up the lock and go to sleep.
|
||||
*
|
||||
* Calling wait() causes the current thread to go to sleep until
|
||||
* another thread calls notify()/notifyAll().
|
||||
*
|
||||
* \note The monitor must be owned before calling wait().
|
||||
*/
|
||||
void wait();
|
||||
/*! \brief Wake up a single thread waiting on this monitor.
|
||||
*
|
||||
* \note The monitor must be owned before calling notify().
|
||||
*/
|
||||
void notify();
|
||||
/*! \brief Wake up all threads that are waiting on this monitor.
|
||||
*
|
||||
* \note The monitor must be owned before calling notifyAll().
|
||||
*/
|
||||
void notifyAll();
|
||||
|
||||
//! Return this lock's name.
|
||||
const char* name() const { return name_; }
|
||||
};
|
||||
|
||||
class ScopedLock : StackObject
|
||||
{
|
||||
private:
|
||||
Monitor* lock_;
|
||||
|
||||
public:
|
||||
ScopedLock(Monitor& lock)
|
||||
: lock_(&lock)
|
||||
{
|
||||
lock_->lock();
|
||||
}
|
||||
|
||||
ScopedLock(Monitor* lock)
|
||||
: lock_(lock)
|
||||
{
|
||||
if (lock_) lock_->lock();
|
||||
}
|
||||
|
||||
~ScopedLock()
|
||||
{
|
||||
if (lock_) lock_->unlock();
|
||||
}
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
inline bool
|
||||
Monitor::tryLock()
|
||||
{
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread != NULL && "cannot lock() from (null)");
|
||||
|
||||
intptr_t ptr = contendersList_.load(std::memory_order_acquire);
|
||||
|
||||
if (unlikely((ptr & kLockBit) != 0)) {
|
||||
if (recursive_ && thread == owner_) {
|
||||
// Recursive lock: increment the lock count and return.
|
||||
++lockCount_;
|
||||
return true;
|
||||
}
|
||||
return false; // Already locked!
|
||||
}
|
||||
|
||||
if (unlikely(!contendersList_.compare_exchange_weak(ptr, ptr | kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire))) {
|
||||
return false; // We failed the CAS from unlocked to locked.
|
||||
}
|
||||
|
||||
setOwner(thread); // cannot move above the CAS.
|
||||
lockCount_ = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
Monitor::lock()
|
||||
{
|
||||
if (unlikely(!tryLock())) {
|
||||
// The lock is contented.
|
||||
finishLock();
|
||||
}
|
||||
|
||||
// This is the beginning of the critical region. From now-on, everything
|
||||
// executes single-threaded!
|
||||
//
|
||||
}
|
||||
|
||||
inline void
|
||||
Monitor::unlock()
|
||||
{
|
||||
assert(isLocked() && owner_ == Thread::current() && "invariant");
|
||||
|
||||
if (recursive_ && --lockCount_ > 0) {
|
||||
// was a recursive lock case, simply return.
|
||||
return;
|
||||
}
|
||||
|
||||
setOwner(NULL);
|
||||
|
||||
// Clear the lock bit.
|
||||
intptr_t ptr = contendersList_.load(std::memory_order_acquire);
|
||||
while (!contendersList_.compare_exchange_weak(ptr, ptr & ~kLockBit,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire))
|
||||
;
|
||||
//
|
||||
// We succeeded the CAS from locked to unlocked.
|
||||
// This is the end of the critical region.
|
||||
|
||||
// Check if we have an on-deck thread that needs signaling.
|
||||
intptr_t onDeck = onDeck_;
|
||||
if (onDeck != 0) {
|
||||
if ((onDeck & kLockBit) == 0) {
|
||||
// Only signal if it is unmarked.
|
||||
reinterpret_cast<Semaphore*>(onDeck)->post();
|
||||
}
|
||||
return; // We are done.
|
||||
}
|
||||
|
||||
// We do not have an on-deck thread yet, we might have to walk the list in
|
||||
// order to select the next onDeck_. Only one thread needs to fill onDeck_,
|
||||
// so return if the list is empty or if the lock got acquired again (it's
|
||||
// somebody else's problem now!)
|
||||
|
||||
intptr_t head = contendersList_;
|
||||
if (head == 0 || (head & kLockBit) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Finish the unlock operation: find a thread to wake up.
|
||||
finishUnlock();
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*MONITOR_HPP_*/
|
||||
@@ -1,95 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008,2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
#else // !_WIN32
|
||||
# include <semaphore.h>
|
||||
# include <errno.h>
|
||||
#endif // !_WIN32
|
||||
|
||||
namespace amd {
|
||||
|
||||
Semaphore::Semaphore()
|
||||
{
|
||||
std::atomic_init(&state_, 0);
|
||||
#ifdef _WIN32
|
||||
handle_ = static_cast<void*>(CreateSemaphore(NULL, 0, LONG_MAX, NULL));
|
||||
assert(handle_ != NULL && "CreateSemaphore failed");
|
||||
#else // !_WIN32
|
||||
if (sem_init(&sem_, 0, 0) != 0) {
|
||||
fatal("sem_init() failed");
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!CloseHandle(static_cast<HANDLE>(handle_))) {
|
||||
fatal("CloseHandle() failed");
|
||||
}
|
||||
#else // !_WIN32
|
||||
if (sem_destroy(&sem_) != 0) {
|
||||
fatal("sem_destroy() failed");
|
||||
}
|
||||
#endif // !WIN32
|
||||
}
|
||||
|
||||
void
|
||||
Semaphore::post()
|
||||
{
|
||||
int state = state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
if (state > 0) {
|
||||
int newstate = state_.load(std::memory_order_acquire);
|
||||
if (state == newstate) {
|
||||
return;
|
||||
}
|
||||
state = newstate;
|
||||
continue;
|
||||
}
|
||||
if (state_.compare_exchange_weak(state, state+1,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state < 0) {
|
||||
// We have threads waiting on this event.
|
||||
#ifdef _WIN32
|
||||
ReleaseSemaphore(static_cast<HANDLE>(handle_), 1, NULL);
|
||||
#else // !_WIN32
|
||||
if (0 != sem_post(&sem_)) {
|
||||
fatal("sem_post() failed");
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Semaphore::wait()
|
||||
{
|
||||
if (state_-- > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (WAIT_OBJECT_0 != WaitForSingleObject(
|
||||
static_cast<HANDLE>(handle_), INFINITE)) {
|
||||
fatal("WaitForSingleObject failed");
|
||||
}
|
||||
#else // !_WIN32
|
||||
while (0 != sem_wait(&sem_)) {
|
||||
if (EINTR != errno) {
|
||||
fatal("sem_wait() failed");
|
||||
}
|
||||
}
|
||||
#endif // !_WIN32
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
@@ -1,65 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008,2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef SEMAPHORE_HPP_
|
||||
#define SEMAPHORE_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#if defined(__linux__)
|
||||
# include <semaphore.h>
|
||||
#endif /*linux*/
|
||||
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Threads
|
||||
* @{
|
||||
*
|
||||
* \addtogroup Synchronization
|
||||
* @{
|
||||
*/
|
||||
|
||||
class Thread;
|
||||
|
||||
//! \brief Counting semaphore
|
||||
class Semaphore : public HeapObject
|
||||
{
|
||||
private:
|
||||
std::atomic_int state_; //!< This semaphore's value.
|
||||
|
||||
#ifdef _WIN32
|
||||
void* handle_; //!< The semaphore object's handle.
|
||||
char padding_[64-sizeof(void*)-sizeof(std::atomic_int)];
|
||||
#else // !_WIN32
|
||||
sem_t sem_; //!< The semaphore object's identifier.
|
||||
char padding_[64-sizeof(sem_t)-sizeof(std::atomic_int)];
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
public:
|
||||
Semaphore();
|
||||
~Semaphore();
|
||||
|
||||
//! \brief Decrement this semaphore
|
||||
void wait();
|
||||
|
||||
//! \brief Increment this semaphore
|
||||
void post();
|
||||
|
||||
//! \brief Reset this semaphore.
|
||||
void reset()
|
||||
{
|
||||
state_.store(0, std::memory_order_release);
|
||||
}
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*SEMAPHORE_HPP_*/
|
||||
@@ -1,191 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "thread/thread.hpp"
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "thread/monitor.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
namespace amd {
|
||||
|
||||
HostThread::HostThread()
|
||||
: Thread("HostThread", 0, false)
|
||||
{
|
||||
setCurrent();
|
||||
Os::currentStackInfo(&stackBase_, &stackSize_);
|
||||
setState(RUNNABLE);
|
||||
}
|
||||
|
||||
void
|
||||
Thread::create()
|
||||
{
|
||||
created_ = new Semaphore();
|
||||
lock_ = new Semaphore();
|
||||
suspend_ = new Semaphore();
|
||||
|
||||
selfSuspendLock_ = new Monitor();
|
||||
|
||||
data_ = NULL;
|
||||
handle_ = NULL;
|
||||
setState(CREATED);
|
||||
}
|
||||
|
||||
Thread::Thread(const std::string& name, size_t stackSize, bool spawn)
|
||||
: handle_(NULL), name_(name), stackSize_(stackSize)
|
||||
{
|
||||
create();
|
||||
|
||||
if (!spawn) return;
|
||||
|
||||
if ((handle_ = Os::createOsThread(this))) {
|
||||
// Now we need to wait for Thread::main to report back.
|
||||
while (state() != Thread::INITIALIZED) {
|
||||
created_->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (handle_ != NULL) {
|
||||
::CloseHandle((HANDLE) handle_);
|
||||
}
|
||||
#endif
|
||||
delete created_;
|
||||
delete lock_;
|
||||
delete suspend_;
|
||||
|
||||
delete selfSuspendLock_;
|
||||
}
|
||||
|
||||
void*
|
||||
Thread::main()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Os::setCurrentThreadName(name().c_str());
|
||||
#endif // DEBUG
|
||||
Os::currentStackInfo(&stackBase_, &stackSize_);
|
||||
setCurrent();
|
||||
|
||||
// Notify the parent thread that we are up and running.
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
setState(INITIALIZED);
|
||||
created_->post();
|
||||
selfSuspendLock_->wait();
|
||||
}
|
||||
|
||||
if (state() == RUNNABLE) {
|
||||
run(data_);
|
||||
}
|
||||
|
||||
setState(FINISHED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Thread::start(void* data)
|
||||
{
|
||||
if (state() != INITIALIZED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data_ = data;
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
setState(RUNNABLE);
|
||||
selfSuspendLock_->notify();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Thread::resume()
|
||||
{
|
||||
ScopedLock sl(selfSuspendLock_);
|
||||
selfSuspendLock_->notify();
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
namespace details {
|
||||
|
||||
__thread Thread* thread_ __attribute__((tls_model("initial-exec")));
|
||||
|
||||
} // namespace details
|
||||
|
||||
void
|
||||
Thread::registerStack(address base, address top)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
void
|
||||
Thread::setCurrent()
|
||||
{
|
||||
details::thread_ = this;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
namespace details {
|
||||
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
__declspec(thread) Thread* thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
DWORD threadIndex_ = TlsAlloc();
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
|
||||
} // namespace details
|
||||
|
||||
void
|
||||
Thread::registerStack(address base, address top)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
void
|
||||
Thread::setCurrent()
|
||||
{
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
details::thread_ = this;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
TlsSetValue(details::threadIndex_, this);
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
Thread::init()
|
||||
{
|
||||
static bool initialized_ = false;
|
||||
|
||||
// We could use InitOnceExecuteOnce/pthread_once here:
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
initialized_ = true;
|
||||
|
||||
// Register the main thread
|
||||
return NULL != new HostThread();
|
||||
}
|
||||
|
||||
void
|
||||
Thread::tearDown()
|
||||
{
|
||||
#if defined(_WIN32) && !defined(USE_DECLSPEC_THREAD)
|
||||
if (details::threadIndex_ != TLS_OUT_OF_INDEXES) {
|
||||
TlsFree(threadIndex_);
|
||||
}
|
||||
#endif // _WIN32 && !USE_DECLSPEC_THREAD
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
@@ -1,231 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef THREAD_HPP_
|
||||
#define THREAD_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/semaphore.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define USE_DECLSPEC_THREAD 1
|
||||
# if !defined(USE_DECLSPEC_THREAD)
|
||||
# include <windows.h>
|
||||
# endif /*!USE_DECLSPEC_THREAD*/
|
||||
#endif /*_WIN32*/
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Threads Threading package
|
||||
* @{
|
||||
*
|
||||
* \addtogroup OsThread Native Threads
|
||||
* @{
|
||||
*/
|
||||
|
||||
class Monitor;
|
||||
|
||||
class Thread : public HeapObject
|
||||
{
|
||||
friend const void* Os::createOsThread(Thread*);
|
||||
|
||||
public:
|
||||
enum ThreadState
|
||||
{
|
||||
CREATED,
|
||||
INITIALIZED,
|
||||
RUNNABLE,
|
||||
SUSPENDED,
|
||||
FINISHED,
|
||||
FAILED
|
||||
};
|
||||
|
||||
private:
|
||||
//! System thread handle.
|
||||
const void* handle_;
|
||||
//! The thread's name.
|
||||
const std::string name_;
|
||||
//! Current running state.
|
||||
volatile ThreadState state_;
|
||||
//! The argument passed to run()
|
||||
void* data_;
|
||||
|
||||
//! \cond ignore
|
||||
Semaphore* created_; //!< To notify the parent thread.
|
||||
Semaphore* lock_; //!< For mutex support (during contention).
|
||||
Semaphore* suspend_; //!< For wait/suspend support.
|
||||
//! \endcond
|
||||
|
||||
Monitor* selfSuspendLock_; //!< For self suspend/resume.
|
||||
|
||||
protected:
|
||||
address stackBase_; //!< Main stack base.
|
||||
size_t stackSize_; //!< Main stack size.
|
||||
|
||||
private:
|
||||
|
||||
/*! \brief The start wrapper for all newly create threads.
|
||||
* This is called from the pthread_create start_thread.
|
||||
*/
|
||||
static void* entry(Thread* thread);
|
||||
|
||||
/*! \brief Thread main (called from the main function).
|
||||
* Setup the thread for running and wait for the semaphore to be signaled.
|
||||
*/
|
||||
void* main();
|
||||
|
||||
//! The entry point for this thread.
|
||||
virtual void run(void* data) = 0;
|
||||
|
||||
protected:
|
||||
//! Bring this thread to the created state.
|
||||
void create();
|
||||
|
||||
//! Set the current thread state.
|
||||
void setState(ThreadState state) { state_ = state; }
|
||||
|
||||
//! Set the thread-local _thread variable (used by current()).
|
||||
void setCurrent();
|
||||
|
||||
//! Register the given memory region as a valid stack.
|
||||
void registerStack(address base, address top);
|
||||
|
||||
/*! \brief Construct a new thread.
|
||||
* If \a spawn is false, do not create a new OS thread, instead,
|
||||
* bind to the currently running on.
|
||||
*/
|
||||
explicit Thread(
|
||||
const std::string& name,
|
||||
size_t stackSize = 0 /*use system default*/,
|
||||
bool spawn = true /* create a new Os::thread */);
|
||||
|
||||
public:
|
||||
//! Return the currently running thread instance.
|
||||
static inline Thread* current();
|
||||
|
||||
//! Initialize the OsThread package.
|
||||
static bool init();
|
||||
|
||||
//! Tear down the OsThread package.
|
||||
static void tearDown();
|
||||
|
||||
//! Destroy this thread.
|
||||
virtual ~Thread();
|
||||
|
||||
//! Return the thread's name
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
//! Get the system thread handle.
|
||||
const void* handle() const { return handle_; }
|
||||
|
||||
//! Start the thread execution
|
||||
bool start(void *data = NULL);
|
||||
|
||||
//! Resume the thread
|
||||
void resume();
|
||||
|
||||
//! Return true is this is the host thread.
|
||||
virtual bool isHostThread() const { return false; }
|
||||
|
||||
//! Return true if this is a worker thread.
|
||||
virtual bool isWorkerThread() const { return false; }
|
||||
|
||||
//! Get the current thread state.
|
||||
ThreadState state() const { return state_; }
|
||||
|
||||
//! Return this thread's stack base.
|
||||
address stackBase() const { return stackBase_; }
|
||||
//! Return this thread's stack size.
|
||||
size_t stackSize() const { return stackSize_; }
|
||||
//! Return this thread's stack bottom.
|
||||
address stackBottom() const { return stackBase() - stackSize(); }
|
||||
|
||||
//! Return this thread's contend semaphore.
|
||||
Semaphore& lockSemaphore() const { return *lock_; }
|
||||
//! Return this thread's resume semaphore.
|
||||
Semaphore& suspendSemaphore() const { return *suspend_; }
|
||||
|
||||
//! Set this thread's affinity to the given cpu.
|
||||
void setAffinity(uint cpu_id) const
|
||||
{
|
||||
Os::setThreadAffinity(handle_, cpu_id);
|
||||
}
|
||||
|
||||
//! Set this thread's affinity to the given cpu mask.
|
||||
void setAffinity(const Os::ThreadAffinityMask& mask) const
|
||||
{
|
||||
Os::setThreadAffinity(handle_, mask);
|
||||
}
|
||||
|
||||
//! Yield to threads of the same priority of higher
|
||||
static void yield()
|
||||
{
|
||||
Os::yield();
|
||||
}
|
||||
};
|
||||
|
||||
class HostThread : public Thread
|
||||
{
|
||||
private:
|
||||
//! A HostThread does not have a run function
|
||||
virtual void run(void* data) { ShouldNotCallThis(); }
|
||||
|
||||
public:
|
||||
//! Construct a new HostThread
|
||||
HostThread();
|
||||
|
||||
//! Return true is this is the host thread.
|
||||
bool isHostThread() const { return true; };
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
namespace details {
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
extern __thread Thread* thread_ __attribute__((tls_model("initial-exec")));
|
||||
|
||||
static inline Thread*
|
||||
currentThread()
|
||||
{
|
||||
return thread_;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
extern __declspec(thread) Thread* thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
extern DWORD threadIndex_;
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
|
||||
static inline Thread*
|
||||
currentThread()
|
||||
{
|
||||
#if defined(USE_DECLSPEC_THREAD)
|
||||
return thread_;
|
||||
#else // !USE_DECLSPEC_THREAD
|
||||
return (Thread*) TlsGetValue(threadIndex_);
|
||||
#endif // !USE_DECLSPEC_THREAD
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace details
|
||||
|
||||
inline Thread*
|
||||
Thread::current()
|
||||
{
|
||||
return details::currentThread();
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
|
||||
#endif /*THREAD_HPP_*/
|
||||
@@ -1,221 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef TOP_HPP_
|
||||
#define TOP_HPP_
|
||||
|
||||
#if defined(ATI_ARCH_ARM)
|
||||
# define __EXPORTED_HEADERS__ 1
|
||||
#endif /*ATI_ARCH_ARM*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOMINMAX 1
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif /*_WIN32*/
|
||||
|
||||
#include "utils/macros.hpp"
|
||||
#if 0 // FIXME_lmoriche
|
||||
#include "CL/opencl.h"
|
||||
#include "amdocl/cl_open_video_amd.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <cstdlib>
|
||||
#else /*!_WIN32*/
|
||||
# include <inttypes.h>
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
#if !defined(ATI_ARCH_ARM)
|
||||
#include <xmmintrin.h>
|
||||
#endif /*!ATI_ARCH_ARM*/
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
|
||||
typedef unsigned char* address;
|
||||
typedef const unsigned char* const_address;
|
||||
typedef void * pointer;
|
||||
typedef const void * const_pointer;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef const char* cstring;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#if _MSC_VER >= 1600
|
||||
# include <stdint.h>
|
||||
#else // _MSC_VER < 1600
|
||||
typedef signed __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif // _MSC_VER < 1600
|
||||
#ifndef _WIN64
|
||||
typedef int32_t ssize_t;
|
||||
#else // _WIN64
|
||||
typedef int64_t ssize_t;
|
||||
#endif // _WIN64
|
||||
#endif /*_WIN32*/
|
||||
|
||||
#ifdef _WIN32
|
||||
# define SIZE_T_FMT "%Iu"
|
||||
# define PTR_FMT "0x%p"
|
||||
# if !defined(snprintf)
|
||||
# define snprintf sprintf_s
|
||||
# endif
|
||||
#else /*!_WIN32*/
|
||||
# define SIZE_T_FMT "%zu"
|
||||
# define PTR_FMT "%p"
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
typedef uint32_t cl_mem_fence_flags;
|
||||
|
||||
//! \cond ignore
|
||||
#define _BAD_INT32 0xBAADBAAD
|
||||
#define _BAD_INT64 0XBAADBAADBAADBAADLL
|
||||
#define _BAD_INTPTR LP64_SWITCH(_BAD_INT32,_BAD_INT64)
|
||||
|
||||
const pointer badPointer = (pointer)(intptr_t) _BAD_INTPTR;
|
||||
const address badAddress = (address)(intptr_t) _BAD_INTPTR;
|
||||
//! \endcond
|
||||
|
||||
const size_t Ki = 1024;
|
||||
const size_t Mi = Ki*Ki;
|
||||
const size_t Gi = Ki*Ki*Ki;
|
||||
|
||||
const size_t K = 1000;
|
||||
const size_t M = K*K;
|
||||
const size_t G = K*K*K;
|
||||
|
||||
#include "utils/debug.hpp"
|
||||
|
||||
//! \addtogroup Utils
|
||||
|
||||
//! Namespace for AMD's OpenCL platform
|
||||
namespace amd {/*@{*/
|
||||
|
||||
//! \brief The default Null object type (!= void*);
|
||||
struct Null {};
|
||||
|
||||
//! \brief Return a const Null object (null)
|
||||
inline const Null null() { return Null(); }
|
||||
|
||||
/*! \brief A struct to hold 2 objects of arbitrary type.
|
||||
*/
|
||||
template <typename F, typename S>
|
||||
struct pair
|
||||
{
|
||||
F first; /*!< \brief first element. */
|
||||
S second; /*!< \brief second element. */
|
||||
|
||||
pair() : first(), second() { }
|
||||
pair(const F& f, const S& s) : first(f), second(s) { }
|
||||
|
||||
template <typename FF, typename SS>
|
||||
pair(const pair<FF,SS>& p) : first(p.first), second(p.second) { }
|
||||
};
|
||||
|
||||
template<typename F, typename S>
|
||||
inline pair<F,S>
|
||||
make_pair(F first, S second)
|
||||
{
|
||||
return pair<F,S>(first, second);
|
||||
}
|
||||
|
||||
/*! \brief Equivalent to a namespace (All member functions are static).
|
||||
*/
|
||||
class AllStatic
|
||||
{
|
||||
WINDOWS_SWITCH(public,private):
|
||||
AllStatic() { ShouldNotCallThis(); }
|
||||
AllStatic(const AllStatic&) { ShouldNotCallThis(); }
|
||||
~AllStatic() { ShouldNotCallThis(); }
|
||||
};
|
||||
|
||||
/*! \brief For embedded objects.
|
||||
*/
|
||||
class EmbeddedObject
|
||||
{
|
||||
WINDOWS_SWITCH(public,private):
|
||||
void* operator new(size_t) { ShouldNotCallThis(); return badPointer; }
|
||||
void operator delete(void *) { ShouldNotCallThis(); }
|
||||
};
|
||||
|
||||
/*! \brief For stack allocated objects.
|
||||
*/
|
||||
class StackObject
|
||||
{
|
||||
WINDOWS_SWITCH(public,private):
|
||||
void* operator new(size_t) { ShouldNotCallThis(); return badPointer; }
|
||||
void operator delete(void *) { ShouldNotCallThis(); }
|
||||
};
|
||||
|
||||
/*! \brief for objects allocated in a dedicate memory pool.
|
||||
the standard 'new' should not be called,
|
||||
only the in place version 'new (allocation_pointer) <class>()'
|
||||
, delete should only invoke the destructors and not release memory
|
||||
*/
|
||||
class MemoryPoolObject
|
||||
{
|
||||
public:
|
||||
void* operator new(size_t) { ShouldNotCallThis(); return badPointer; }
|
||||
void* operator new(size_t size,void * address) { return address; }
|
||||
void operator delete(void *) { }
|
||||
void operator delete( void *,void * address) { }
|
||||
};
|
||||
|
||||
/*! \brief For objects allocated on the C-heap.
|
||||
*/
|
||||
class HeapObject
|
||||
{
|
||||
public:
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* obj);
|
||||
};
|
||||
|
||||
/*! \brief For all reference counted objects.
|
||||
*/
|
||||
class ReferenceCountedObject
|
||||
{
|
||||
volatile uint referenceCount_;
|
||||
|
||||
protected:
|
||||
virtual ~ReferenceCountedObject() { }
|
||||
virtual bool terminate() { return true; }
|
||||
|
||||
public:
|
||||
ReferenceCountedObject() : referenceCount_(1) { }
|
||||
|
||||
void* operator new(size_t size) { return ::operator new(size); }
|
||||
void operator delete(void* p) { return ::operator delete(p); }
|
||||
|
||||
uint referenceCount() const { return referenceCount_; }
|
||||
|
||||
uint retain();
|
||||
uint release();
|
||||
};
|
||||
|
||||
/*@}*/} // namespace amd
|
||||
|
||||
#ifdef FOR_DOXYGEN_ONLY
|
||||
namespace std
|
||||
{
|
||||
template<class F, class S> struct pair { F first; S second; };
|
||||
template<class T> struct vector { public: T data; };
|
||||
template<class T> class deque { public: T data; };
|
||||
template<class T> class list { public: T data; };
|
||||
template<class T> class slist { public: T data; };
|
||||
template<class T> class set { public: T data; };
|
||||
template<class Key, class Data> class map { public: Key key; Data data; };
|
||||
}
|
||||
#endif // FOR_DOXYGEN_ONLY
|
||||
|
||||
#undef min // using std::min
|
||||
#undef max // using std::max
|
||||
|
||||
#endif /*TOP_HPP_*/
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "top.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
#if !defined(LOG_LEVEL)
|
||||
# include "utils/flags.hpp"
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
namespace amd {
|
||||
|
||||
//! \cond ignore
|
||||
extern "C" void
|
||||
breakpoint(void)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
DebugBreak();
|
||||
#endif // _MSC_VER
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
bool
|
||||
ShouldBreak(LogLevel level)
|
||||
{
|
||||
if ((level == LOG_WARNING && BREAK_ON_LOG_WARNING)
|
||||
|| (level == LOG_ERROR && BREAK_ON_LOG_ERROR)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
report_fatal(const char* file, int line, const char* message)
|
||||
{
|
||||
// FIXME_lmoriche: Obfuscate the message string
|
||||
fprintf(stderr, "%s:%d: %s\n", file, line, message);
|
||||
::abort();
|
||||
}
|
||||
|
||||
void
|
||||
report_warning(const char* message)
|
||||
{
|
||||
fprintf(stderr, "Warning: %s\n", message);
|
||||
}
|
||||
|
||||
void
|
||||
log_entry(LogLevel level, const char* file, int line, const char* message)
|
||||
{
|
||||
if (level == LOG_NONE) {
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, ":%d:%s:%d: %s\n", level, file, line, message);
|
||||
}
|
||||
|
||||
void
|
||||
log_timestamped(LogLevel level, const char* file, int line, const char* message)
|
||||
{
|
||||
static bool gotstart = false; // not thread-safe, but not scary if fails
|
||||
static uint64_t start;
|
||||
|
||||
if (!gotstart) {
|
||||
start = Os::timeNanos();
|
||||
gotstart = true;
|
||||
}
|
||||
|
||||
uint64_t time = Os::timeNanos() - start;
|
||||
if (level == LOG_NONE) {
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
fprintf(stderr, ":%d:%s:%d: (%010lld) %s\n", level, file, line, time, message);
|
||||
#else // if you prefer fixed-width fields
|
||||
fprintf(stderr, ":% 2d:%15s:% 5d: (%010lld) %s\n",
|
||||
level, file, line, time/100ULL, message); // timestamp is 100ns units
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
log_printf(LogLevel level, const char* file, int line, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
char message[1024];
|
||||
vsprintf(message, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fprintf(stderr, ":%d:%s:%d: %s\n", level, file, line, message);
|
||||
}
|
||||
|
||||
} // namespace amd
|
||||
@@ -1,182 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef DEBUG_HPP_
|
||||
#define DEBUG_HPP_
|
||||
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//! \addtogroup Utils
|
||||
|
||||
namespace amd {/*@{*/
|
||||
|
||||
enum LogLevel {
|
||||
LOG_NONE = 0,
|
||||
LOG_ERROR = 1,
|
||||
LOG_WARNING = 2,
|
||||
LOG_INFO = 3,
|
||||
LOG_DEBUG = 4
|
||||
};
|
||||
|
||||
//! \cond ignore
|
||||
extern "C" void
|
||||
breakpoint();
|
||||
//! \endcond
|
||||
|
||||
//! \brief Report a Fatal exception message and abort.
|
||||
extern void
|
||||
report_fatal(const char* file, int line, const char* message);
|
||||
|
||||
//! \brief Display a warning message.
|
||||
extern void
|
||||
report_warning(const char* message);
|
||||
|
||||
//! \brief Insert a log entry.
|
||||
extern void
|
||||
log_entry(LogLevel level, const char* file, int line, const char* messsage);
|
||||
|
||||
//! \brief Insert a timestamped log entry.
|
||||
extern void
|
||||
log_timestamped(LogLevel level, const char* file, int line, const char* messsage);
|
||||
|
||||
//! \brief Insert a printf-style log entry.
|
||||
extern void
|
||||
log_printf(
|
||||
LogLevel level,
|
||||
const char* file,
|
||||
int line,
|
||||
const char* format,
|
||||
...);
|
||||
|
||||
/*@}*/} // namespace amd
|
||||
|
||||
#if __INTEL_COMPILER
|
||||
|
||||
// Disable ICC's warning #279: controlling expression is constant
|
||||
// (0!=1 && "msg")
|
||||
// ^
|
||||
#pragma warning ( disable : 279 )
|
||||
|
||||
#endif // __INTEL_COMPILER
|
||||
|
||||
//! \brief Abort the program if the invariant \a cond is false.
|
||||
#define guarantee(cond) \
|
||||
if (!(cond)) \
|
||||
{ \
|
||||
amd::report_fatal(__FILE__, __LINE__, \
|
||||
"guarantee(" XSTR(cond) ")"); \
|
||||
amd::breakpoint(); \
|
||||
}
|
||||
|
||||
#define fixme_guarantee(cond) guarantee(cond)
|
||||
|
||||
//! \brief Abort the program with a fatal error message.
|
||||
#define fatal(msg) do { assert(false && msg); } while (0)
|
||||
|
||||
|
||||
//! \brief Display a warning message.
|
||||
inline void
|
||||
warning(const char* msg)
|
||||
{
|
||||
amd::report_warning(msg);
|
||||
}
|
||||
|
||||
/*! \brief Abort the program with a "ShouldNotReachHere" message.
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define ShouldNotReachHere() fatal("ShouldNotReachHere()")
|
||||
|
||||
/*! \brief Abort the program with a "ShouldNotCallThis" message.
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define ShouldNotCallThis() fatal("ShouldNotCallThis()")
|
||||
|
||||
/*! \brief Abort the program with an "Unimplemented" message.
|
||||
* \hideinitializer
|
||||
*/
|
||||
#define Unimplemented() fatal("Unimplemented()")
|
||||
|
||||
/*! \brief Display an "Untested" warning message.
|
||||
* \hideinitializer
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
# define Untested(msg) \
|
||||
warning("Untested(\"" msg "\")")
|
||||
#else /*NDEBUG*/
|
||||
# define Untested(msg) (void)(0)
|
||||
#endif /*NDEBUG*/
|
||||
|
||||
#ifdef DEBUG
|
||||
namespace amd {
|
||||
extern bool ShouldBreak(LogLevel level);
|
||||
} // namespace amd
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define Log(level,msg) \
|
||||
do \
|
||||
{ \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
amd::log_entry(level, __FILE__, __LINE__, msg); \
|
||||
if (amd::ShouldBreak(level)) { \
|
||||
amd::breakpoint(); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !DEBUG
|
||||
# define Log(level,msg) (void)(0)
|
||||
#endif // !DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define LogTS(level,msg) \
|
||||
do \
|
||||
{ \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
amd::log_timestamped(level, __FILE__, __LINE__, msg); \
|
||||
if (amd::ShouldBreak(level)) { \
|
||||
amd::breakpoint(); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !DEBUG
|
||||
# define Log(level,msg) (void)(0)
|
||||
#endif // !DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define Logf(level, format, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
amd::log_printf(level, __FILE__, __LINE__, format, __VA_ARGS__); \
|
||||
if (amd::ShouldBreak(level)) { \
|
||||
amd::breakpoint(); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !DEBUG
|
||||
# define Logf(level, format, ...) (void)(0)
|
||||
#endif // !DEBUG
|
||||
|
||||
#define CondLog(cond,msg) \
|
||||
do { \
|
||||
if (false DEBUG_ONLY(|| (cond))) { \
|
||||
Log(amd::LOG_INFO,msg); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define LogInfo(msg) Log(amd::LOG_INFO,msg)
|
||||
#define LogError(msg) Log(amd::LOG_ERROR,msg)
|
||||
#define LogWarning(msg) Log(amd::LOG_WARNING,msg)
|
||||
|
||||
#define LogTSInfo(msg) LogTS(amd::LOG_INFO,msg)
|
||||
#define LogTSError(msg) LogTS(amd::LOG_ERROR,msg)
|
||||
#define LogTSWarning(msg) LogTS(amd::LOG_WARNING,msg)
|
||||
|
||||
#define LogPrintfDebug(format, ...) Logf(amd::LOG_DEBUG, format, __VA_ARGS__)
|
||||
#define LogPrintfError(format, ...) Logf(amd::LOG_ERROR, format, __VA_ARGS__)
|
||||
#define LogPrintfWarning(format, ...) Logf(amd::LOG_WARNING, format, __VA_ARGS__)
|
||||
#define LogPrintfInfo(format, ...) Logf(amd::LOG_INFO, format, __VA_ARGS__)
|
||||
|
||||
#endif /*DEBUG_HPP_*/
|
||||
@@ -1,177 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MACROS_HPP_
|
||||
#define MACROS_HPP_
|
||||
|
||||
#ifndef OPENCL_EXPORTS
|
||||
# define OPENCL_EXPORTS 1
|
||||
#endif // OPENCL_EXPORTS
|
||||
|
||||
#if defined(NDEBUG)
|
||||
# define RELEASE 1
|
||||
#else// !NDEBUG
|
||||
# define ASSERT 1
|
||||
# define DEBUG 1
|
||||
#endif // !NDEBUG
|
||||
|
||||
#if defined(_WIN64) && !defined(_LP64)
|
||||
# define _LP64 1
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) && !defined(DEBUG)
|
||||
# define DEBUG 1
|
||||
#endif // _DEBUG && !DEBUG
|
||||
|
||||
#if defined(DEBUG) && defined(RELEASE)
|
||||
# error "Build Error: cannot have both -DDEBUG and -DRELEASE"
|
||||
#endif /*DEBUG && RELEASE*/
|
||||
|
||||
#if !defined(DEBUG) && !defined(RELEASE)
|
||||
# error "Build Error: must have either -DDEBUG or -DRELEASE"
|
||||
#endif /*DEBUG && RELEASE*/
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DEBUG_ONLY(x) x
|
||||
# define RELEASE_ONLY(x)
|
||||
# define IS_DEBUG true
|
||||
#else // !DEBUG
|
||||
# define DEBUG_ONLY(x)
|
||||
# define RELEASE_ONLY(x) x
|
||||
# define IS_DEBUG false
|
||||
#endif /*!DEBUG*/
|
||||
#define DEBUG_SWITCH(d,r) DEBUG_ONLY(d)RELEASE_ONLY(r)
|
||||
#define RELEASE_SWITCH(r,d) RELEASE_ONLY(r)DEBUG_ONLY(d)
|
||||
|
||||
//! \brief Make a c-string of __macro__
|
||||
#define STR(__macro__) #__macro__
|
||||
//! \brief Make a c-string of the expansion of __macro__
|
||||
#define XSTR(__macro__) STR(__macro__)
|
||||
//! \brief Concatenate 2 symbols
|
||||
#define CONCAT(a,b) a##b
|
||||
#define XCONCAT(a,b) CONCAT(a,b)
|
||||
|
||||
|
||||
//! \cond ignore
|
||||
#ifdef _LP64
|
||||
# define LP64_ONLY(x) x
|
||||
# define NOT_LP64(x)
|
||||
#else // !_LP64
|
||||
# define LP64_ONLY(x)
|
||||
# define NOT_LP64(x) x
|
||||
#endif /*!_LP64*/
|
||||
#define LP64_SWITCH(lp32,lp64) NOT_LP64(lp32)LP64_ONLY(lp64)
|
||||
|
||||
#ifdef __linux__
|
||||
# define IS_LINUX true
|
||||
# define LINUX_ONLY(x) x
|
||||
# define NOT_LINUX(x)
|
||||
#else // !__linux__
|
||||
# define LINUX_ONLY(x)
|
||||
# define NOT_LINUX(x) x
|
||||
#endif /*!__linux__*/
|
||||
|
||||
#ifdef __APPLE__
|
||||
# define IS_MACOS true
|
||||
# define MACOS_ONLY(x) x
|
||||
# define NOT_MACOS(x)
|
||||
#else // !__APPLE__
|
||||
# define MACOS_ONLY(x)
|
||||
# define NOT_MACOS(x) x
|
||||
#endif /*!__APPLE__*/
|
||||
|
||||
#ifdef _WIN32
|
||||
# define IS_WINDOWS true
|
||||
# define WINDOWS_ONLY(x) x
|
||||
# define NOT_WINDOWS(x)
|
||||
#else // !_WIN32
|
||||
# define WINDOWS_ONLY(x)
|
||||
# define NOT_WINDOWS(x) x
|
||||
#endif /*!_WIN32*/
|
||||
|
||||
#ifdef _WIN64
|
||||
# define WIN64_ONLY(x) x
|
||||
# define NOT_WIN64(x)
|
||||
#else // !_WIN64
|
||||
# define WIN64_ONLY(x)
|
||||
# define NOT_WIN64(x) x
|
||||
#endif /*!_WIN64*/
|
||||
|
||||
#ifndef IS_LINUX
|
||||
# define IS_LINUX false
|
||||
#endif
|
||||
#ifndef IS_MACOS
|
||||
# define IS_MACOS false
|
||||
#endif
|
||||
#ifndef IS_WINDOWS
|
||||
# define IS_WINDOWS false
|
||||
#endif
|
||||
|
||||
#define IF_LEFT_true(x) x
|
||||
#define IF_LEFT_false(x)
|
||||
#define IF_RIGHT_true(x)
|
||||
#define IF_RIGHT_false(x) x
|
||||
|
||||
#define IF_LEFT(cond,x) IF_LEFT_##cond(x)
|
||||
#define IF_RIGHT(cond,x) IF_RIGHT_##cond(x)
|
||||
#define IF(cond,x,y) IF_LEFT(cond,x)IF_RIGHT(cond,y)
|
||||
|
||||
#define LINUX_SWITCH(x,other) LINUX_ONLY(x)NOT_LINUX(other)
|
||||
#define MACOS_SWITCH(x,other) MACOS_ONLY(x)NOT_MACOS(other)
|
||||
#define WINDOWS_SWITCH(x,other) WINDOWS_ONLY(x)NOT_WINDOWS(other)
|
||||
|
||||
#ifdef OPENCL_MAINLINE
|
||||
# define IS_MAINLINE true
|
||||
#else // OPENCL_STAGING
|
||||
# define IS_MAINLINE false
|
||||
#endif
|
||||
|
||||
#ifdef OPTIMIZED
|
||||
# define OPTIMIZED_ONLY(x) x
|
||||
# define NOT_OPTIMIZED(x)
|
||||
# define IS_OPTIMIZED true
|
||||
#else
|
||||
# define OPTIMIZED_ONLY(x)
|
||||
# define NOT_OPTIMIZED(x) x
|
||||
# define IS_OPTIMIZED false
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define __ALIGNED__(x) __attribute__((aligned(x)))
|
||||
#elif defined(_MSC_VER)
|
||||
# define __ALIGNED__(x) __declspec(align(x))
|
||||
#elif defined(RC_INVOKED)
|
||||
# define __ALIGNED__(x)
|
||||
#else
|
||||
# error
|
||||
#endif /*_MSC_VER*/
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define likely(cond) __builtin_expect(!!(cond), 1)
|
||||
# define unlikely(cond) __builtin_expect(!!(cond), 0)
|
||||
#else // !__GNUC__
|
||||
# define likely(cond) (cond)
|
||||
# define unlikely(cond) (cond)
|
||||
#endif // !__GNUC__
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define NOINLINE __attribute__((noinline))
|
||||
# define ALWAYSINLINE __attribute__ ((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
# define NOINLINE __declspec(noinline)
|
||||
# define ALWAYSINLINE __forceinline
|
||||
#else // !_MSC_VER
|
||||
# define NOINLINE
|
||||
# define ALWAYSINLINE
|
||||
#endif // !_MSC_VER
|
||||
|
||||
#ifdef BRAHMA
|
||||
# define IS_BRAHMA true
|
||||
#else
|
||||
# define IS_BRAHMA false
|
||||
#endif
|
||||
|
||||
//! \endcond
|
||||
|
||||
#endif // MACROS_HPP_
|
||||
@@ -1,281 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef UTIL_HPP_
|
||||
#define UTIL_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
namespace amd {
|
||||
|
||||
/*! \addtogroup Utils Utilities
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! \brief Check if the given value \a val is a power of 2.
|
||||
template <typename T>
|
||||
static inline bool
|
||||
isPowerOfTwo(T val)
|
||||
{
|
||||
return (val & (val - 1)) == 0;
|
||||
}
|
||||
|
||||
//! \cond ignore
|
||||
|
||||
// Compute the next power of 2 helper.
|
||||
template <uint N>
|
||||
struct NextPowerOfTwoFunction
|
||||
{
|
||||
template <typename T>
|
||||
static T compute(T val)
|
||||
{
|
||||
val = NextPowerOfTwoFunction<N/2>::compute(val);
|
||||
return (val >> N) | val;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialized version for <1> to break the recursion.
|
||||
template <>
|
||||
struct NextPowerOfTwoFunction<1>
|
||||
{
|
||||
template <typename T>
|
||||
static T compute(T val) { return (val >> 1) | val; }
|
||||
};
|
||||
|
||||
template <uint N, int S>
|
||||
struct NextPowerOfTwoHelper
|
||||
{
|
||||
static const uint prev = NextPowerOfTwoHelper<N, S / 2>::value;
|
||||
static const uint value = (prev >> S) | prev;
|
||||
};
|
||||
template <uint N>
|
||||
struct NextPowerOfTwoHelper<N, 1>
|
||||
{
|
||||
static const int value = (N >> 1) | N;
|
||||
};
|
||||
|
||||
template <uint N>
|
||||
struct NextPowerOfTwo
|
||||
{
|
||||
static const uint value = NextPowerOfTwoHelper<N-1, 16>::value + 1;
|
||||
};
|
||||
|
||||
//! \endcond
|
||||
|
||||
/*! \brief Return the next power of two for a value of type T.
|
||||
*
|
||||
* The compute function is (with n = sizeof(T)*8):
|
||||
*
|
||||
* val = (val >> 1) | val;
|
||||
* val = (val >> 2) | val;
|
||||
* ...
|
||||
* val = (val >> n/4) | val;
|
||||
* val = (val >> n/2) | val;
|
||||
*
|
||||
* The next power of two is: 1+compute(val-1)
|
||||
*/
|
||||
template <typename T>
|
||||
inline T
|
||||
nextPowerOfTwo(T val)
|
||||
{
|
||||
return NextPowerOfTwoFunction<sizeof(T)*4>::compute(val - 1) + 1;
|
||||
}
|
||||
|
||||
// Compute log2(N)
|
||||
template <uint N>
|
||||
struct Log2
|
||||
{
|
||||
static const uint value = Log2<N/2>::value + 1;
|
||||
};
|
||||
|
||||
// Break the recursion
|
||||
template <>
|
||||
struct Log2<1>
|
||||
{
|
||||
static const uint value = 0;
|
||||
};
|
||||
|
||||
/*! \brief Return the log2 for a value of type T.
|
||||
*
|
||||
* The compute function is (with n = sizeof(T)*8):
|
||||
*
|
||||
* uint l = 0;
|
||||
* if (val >= 1 << n/2) { val >>= n/2; l |= n/2; }
|
||||
* if (val >= 1 << n/4) { val >>= n/4; l |= n/4; }
|
||||
* ...
|
||||
* if (val >= 1 << 2) { val >>= 2; l |= 2; }
|
||||
* if (val >= 1 << 1) { l |= 1; }
|
||||
* return l;
|
||||
*/
|
||||
template <uint N>
|
||||
struct Log2Function
|
||||
{
|
||||
template <typename T>
|
||||
static uint compute(T val)
|
||||
{
|
||||
uint l = 0;
|
||||
if (val >= T(1) << N) {
|
||||
val >>= N; l = N;
|
||||
}
|
||||
return l + Log2Function<N/2>::compute(val);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Log2Function<1>
|
||||
{
|
||||
template <typename T>
|
||||
static uint compute(T val) {
|
||||
return (val >= T(1)<<1) ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
// log2 helper function
|
||||
template <typename T>
|
||||
inline uint
|
||||
log2(T val)
|
||||
{
|
||||
return Log2Function<sizeof(T)*4>::compute(val);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T
|
||||
alignDown(T value, size_t alignment)
|
||||
{
|
||||
return (T) (value & ~(alignment - 1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T*
|
||||
alignDown(T* value, size_t alignment)
|
||||
{
|
||||
return (T*) alignDown((intptr_t) value, alignment);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T
|
||||
alignUp(T value, size_t alignment)
|
||||
{
|
||||
return alignDown((T) (value + alignment - 1), alignment);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T*
|
||||
alignUp(T* value, size_t alignment)
|
||||
{
|
||||
return (T*) alignDown((intptr_t) (value + alignment - 1), alignment);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool isMultipleOf(T value, size_t alignment)
|
||||
{
|
||||
if (isPowerOfTwo(alignment)) {
|
||||
// fast path, using logical operators
|
||||
return alignUp(value, alignment) == value;
|
||||
}
|
||||
return value % alignment == 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool isMultipleOf(T* value, size_t alignment)
|
||||
{
|
||||
intptr_t ptr = reinterpret_cast<intptr_t>(value);
|
||||
return isMultipleOf(ptr, alignment);
|
||||
}
|
||||
|
||||
template <class Reference, class Value>
|
||||
struct DeviceMap {
|
||||
Reference ref_;
|
||||
Value value_;
|
||||
};
|
||||
|
||||
|
||||
inline uint
|
||||
countBitsSet32(uint32_t value)
|
||||
{
|
||||
#if __GNUC__ >= 4
|
||||
return (uint)__builtin_popcount(value);
|
||||
#else
|
||||
value = value - ((value >> 1) & 0x55555555);
|
||||
value = (value & 0x33333333) + ((value >> 2) & 0x33333333);
|
||||
return (uint)(((value + (value >> 4) & 0xF0F0F0F) * 0x1010101) >> 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint
|
||||
countBitsSet64(uint64_t value)
|
||||
{
|
||||
#if __GNUC__ >= 4
|
||||
return (uint)__builtin_popcountll(value);
|
||||
#else
|
||||
value = value - ((value >> 1) & 0x5555555555555555ULL);
|
||||
value = (value & 0x3333333333333333ULL) + ((value >> 2) & 0x3333333333333333ULL);
|
||||
value = (value + (value >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
return (uint)((uint64_t)(value * 0x0101010101010101ULL) >> 56);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint
|
||||
leastBitSet32(uint32_t value)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
unsigned long idx;
|
||||
return _BitScanForward(&idx, (unsigned long)value) ? idx : (uint)-1;
|
||||
#else
|
||||
return value ? __builtin_ctz(value) : (uint)-1;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint
|
||||
leastBitSet64(uint64_t value)
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
unsigned long idx;
|
||||
return _BitScanForward64(&idx, (unsigned __int64)value) ? idx : (uint)-1;
|
||||
#elif defined (__GNUC__)
|
||||
return value ? __builtin_ctzll(value) : (uint)-1;
|
||||
#else
|
||||
static const uint8_t lookup67[67+1] = {
|
||||
64, 0, 1, 39, 2, 15, 40, 23,
|
||||
3, 12, 16, 59, 41, 19, 24, 54,
|
||||
4, -1, 13, 10, 17, 62, 60, 28,
|
||||
42, 30, 20, 51, 25, 44, 55, 47,
|
||||
5, 32, -1, 38, 14, 22, 11, 58,
|
||||
18, 53, 63, 9, 61, 27, 29, 50,
|
||||
43, 46, 31, 37, 21, 57, 52, 8,
|
||||
26, 49, 45, 36, 56, 7, 48, 35,
|
||||
6, 34, 33, -1
|
||||
};
|
||||
|
||||
return (uint)lookup67[((int64_t)value & -(int64_t)value) % 67];
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline uint countBitsSet(T value)
|
||||
{
|
||||
return (sizeof(T) == 8) ? countBitsSet64((uint64_t)value) :
|
||||
countBitsSet32((uint32_t)value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline uint leastBitSet(T value)
|
||||
{
|
||||
return (sizeof(T) == 8) ? leastBitSet64((uint64_t)value) :
|
||||
leastBitSet32((uint32_t)value);
|
||||
}
|
||||
|
||||
static inline bool Is32Bits() {
|
||||
return LP64_SWITCH(true, false);
|
||||
}
|
||||
|
||||
static inline bool Is64Bits() {
|
||||
return LP64_SWITCH(false, true);
|
||||
}
|
||||
/*@}*/} // namespace amd
|
||||
|
||||
#endif /*UTIL_HPP_*/
|
||||
@@ -30,16 +30,6 @@ breakpoint(void)
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
bool
|
||||
ShouldBreak(LogLevel level)
|
||||
{
|
||||
if ((level == LOG_WARNING && BREAK_ON_LOG_WARNING)
|
||||
|| (level == LOG_ERROR && BREAK_ON_LOG_ERROR)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
report_fatal(const char* file, int line, const char* message)
|
||||
{
|
||||
|
||||
@@ -108,21 +108,12 @@ warning(const char* msg)
|
||||
# define Untested(msg) (void)(0)
|
||||
#endif /*NDEBUG*/
|
||||
|
||||
#ifdef DEBUG
|
||||
namespace amd {
|
||||
extern bool ShouldBreak(LogLevel level);
|
||||
} // namespace amd
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define Log(level,msg) \
|
||||
do \
|
||||
{ \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
amd::log_entry(level, __FILE__, __LINE__, msg); \
|
||||
if (amd::ShouldBreak(level)) { \
|
||||
amd::breakpoint(); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !DEBUG
|
||||
@@ -135,9 +126,6 @@ do \
|
||||
{ \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
amd::log_timestamped(level, __FILE__, __LINE__, msg); \
|
||||
if (amd::ShouldBreak(level)) { \
|
||||
amd::breakpoint(); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !DEBUG
|
||||
@@ -150,9 +138,6 @@ do \
|
||||
{ \
|
||||
if (LOG_LEVEL >= level) { \
|
||||
amd::log_printf(level, __FILE__, __LINE__, format, __VA_ARGS__); \
|
||||
if (amd::ShouldBreak(level)) { \
|
||||
amd::breakpoint(); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#else // !DEBUG
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
\
|
||||
debug(int, LOG_LEVEL, 0, \
|
||||
"The default log level") \
|
||||
debug(bool, BREAK_ON_LOG_WARNING, false, \
|
||||
"Break each time an error is logged") \
|
||||
debug(bool, BREAK_ON_LOG_ERROR, false, \
|
||||
"Break each time an error is logged") \
|
||||
debug(uint, DEBUG_GPU_FLAGS, 0, \
|
||||
"The debug options for GPU device") \
|
||||
debug(uint, GPU_MAX_COMMAND_QUEUES, 70, \
|
||||
|
||||
Reference in New Issue
Block a user