[ROCm/clr commit: 3694ab2ce8]
Tento commit je obsažen v:
foreman
2014-07-04 16:17:05 -04:00
rodič b0b5b33fcf
revize f80f2f233c
351 změnil soubory, kde provedl 113713 přidání a 1 odebrání
+87
Zobrazit soubor
@@ -0,0 +1,87 @@
//
// 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
+30
Zobrazit soubor
@@ -0,0 +1,30 @@
//
// 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_*/
+145
Zobrazit soubor
@@ -0,0 +1,145 @@
//
// 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
+519
Zobrazit soubor
@@ -0,0 +1,519 @@
//
// 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_*/
+882
Zobrazit soubor
@@ -0,0 +1,882 @@
//
// 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 <vector>
#include <string>
#include <sstream>
#include <cstring> // for strncmp
#include <cstdlib>
#include <cstdio> // for tempnam
#include <limits.h>
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)
{
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
// Call the chained signal handler
if (callOldSignalHandler(sig, info, ptr)) {
return;
}
// @todo: only handle exception in the generated code.
//
//if (!isKernelCode(insn)) {
// return;
//}
if (sig == SIGFPE && info->si_code == FPE_INTDIV) {
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;
}
}
std::cerr << "Unhandled signal in divisionErrorHandler()" << std::endl;
::abort();
}
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)
{
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);
}
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 amd::Atomic<size_t> counter = 0;
std::string tempPath = getTempPath();
std::stringstream tempFileName;
tempFileName << tempPath << "/OCL" << ::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::string strFileName;
char* buff = new char[FILE_PATH_MAX_LENGTH];
if (readlink("/proc/self/exe", buff, FILE_PATH_MAX_LENGTH) > 0) {
// Get filename without path and extension.
strFileName = strrchr(buff, '/') ? strrchr(buff, '/') + 1 : buff;
}
delete buff;
return strFileName;
}
} // namespace amd
#endif // !defined(_WIN32) && !defined(__CYGWIN__)
Rozdílový obsah nebyl zobrazen, protože je příliš veliký Načíst rozdílové porovnání
+63
Zobrazit soubor
@@ -0,0 +1,63 @@
#
# 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
+110
Zobrazit soubor
@@ -0,0 +1,110 @@
;
; 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